summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/alias/t19349.nim19
-rw-r--r--tests/alias/talias.nim67
-rw-r--r--tests/align/globalalignas.nim3
-rw-r--r--tests/align/talign.nim69
-rw-r--r--tests/align/tillegalalign.nim7
-rw-r--r--tests/alloc/tmembug.nim54
-rw-r--r--tests/alloc/tmembug2.nim58
-rw-r--r--tests/arc/amodule.nim21
-rw-r--r--tests/arc/bmodule.nim4
-rw-r--r--tests/arc/cmodule.nim4
-rw-r--r--tests/arc/dmodule.nim23
-rw-r--r--tests/arc/nim.cfg1
-rw-r--r--tests/arc/t14383.nim217
-rw-r--r--tests/arc/t14472.nim43
-rw-r--r--tests/arc/t14864.nim5
-rw-r--r--tests/arc/t15909.nim16
-rw-r--r--tests/arc/t16033.nim10
-rw-r--r--tests/arc/t16458.nim6
-rw-r--r--tests/arc/t16558.nim9
-rw-r--r--tests/arc/t17025.nim56
-rw-r--r--tests/arc/t17173.nim10
-rw-r--r--tests/arc/t17812.nim41
-rw-r--r--tests/arc/t18645.nim18
-rw-r--r--tests/arc/t18971.nim10
-rw-r--r--tests/arc/t18977.nim26
-rw-r--r--tests/arc/t19231.nim18
-rw-r--r--tests/arc/t19364.nim30
-rw-r--r--tests/arc/t19401.nim32
-rw-r--r--tests/arc/t19402.nim32
-rw-r--r--tests/arc/t19435.nim29
-rw-r--r--tests/arc/t19457.nim16
-rw-r--r--tests/arc/t19862.nim15
-rw-r--r--tests/arc/t20456.nim7
-rw-r--r--tests/arc/t20588.nim25
-rw-r--r--tests/arc/t21184.nim77
-rw-r--r--tests/arc/t22218.nim25
-rw-r--r--tests/arc/t22237.nim55
-rw-r--r--tests/arc/t22478.nim46
-rw-r--r--tests/arc/t22787.nim37
-rw-r--r--tests/arc/t23247.nim52
-rw-r--r--tests/arc/t9650.nim87
-rw-r--r--tests/arc/taliased_reassign.nim41
-rw-r--r--tests/arc/tamemfiles.nim110
-rw-r--r--tests/arc/tamodule.nim9
-rw-r--r--tests/arc/tarc_macro.nim57
-rw-r--r--tests/arc/tarc_orc.nim186
-rw-r--r--tests/arc/tarcmisc.nim836
-rw-r--r--tests/arc/tasyncawait.nim68
-rw-r--r--tests/arc/tasyncleak.nim21
-rw-r--r--tests/arc/tasyncleak2.nim88
-rw-r--r--tests/arc/tasyncleak3.nim47
-rw-r--r--tests/arc/tasyncleak4.nim21
-rw-r--r--tests/arc/tasyncorc.nim26
-rw-r--r--tests/arc/tcaseobj.nim366
-rw-r--r--tests/arc/tcaseobjcopy.nim253
-rw-r--r--tests/arc/tclosureiter.nim36
-rw-r--r--tests/arc/tcomputedgoto.nim44
-rw-r--r--tests/arc/tcomputedgotocopy.nim44
-rw-r--r--tests/arc/tconst_to_sink.nim26
-rw-r--r--tests/arc/tcontrolflow.nim118
-rw-r--r--tests/arc/tcursor_field_obj_constr.nim44
-rw-r--r--tests/arc/tcursor_on_localvar.nim161
-rw-r--r--tests/arc/tcursorloop.nim45
-rw-r--r--tests/arc/tcustomtrace.nim240
-rw-r--r--tests/arc/tdeepcopy.nim67
-rw-r--r--tests/arc/tdestroy_in_loopcond.nim74
-rw-r--r--tests/arc/tdup.nim71
-rw-r--r--tests/arc/testfile.txt2
-rw-r--r--tests/arc/texceptions.nim16
-rw-r--r--tests/arc/texplicit_sink.nim29
-rw-r--r--tests/arc/tfuncobj.nim38
-rw-r--r--tests/arc/thamming_orc.nim155
-rw-r--r--tests/arc/thamming_thinout.nim183
-rw-r--r--tests/arc/thard_alignment.nim148
-rw-r--r--tests/arc/thavlak_orc_stress.nim414
-rw-r--r--tests/arc/theavy_recursion.nim43
-rw-r--r--tests/arc/timportedobj.nim14
-rw-r--r--tests/arc/titeration_doesnt_copy.nim67
-rw-r--r--tests/arc/tkeys_lent.nim17
-rw-r--r--tests/arc/tmalloc.nim16
-rw-r--r--tests/arc/tmarshal.nim140
-rw-r--r--tests/arc/tmove_regression.nim22
-rw-r--r--tests/arc/tmovebug.nim841
-rw-r--r--tests/arc/tmovebugcopy.nim526
-rw-r--r--tests/arc/tnewseq_legacy.nim13
-rw-r--r--tests/arc/top_no_cursor2.nim53
-rw-r--r--tests/arc/topenarray.nim86
-rw-r--r--tests/arc/topt_cursor.nim57
-rw-r--r--tests/arc/topt_cursor2.nim76
-rw-r--r--tests/arc/topt_no_cursor.nim376
-rw-r--r--tests/arc/topt_refcursors.nim54
-rw-r--r--tests/arc/topt_wasmoved_destroy_pairs.nim94
-rw-r--r--tests/arc/torc_basic_test.nim138
-rw-r--r--tests/arc/torc_selfcycles.nim33
-rw-r--r--tests/arc/torcbench.nim38
-rw-r--r--tests/arc/torcmisc.nim66
-rw-r--r--tests/arc/tref_cast_error.nim15
-rw-r--r--tests/arc/trepr.nim97
-rw-r--r--tests/arc/trtree.nim640
-rw-r--r--tests/arc/tshared_ptr_crash.nim67
-rw-r--r--tests/arc/tstrformat.nim22
-rw-r--r--tests/arc/tstringliteral.nim17
-rw-r--r--tests/arc/tthread.nim63
-rw-r--r--tests/arc/tunref_cycle.nim26
-rw-r--r--tests/arc/tweave.nim157
-rw-r--r--tests/arc/tweavecopy.nim154
-rw-r--r--tests/arc/twrong_sinkinference.nim18
-rw-r--r--tests/array/t15117.nim27
-rw-r--r--tests/array/t20248.nim14
-rw-r--r--tests/array/t9932.nim11
-rw-r--r--tests/array/tarray.nim607
-rw-r--r--tests/array/tarraycons.nim21
-rw-r--r--tests/array/tarraycons_ptr_generic2.nim17
-rw-r--r--tests/array/tarrayplus.nim13
-rw-r--r--tests/array/tidx_lit_err1.nim6
-rw-r--r--tests/array/tidx_lit_err2.nim5
-rw-r--r--tests/array/tidx_lit_err3.nim5
-rw-r--r--tests/array/tinvalidarrayaccess.nim21
-rw-r--r--tests/array/tinvalidarrayaccess2.nim10
-rw-r--r--tests/array/tlargeindex.nim18
-rw-r--r--tests/array/troofregression2.txt1
-rw-r--r--tests/assert/config.nims1
-rw-r--r--tests/assert/panicoverride.nim15
-rw-r--r--tests/assert/t21195.nim6
-rw-r--r--tests/assert/tassert.nim20
-rw-r--r--tests/assert/tassert2.nim111
-rw-r--r--tests/assert/tassert_c.nim40
-rw-r--r--tests/assert/tunittests.nim4
-rw-r--r--tests/assert/tuserassert.nim13
-rw-r--r--tests/assign/moverload_asgn2.nim14
-rw-r--r--tests/assign/tassign.nim218
-rw-r--r--tests/assign/tobject_assign.nim49
-rw-r--r--tests/assign/toverload_asgn2.nim23
-rw-r--r--tests/assign/tvariantasgn.nim39
-rw-r--r--tests/ast_pattern_matching.nim584
-rw-r--r--tests/astoverload/tastoverload1.nim21
-rw-r--r--tests/astspec/tastspec.nim1119
-rw-r--r--tests/async/hello.txt1
-rw-r--r--tests/async/nim.cfg1
-rw-r--r--tests/async/t11558.nim13
-rw-r--r--tests/async/t12221.nim40
-rw-r--r--tests/async/t13889.nim27
-rw-r--r--tests/async/t14820.nim25
-rw-r--r--tests/async/t15148.nim12
-rw-r--r--tests/async/t15804.nim15
-rw-r--r--tests/async/t17045.nim28
-rw-r--r--tests/async/t20111.nim19
-rw-r--r--tests/async/t21447.nim6
-rw-r--r--tests/async/t21893.nim13
-rw-r--r--tests/async/t22210.nim41
-rw-r--r--tests/async/t22210_2.nim73
-rw-r--r--tests/async/t3075.nim29
-rw-r--r--tests/async/t6846.nim15
-rw-r--r--tests/async/t7192.nim14
-rw-r--r--tests/async/t7758.nim21
-rw-r--r--tests/async/t8982.nim33
-rw-r--r--tests/async/t9201.nim14
-rw-r--r--tests/async/tacceptcloserace.nim36
-rw-r--r--tests/async/tasyncRecvLine.nim53
-rw-r--r--tests/async/tasync_forward.nim18
-rw-r--r--tests/async/tasync_gcsafe.nim36
-rw-r--r--tests/async/tasync_gcunsafe.nim30
-rw-r--r--tests/async/tasync_in_seq_constr.nim25
-rw-r--r--tests/async/tasync_misc.nim83
-rw-r--r--tests/async/tasync_noasync.nim44
-rw-r--r--tests/async/tasync_nofuture.nim11
-rw-r--r--tests/async/tasync_traceback.nim122
-rw-r--r--tests/async/tasyncall.nim93
-rw-r--r--tests/async/tasyncawait.nim56
-rw-r--r--tests/async/tasyncclosestall.nim101
-rw-r--r--tests/async/tasyncconnect.nim33
-rw-r--r--tests/async/tasyncdial.nim52
-rw-r--r--tests/async/tasyncdiscard.nim39
-rw-r--r--tests/async/tasynceagain.nim67
-rw-r--r--tests/async/tasyncexceptions.nim40
-rw-r--r--tests/async/tasyncfile.nim61
-rw-r--r--tests/async/tasyncfilewrite.nim20
-rw-r--r--tests/async/tasyncintemplate.nim62
-rw-r--r--tests/async/tasyncnetudp.nim90
-rw-r--r--tests/async/tasyncrecursion.nim21
-rw-r--r--tests/async/tasyncsend4757.nim24
-rw-r--r--tests/async/tasyncssl.nim74
-rw-r--r--tests/async/tasynctry.nim118
-rw-r--r--tests/async/tawaitsemantics.nim95
-rw-r--r--tests/async/tbreak_must_exec_finally.nim25
-rw-r--r--tests/async/tcallbacks.nim21
-rw-r--r--tests/async/tdiscardableproc.nim9
-rw-r--r--tests/async/testmanyasyncevents.nim24
-rw-r--r--tests/async/tfuturestream.nim71
-rw-r--r--tests/async/tfuturevar.nim46
-rw-r--r--tests/async/tgeneric_async.nim40
-rw-r--r--tests/async/tgenericasync.nim14
-rw-r--r--tests/async/tioselectors.nim643
-rw-r--r--tests/async/tioselectors.nim.cfg1
-rw-r--r--tests/async/tjsandnativeasync.nim30
-rw-r--r--tests/async/tlambda.nim58
-rw-r--r--tests/async/tmultisync.nim8
-rw-r--r--tests/async/tnestedpfuturetypeparam.nim8
-rw-r--r--tests/async/tnewasyncudp.nim111
-rw-r--r--tests/async/tnimcall_to_closure.nim17
-rw-r--r--tests/async/tpendingcheck.nim18
-rw-r--r--tests/async/tpolltimeouts.nim19
-rw-r--r--tests/async/treturn_await.nim23
-rw-r--r--tests/async/ttemplateinasync.nim11
-rw-r--r--tests/async/tupcoming_async.nim157
-rw-r--r--tests/async/twinasyncrw.nim243
-rw-r--r--tests/avr/nim.cfg12
-rw-r--r--tests/avr/panicoverride.nim13
-rw-r--r--tests/avr/thello.nim6
-rw-r--r--tests/benchmarks/readme.md5
-rw-r--r--tests/benchmarks/ttls.nim30
-rw-r--r--tests/c/tcompile.c3
-rw-r--r--tests/c/tcompile.nim10
-rw-r--r--tests/c/temit.nim16
-rw-r--r--tests/c/treservedcidentsasfields.nim39
-rwxr-xr-xtests/cairotest.nim14
-rw-r--r--tests/casestmt/t18964.nim12
-rw-r--r--tests/casestmt/t7699.nim15
-rw-r--r--tests/casestmt/tcase_issues.nim7
-rw-r--r--tests/casestmt/tcaseexpr1.nim39
-rw-r--r--tests/casestmt/tcaseoverlaprange.nim15
-rw-r--r--tests/casestmt/tcaseoverlaprange2.nim18
-rw-r--r--tests/casestmt/tcasestmt.nim319
-rw-r--r--tests/casestmt/tcomputedgoto.nim59
-rw-r--r--tests/casestmt/tcstring.nim52
-rw-r--r--tests/casestmt/tincompletecaseobject.nim115
-rw-r--r--tests/casestmt/tincompletecaseobject2.nim26
-rw-r--r--tests/casestmt/tlinearscanend.nim26
-rw-r--r--tests/casestmt/trangeexhaustiveness.nim7
-rw-r--r--tests/cast/tcast.nim21
-rw-r--r--tests/ccgbugs/m1/defs.nim4
-rw-r--r--tests/ccgbugs/m19445.c3
-rw-r--r--tests/ccgbugs/m2/defs.nim4
-rw-r--r--tests/ccgbugs/mstatic_assert.nim6
-rw-r--r--tests/ccgbugs/mymodule.nim14
-rw-r--r--tests/ccgbugs/pkg8616/rtarray.nim2
-rw-r--r--tests/ccgbugs/pkg8616/scheduler.nim10
-rw-r--r--tests/ccgbugs/t10128.nim18
-rw-r--r--tests/ccgbugs/t10964.nim7
-rw-r--r--tests/ccgbugs/t13062.nim33
-rw-r--r--tests/ccgbugs/t13902.nim12
-rw-r--r--tests/ccgbugs/t15428.nim22
-rw-r--r--tests/ccgbugs/t16027.nim13
-rw-r--r--tests/ccgbugs/t16374.nim38
-rw-r--r--tests/ccgbugs/t19445.nim13
-rw-r--r--tests/ccgbugs/t20139.nim10
-rw-r--r--tests/ccgbugs/t20141.nim27
-rw-r--r--tests/ccgbugs/t20787.nim4
-rw-r--r--tests/ccgbugs/t21116.nim10
-rw-r--r--tests/ccgbugs/t21972.nim33
-rw-r--r--tests/ccgbugs/t21995.nim9
-rw-r--r--tests/ccgbugs/t22462.nim20
-rw-r--r--tests/ccgbugs/t23796.nim25
-rw-r--r--tests/ccgbugs/t2procs.nim18
-rw-r--r--tests/ccgbugs/t5296.nim21
-rw-r--r--tests/ccgbugs/t5345.nim10
-rw-r--r--tests/ccgbugs/t6279.nim9
-rw-r--r--tests/ccgbugs/t6756.nim24
-rw-r--r--tests/ccgbugs/t7079.nim9
-rw-r--r--tests/ccgbugs/t8616.nim4
-rw-r--r--tests/ccgbugs/t8781.nim25
-rw-r--r--tests/ccgbugs/t8967.nim14
-rw-r--r--tests/ccgbugs/t9098.nim12
-rw-r--r--tests/ccgbugs/t9286.nim22
-rw-r--r--tests/ccgbugs/t9578.nim76
-rw-r--r--tests/ccgbugs/t9655.nim30
-rw-r--r--tests/ccgbugs/taddhigh.nim19
-rw-r--r--tests/ccgbugs/targ_lefttoright.nim71
-rw-r--r--tests/ccgbugs/tarray_equality.nim15
-rw-r--r--tests/ccgbugs/tassign_nil_strings.nim13
-rw-r--r--tests/ccgbugs/tborrowmagic.nim8
-rw-r--r--tests/ccgbugs/tbug1081.nim34
-rw-r--r--tests/ccgbugs/tbug21505.nim39
-rw-r--r--tests/ccgbugs/tcapture_static.nim13
-rw-r--r--tests/ccgbugs/tccgen1.nim67
-rw-r--r--tests/ccgbugs/tccgissues.nim14
-rw-r--r--tests/ccgbugs/tcgbug.nim163
-rw-r--r--tests/ccgbugs/tclosureeq.nim19
-rw-r--r--tests/ccgbugs/tcodegenbug1.nim185
-rw-r--r--tests/ccgbugs/tcodegenbug_bool.nim11
-rw-r--r--tests/ccgbugs/tcodegendecllambda.nim14
-rw-r--r--tests/ccgbugs/tcompile_time_var_at_runtime.nim11
-rw-r--r--tests/ccgbugs/tctypes.nim43
-rw-r--r--tests/ccgbugs/tcvarargs.nim35
-rw-r--r--tests/ccgbugs/tdeepcopy_addr_rval.nim17
-rw-r--r--tests/ccgbugs/tderefblock.nim76
-rw-r--r--tests/ccgbugs/tescaping_temps.nim31
-rw-r--r--tests/ccgbugs/tforward_decl_only.nim34
-rw-r--r--tests/ccgbugs/tgeneric_closure.nim34
-rw-r--r--tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim27
-rw-r--r--tests/ccgbugs/thtiobj.nim9
-rw-r--r--tests/ccgbugs/tissues.nim38
-rw-r--r--tests/ccgbugs/tlvalueconv.nim32
-rw-r--r--tests/ccgbugs/tmangle.nim16
-rw-r--r--tests/ccgbugs/tmangle_field.nim16
-rw-r--r--tests/ccgbugs/tmarkerproc_regression.nim47
-rw-r--r--tests/ccgbugs/tmissing_ccgtrav_unique_type.nim12
-rw-r--r--tests/ccgbugs/tmissingbracket.nim53
-rw-r--r--tests/ccgbugs/tmissingderef.nim40
-rw-r--r--tests/ccgbugs/tmissingderef2.nim25
-rw-r--r--tests/ccgbugs/tmissinginit.nim31
-rw-r--r--tests/ccgbugs/tmissingvolatile.nim21
-rw-r--r--tests/ccgbugs/tnil_type.nim15
-rw-r--r--tests/ccgbugs/tnoalias.nim13
-rw-r--r--tests/ccgbugs/tnocodegen_for_compiletime.nim9
-rw-r--r--tests/ccgbugs/tobjconstr_bad_aliasing.nim76
-rw-r--r--tests/ccgbugs/tobjconstr_outoforder.nim38
-rw-r--r--tests/ccgbugs/tobjconstr_regression.nim14
-rw-r--r--tests/ccgbugs/topenarraycast.nim8
-rw-r--r--tests/ccgbugs/tpartialcs.nim20
-rw-r--r--tests/ccgbugs/tprogmem.nim11
-rw-r--r--tests/ccgbugs/trecursive_table.nim17
-rw-r--r--tests/ccgbugs/trefseqsort.nim33
-rw-r--r--tests/ccgbugs/tresult_of_array.nim29
-rw-r--r--tests/ccgbugs/tret_arg_init.nim28
-rw-r--r--tests/ccgbugs/tsamename3.nim120
-rw-r--r--tests/ccgbugs/tsequence_outoforder.nim11
-rw-r--r--tests/ccgbugs/tsighash_typename_regression.nim32
-rw-r--r--tests/ccgbugs/tstringslice.nim20
-rw-r--r--tests/ccgbugs/tunsafeaddr.nim47
-rw-r--r--tests/ccgbugs/tuple_canon.nim119
-rw-r--r--tests/ccgbugs/tuplecast.nim8
-rw-r--r--tests/ccgbugs/tweakopenarray.nim12
-rw-r--r--tests/ccgbugs/twrong_discriminant_check.nim30
-rw-r--r--tests/ccgbugs/twrong_method.nim27
-rw-r--r--tests/ccgbugs/twrong_rc_for_refarray.nim26
-rw-r--r--tests/ccgbugs/twrong_string_asgn.nim19
-rw-r--r--tests/ccgbugs/twrong_tupleconv.nim35
-rw-r--r--tests/ccgbugs/twrongrefcounting.nim33
-rw-r--r--tests/ccgbugs/xarray9578.nim7
-rw-r--r--tests/ccgbugs/xoa9578.nim4
-rw-r--r--tests/ccgbugs/xseq9578.nim7
-rw-r--r--tests/ccgbugs/xtuple9578.nim7
-rw-r--r--tests/ccgbugs/xua9578.nim7
-rw-r--r--tests/ccgbugs2/tcodegen.nim47
-rw-r--r--tests/ccgbugs2/tinefficient_const_table.nim27
-rwxr-xr-xtests/cgitest.nim15
-rw-r--r--tests/closure/t11042.nim55
-rw-r--r--tests/closure/t15594.nim10
-rw-r--r--tests/closure/t1641.nim20
-rw-r--r--tests/closure/t19095.nim35
-rw-r--r--tests/closure/t20152.nim20
-rw-r--r--tests/closure/t8550.nim13
-rw-r--r--tests/closure/t9334.nim19
-rw-r--r--tests/closure/tboehmdeepcopy.nim18
-rw-r--r--tests/closure/tcapture.nim34
-rw-r--r--tests/closure/tclosure.nim504
-rw-r--r--tests/closure/tclosure_issues.nim82
-rw-r--r--tests/closure/texplicit_dummy_closure.nim25
-rw-r--r--tests/closure/tinfer_closure_for_nestedproc.nim42
-rw-r--r--tests/closure/tinvalidclosure.nim12
-rw-r--r--tests/closure/tinvalidclosure2.nim14
-rw-r--r--tests/closure/tinvalidclosure3.nim12
-rw-r--r--tests/closure/tinvalidclosure4.nim9
-rw-r--r--tests/closure/tinvalidclosure5.nim10
-rw-r--r--tests/closure/tmacrobust1512.nim123
-rw-r--r--tests/closure/tnested.nim215
-rw-r--r--tests/closure/tstmtlist.nim9
-rw-r--r--tests/closure/ttimeinfo.nim22
-rw-r--r--tests/closure/uclosures.nim23
-rw-r--r--tests/codegen/titaniummangle.nim193
-rw-r--r--tests/collections/tactiontable.nim37
-rw-r--r--tests/collections/tcollections.nim105
-rw-r--r--tests/collections/tcollections_to_string.nim115
-rw-r--r--tests/collections/thashsets.nim382
-rw-r--r--tests/collections/tseq.nim242
-rw-r--r--tests/collections/ttables.nim457
-rw-r--r--tests/collections/ttablesthreads.nim276
-rw-r--r--tests/compileoption/texperimental.nim20
-rw-r--r--tests/compileoption/texperimental.nims19
-rw-r--r--tests/compiler/nim.cfg7
-rw-r--r--tests/compiler/samplelib.nim2
-rw-r--r--tests/compiler/t12684.nim7
-rw-r--r--tests/compiler/tasciitables.nim109
-rw-r--r--tests/compiler/tasm.nim15
-rw-r--r--tests/compiler/tbtrees.nim84
-rw-r--r--tests/compiler/tcmdlineclib.nim3
-rw-r--r--tests/compiler/tcmdlineclib.nims10
-rw-r--r--tests/compiler/tcmdlinecpuamd64.nim10
-rw-r--r--tests/compiler/tcmdlinecpuamd64.nim.cfg1
-rw-r--r--tests/compiler/tcmdlineoswin.nim14
-rw-r--r--tests/compiler/tcmdlineoswin.nim.cfg1
-rw-r--r--tests/compiler/tcppCompileToNamespace.nim11
-rw-r--r--tests/compiler/tdebugutils.nim38
-rw-r--r--tests/compiler/tgrammar.nim7
-rw-r--r--tests/compiler/tint128.nim184
-rw-r--r--tests/compiler/tnimblecmd.nim75
-rw-r--r--tests/compiler/tpathutils.nim18
-rw-r--r--tests/compiler/tprefixmatches.nim32
-rw-r--r--tests/compiler/tunittest_light.nim55
-rw-r--r--tests/compilerapi/exposed.nim3
-rw-r--r--tests/compilerapi/invalid.nim1
-rw-r--r--tests/compilerapi/myscript.nim14
-rw-r--r--tests/compilerapi/tcompilerapi.nim98
-rw-r--r--tests/compiles/mstaticlib.nim1
-rw-r--r--tests/compiles/t8630.nim13
-rw-r--r--tests/compiles/tcompiles.nim30
-rw-r--r--tests/compiles/tevilcompiles.nim12
-rw-r--r--tests/compiles/trecursive_generic_in_compiles.nim94
-rw-r--r--tests/compiles/tstaticlib.nim22
-rw-r--r--tests/concepts/libs/trie.nim26
-rw-r--r--tests/concepts/libs/trie_database.nim12
-rw-r--r--tests/concepts/matrix.nim14
-rw-r--r--tests/concepts/matrixalgo.nim28
-rw-r--r--tests/concepts/mvarconcept.nim13
-rw-r--r--tests/concepts/t18409.nim37
-rw-r--r--tests/concepts/t19730.nim20
-rw-r--r--tests/concepts/t20237.nim3
-rw-r--r--tests/concepts/t3330.nim70
-rw-r--r--tests/concepts/t4982.nim18
-rw-r--r--tests/concepts/t5888lib/ca.nim4
-rw-r--r--tests/concepts/t5888lib/opt.nim6
-rw-r--r--tests/concepts/t8012.nim15
-rw-r--r--tests/concepts/t8558.nim26
-rw-r--r--tests/concepts/t976.nim57
-rw-r--r--tests/concepts/tcomparable.nim13
-rw-r--r--tests/concepts/tconceptinclosure.nim53
-rw-r--r--tests/concepts/tconcepts.nim451
-rw-r--r--tests/concepts/tconcepts_issues.nim556
-rw-r--r--tests/concepts/tconcepts_overload_precedence.nim69
-rw-r--r--tests/concepts/templatesinconcepts.nim56
-rw-r--r--tests/concepts/texplain.nim182
-rw-r--r--tests/concepts/titerable.nim20
-rw-r--r--tests/concepts/tmanual.nim42
-rw-r--r--tests/concepts/tmapconcept.nim102
-rw-r--r--tests/concepts/tmatrixconcept.nim81
-rw-r--r--tests/concepts/tmatrixlib.nim31
-rw-r--r--tests/concepts/tmodifiersinplace.nim30
-rw-r--r--tests/concepts/tmonoid.nim25
-rw-r--r--tests/concepts/trandomvars.nim63
-rw-r--r--tests/concepts/trandomvars2.nim42
-rw-r--r--tests/concepts/treversable.nim31
-rw-r--r--tests/concepts/tseqofconcept.nim19
-rw-r--r--tests/concepts/tspec.nim105
-rw-r--r--tests/concepts/tstackconcept.nim62
-rw-r--r--tests/concepts/tswizzle.nim80
-rw-r--r--tests/concepts/ttrieconcept.nim7
-rw-r--r--tests/concepts/tusertypeclasses.nim131
-rw-r--r--tests/concepts/tusertypeclasses2.nim63
-rw-r--r--tests/concepts/tvarconcept.nim9
-rw-r--r--tests/concepts/tvectorspace.nim19
-rw-r--r--tests/concepts/twrapconcept.nim21
-rw-r--r--tests/config.nims49
-rw-r--r--tests/constructors/a.nim2
-rw-r--r--tests/constructors/b.nim2
-rw-r--r--tests/constructors/t18990.nim3
-rw-r--r--tests/constructors/t5965_1.nim10
-rw-r--r--tests/constructors/t5965_2.nim10
-rw-r--r--[-rwxr-xr-x]tests/constructors/tconstr1.nim (renamed from tests/tconstr1.nim)51
-rw-r--r--[-rwxr-xr-x]tests/constructors/tconstr2.nim (renamed from tests/tconstr2.nim)42
-rw-r--r--tests/constructors/tinvalid_construction.nim439
-rw-r--r--[-rwxr-xr-x]tests/controlflow/tblock1.nim (renamed from tests/tblock1.nim)27
-rw-r--r--tests/controlflow/tcontrolflow.nim116
-rw-r--r--tests/controlflow/tstatret.nim9
-rw-r--r--tests/controlflow/tunamedbreak.nim15
-rw-r--r--tests/controlflow/tunreachable.nim79
-rw-r--r--tests/controlflow/tunreachable2.nim12
-rw-r--r--tests/converter/m18986.nim3
-rw-r--r--tests/converter/mdontleak.nim3
-rw-r--r--tests/converter/t18986.nim10
-rw-r--r--tests/converter/t21531.nim10
-rw-r--r--tests/converter/t7097.nim38
-rw-r--r--tests/converter/t7098.nim35
-rw-r--r--tests/converter/t9165.nim11
-rw-r--r--tests/converter/tconvcolors.nim7
-rw-r--r--tests/converter/tconvert.nim44
-rw-r--r--tests/converter/tconverter.nim11
-rw-r--r--tests/converter/tconverter_unique_ptr.nim149
-rw-r--r--tests/converter/tconverter_with_constraint.nim20
-rw-r--r--tests/converter/tconverter_with_varargs.nim18
-rw-r--r--tests/converter/tdontleak.nim10
-rw-r--r--tests/converter/texplicit_conversion.nim19
-rw-r--r--tests/converter/tgenericconverter.nim54
-rw-r--r--tests/converter/tgenericconverter2.nim85
-rw-r--r--tests/converter/tor_in_converter.nim23
-rw-r--r--tests/converter/ttypeconverter1.nim15
-rw-r--r--tests/coroutines/texceptions.nim29
-rw-r--r--tests/coroutines/texceptions.nim.cfg1
-rw-r--r--tests/coroutines/tgc.nim22
-rw-r--r--tests/coroutines/tgc.nim.cfg1
-rw-r--r--tests/coroutines/titerators.nim31
-rw-r--r--tests/coroutines/titerators.nim.cfg1
-rw-r--r--tests/coroutines/twait.nim28
-rw-r--r--tests/coroutines/twait.nim.cfg1
-rw-r--r--tests/cpp/23962.h17
-rw-r--r--tests/cpp/amodule.nim10
-rw-r--r--tests/cpp/enum.hpp3
-rw-r--r--tests/cpp/fam.h4
-rw-r--r--tests/cpp/foo.c4
-rw-r--r--tests/cpp/mexportc.nim9
-rw-r--r--tests/cpp/t10148.nim29
-rw-r--r--tests/cpp/t10241.nim19
-rw-r--r--tests/cpp/t12946.nim8
-rw-r--r--tests/cpp/t22679.nim50
-rw-r--r--tests/cpp/t22680.nim50
-rw-r--r--tests/cpp/t22712.nim15
-rw-r--r--tests/cpp/t23306.nim12
-rw-r--r--tests/cpp/t23434.nim17
-rw-r--r--tests/cpp/t23657.nim54
-rw-r--r--tests/cpp/t23962.nim32
-rw-r--r--tests/cpp/t4834.nim17
-rw-r--r--tests/cpp/t6986.nim19
-rw-r--r--tests/cpp/t8241.nim32
-rw-r--r--tests/cpp/t9013.nim9
-rw-r--r--tests/cpp/tasync_cpp.nim15
-rw-r--r--tests/cpp/tcasts.nim20
-rw-r--r--tests/cpp/tcodegendecl.nim17
-rw-r--r--tests/cpp/tconstructor.nim131
-rw-r--r--tests/cpp/tcovariancerules.nim417
-rw-r--r--tests/cpp/tcppraise.nim71
-rw-r--r--tests/cpp/tdont_init_instantiation.nim29
-rw-r--r--tests/cpp/tembarrassing_generic_bug.nim9
-rw-r--r--tests/cpp/temitlist.nim38
-rw-r--r--tests/cpp/tempty_generic_obj.nim47
-rw-r--r--tests/cpp/tenum_set.nim9
-rw-r--r--tests/cpp/tevalorder.nim18
-rw-r--r--tests/cpp/texportc.nim22
-rw-r--r--tests/cpp/tfam.nim7
-rw-r--r--tests/cpp/tgen_prototype_for_importc.nim10
-rw-r--r--tests/cpp/tget_subsystem.nim39
-rw-r--r--tests/cpp/tinitializers.nim60
-rw-r--r--tests/cpp/tmember.nim75
-rw-r--r--tests/cpp/tmember_forward_declaration.nim27
-rw-r--r--tests/cpp/tnativesockets.nim6
-rw-r--r--tests/cpp/tnoinitfield.nim30
-rw-r--r--tests/cpp/torc.nim75
-rw-r--r--tests/cpp/tpassbypragmas.nim27
-rw-r--r--tests/cpp/treturn_array.nim13
-rw-r--r--tests/cpp/tretvar.nim39
-rw-r--r--tests/cpp/tsigbreak.nim29
-rw-r--r--tests/cpp/tstaticvar_via_typedesc.nim20
-rw-r--r--tests/cpp/ttemplatetype.nim13
-rw-r--r--tests/cpp/tterminate_handler.nim10
-rw-r--r--tests/cpp/tthread_createthread.nim15
-rw-r--r--tests/cpp/ttypeinfo1.nim22
-rw-r--r--tests/cpp/ttypeinfo2.nim6
-rw-r--r--tests/cpp/tvector_iterator.nim19
-rw-r--r--tests/cpp/tvectorseq.nim38
-rw-r--r--tests/cpp/tvirtual.nim126
-rw-r--r--tests/cpp/virtualptr.nim9
-rwxr-xr-xtests/curltest.nim10
-rw-r--r--tests/defer/t22309.nim11
-rw-r--r--tests/destructor/const_smart_ptr.nim75
-rw-r--r--tests/destructor/helper.nim3
-rw-r--r--tests/destructor/nim.cfg1
-rw-r--r--tests/destructor/objFile.nim8
-rw-r--r--tests/destructor/smart_ptr.nim43
-rw-r--r--tests/destructor/t12037.nim34
-rw-r--r--tests/destructor/t16607.nim23
-rw-r--r--tests/destructor/t17198.nim32
-rw-r--r--tests/destructor/t23748.nim31
-rw-r--r--tests/destructor/t23837.nim51
-rw-r--r--tests/destructor/t5342.nim24
-rw-r--r--tests/destructor/t7346.nim14
-rw-r--r--tests/destructor/t9440.nim52
-rw-r--r--tests/destructor/tarc.nim184
-rw-r--r--tests/destructor/tarc2.nim31
-rw-r--r--tests/destructor/tarc3.nim101
-rw-r--r--tests/destructor/tarctypesections.nim70
-rw-r--r--tests/destructor/tarray_indexing.nim75
-rw-r--r--tests/destructor/tasync_prototype.nim59
-rw-r--r--tests/destructor/tasync_prototype_cyclic.nim55
-rw-r--r--tests/destructor/tatomicptrs.nim176
-rw-r--r--tests/destructor/tbintree2.nim101
-rw-r--r--tests/destructor/tcaseobj_transitions.nim49
-rw-r--r--tests/destructor/tcast.nim14
-rw-r--r--tests/destructor/tcomplexobjconstr.nim56
-rw-r--r--tests/destructor/tconst_smart_ptr.nim7
-rw-r--r--tests/destructor/tconsume_twice.nim15
-rw-r--r--tests/destructor/tcustomseqs.nim144
-rw-r--r--tests/destructor/tcustomstrings.nim97
-rw-r--r--tests/destructor/tcycle1.nim54
-rw-r--r--tests/destructor/tcycle2.nim36
-rw-r--r--tests/destructor/tcycle3.nim98
-rw-r--r--tests/destructor/tdangingref_simple.nim32
-rw-r--r--tests/destructor/tdestructor.nim167
-rw-r--r--tests/destructor/tdestructor3.nim185
-rw-r--r--tests/destructor/tdestructor_too_late.nim14
-rw-r--r--tests/destructor/tdistinctseq.nim8
-rw-r--r--tests/destructor/tdont_return_unowned_from_owned.nim56
-rw-r--r--tests/destructor/terror_module.nim20
-rw-r--r--tests/destructor/texceptions.nim29
-rw-r--r--tests/destructor/texplicit_move.nim30
-rw-r--r--tests/destructor/tfinalizer.nim31
-rw-r--r--tests/destructor/tgcdestructors.nim203
-rw-r--r--tests/destructor/tgcleak4.nim47
-rw-r--r--tests/destructor/tglobaldestructor.nim9
-rw-r--r--tests/destructor/tgotoexc_leak.nim19
-rwxr-xr-xtests/destructor/tgotoexceptions.nim117
-rw-r--r--tests/destructor/tgotoexceptions2.nim104
-rw-r--r--tests/destructor/tgotoexceptions3.nim7
-rw-r--r--tests/destructor/tgotoexceptions4.nim60
-rw-r--r--tests/destructor/tgotoexceptions5.nim45
-rw-r--r--tests/destructor/tgotoexceptions6.nim10
-rw-r--r--tests/destructor/tgotoexceptions7.nim49
-rw-r--r--tests/destructor/tgotoexceptions8.nim76
-rw-r--r--tests/destructor/tinvalid_rebind.nim15
-rw-r--r--tests/destructor/tmatrix.nim135
-rw-r--r--tests/destructor/tmisc_destructors.nim43
-rw-r--r--tests/destructor/tmove.nim18
-rw-r--r--tests/destructor/tmove_objconstr.nim194
-rw-r--r--tests/destructor/tnewruntime_misc.nim155
-rw-r--r--tests/destructor/tnewruntime_strutils.nim254
-rw-r--r--tests/destructor/tnonvardestructor.nim247
-rw-r--r--tests/destructor/tobjfield_analysis.nim51
-rw-r--r--tests/destructor/topt.nim61
-rw-r--r--tests/destructor/topttree.nim109
-rw-r--r--tests/destructor/towned_binary_tree.nim91
-rw-r--r--tests/destructor/tprevent_assign.nim33
-rw-r--r--tests/destructor/tprevent_assign2.nim56
-rw-r--r--tests/destructor/tprevent_assign3.nim54
-rw-r--r--tests/destructor/trecursive.nim60
-rw-r--r--tests/destructor/tselect.nim50
-rw-r--r--tests/destructor/tsetjmp_raise.nim11
-rw-r--r--tests/destructor/tsimpleclosure.nim62
-rw-r--r--tests/destructor/tsink.nim70
-rw-r--r--tests/destructor/ttuple.nim130
-rw-r--r--tests/destructor/turn_destroy_into_finalizer.nim26
-rw-r--r--tests/destructor/tuse_ownedref_after_move.nim57
-rw-r--r--tests/destructor/tuse_result_prevents_sinks.nim37
-rw-r--r--tests/destructor/tv2_cast.nim116
-rw-r--r--tests/destructor/tv2_raise.nim53
-rw-r--r--tests/destructor/twasmoved.nim14
-rw-r--r--tests/destructor/twasmoved_error.nim37
-rw-r--r--tests/destructor/twidgets.nim76
-rw-r--r--tests/destructor/twidgets_unown.nim72
-rw-r--r--tests/dir with space/more spaces/mspace.nim1
-rw-r--r--tests/dir with space/tspace.nim10
-rw-r--r--tests/discard/t23677.nim12
-rw-r--r--tests/discard/tdiscardable.nim175
-rw-r--r--tests/discard/tfinallyerrmsg.nim19
-rw-r--r--tests/discard/tillegaldiscard.nim9
-rw-r--r--tests/discard/tillegaldiscardtypes.nim14
-rw-r--r--tests/discard/tneedsdiscard.nim12
-rw-r--r--tests/discard/tneedsdiscard_in_for.nim22
-rw-r--r--tests/discard/tvoidcontext.nim12
-rw-r--r--tests/distinct/t7165.nim15
-rw-r--r--tests/distinct/tborrow.nim132
-rw-r--r--tests/distinct/tcomplexaddressableconv.nim21
-rw-r--r--tests/distinct/tdistinct.nim227
-rw-r--r--tests/distinct/tdistinct_issues.nim81
-rw-r--r--tests/distinct/tinvalidborrow.nim42
-rw-r--r--tests/distinct/tnil.nim22
-rw-r--r--tests/distinct/typeclassborrow.nim56
-rw-r--r--tests/dll/client.nim43
-rw-r--r--tests/dll/client.nim.cfg1
-rw-r--r--tests/dll/nimhcr_0.nim4
-rw-r--r--tests/dll/nimhcr_0_1.nim14
-rw-r--r--tests/dll/nimhcr_0_2.nim18
-rw-r--r--tests/dll/nimhcr_0_3.nim19
-rw-r--r--tests/dll/nimhcr_0_4.nim19
-rw-r--r--tests/dll/nimhcr_0_5.nim2
-rw-r--r--tests/dll/nimhcr_0_6.nim4
-rw-r--r--tests/dll/nimhcr_1.nim0
-rw-r--r--tests/dll/nimhcr_1_1.nim51
-rw-r--r--tests/dll/nimhcr_1_2.nim4
-rw-r--r--tests/dll/nimhcr_1_3.nim0
-rw-r--r--tests/dll/nimhcr_2.nim0
-rw-r--r--tests/dll/nimhcr_2_1.nim32
-rw-r--r--tests/dll/nimhcr_2_2.nim7
-rw-r--r--tests/dll/nimhcr_2_3.nim0
-rw-r--r--tests/dll/nimhcr_basic.nim8
-rw-r--r--tests/dll/nimhcr_integration.nim170
-rw-r--r--tests/dll/nimhcr_unit.nim149
-rw-r--r--tests/dll/nimhcr_unit.nim.cfg2
-rw-r--r--tests/dll/server.nim27
-rw-r--r--tests/dll/server.nim.cfg2
-rw-r--r--tests/dll/test_nimhcr_integration.bat10
-rwxr-xr-xtests/dll/test_nimhcr_integration.sh17
-rw-r--r--tests/dll/visibility.nim43
-rw-r--r--tests/dummy.txt1
-rwxr-xr-xtests/ecmas.nim16
-rw-r--r--tests/effects/tcast_as_pragma.nim18
-rw-r--r--tests/effects/tdiagnostic_messages.nim37
-rw-r--r--tests/effects/teffects1.nim47
-rw-r--r--tests/effects/teffects10.nim12
-rw-r--r--tests/effects/teffects11.nim21
-rw-r--r--tests/effects/teffects12.nim52
-rw-r--r--tests/effects/teffects13.nim19
-rw-r--r--tests/effects/teffects14.nim15
-rw-r--r--tests/effects/teffects15.nim18
-rw-r--r--tests/effects/teffects16.nim20
-rw-r--r--tests/effects/teffects17.nim17
-rw-r--r--tests/effects/teffects18.nim19
-rw-r--r--tests/effects/teffects19.nim23
-rw-r--r--tests/effects/teffects2.nim20
-rw-r--r--tests/effects/teffects3.nim18
-rw-r--r--tests/effects/teffects4.nim23
-rw-r--r--tests/effects/teffects5.nim14
-rw-r--r--tests/effects/teffects6.nim56
-rw-r--r--tests/effects/teffects7.nim16
-rw-r--r--tests/effects/teffects8.nim13
-rw-r--r--tests/effects/teffects9.nim22
-rw-r--r--tests/effects/teffectsmisc.nim39
-rw-r--r--tests/effects/tfuncs_cannot_mutate.nim35
-rw-r--r--tests/effects/tfuncs_cannot_mutate2.nim24
-rw-r--r--tests/effects/tfuncs_cannot_mutate3.nim35
-rw-r--r--tests/effects/tfuncs_cannot_mutate_simple.nim19
-rw-r--r--tests/effects/tgcsafe.nim26
-rw-r--r--tests/effects/tgcsafe2.nim12
-rw-r--r--tests/effects/tgcsafe3.nim21
-rw-r--r--tests/effects/thooks.nim16
-rw-r--r--tests/effects/tlaxeffects.nim11
-rw-r--r--tests/effects/tnestedprocs.nim63
-rw-r--r--tests/effects/tnosideeffect.nim24
-rw-r--r--tests/effects/tsidee1.nim15
-rw-r--r--tests/effects/tsidee2.nim13
-rw-r--r--tests/effects/tsidee3.nim13
-rw-r--r--tests/effects/tsidee4.nim15
-rw-r--r--tests/effects/tstrict_caseobjects.nim47
-rw-r--r--tests/effects/tstrict_effects.nim27
-rw-r--r--tests/effects/tstrict_effects2.nim28
-rw-r--r--tests/effects/tstrict_effects3.nim57
-rw-r--r--tests/effects/tstrict_effects_sort.nim27
-rw-r--r--tests/effects/tstrict_funcs.nim46
-rw-r--r--tests/effects/tstrict_funcs_imports.nim176
-rw-r--r--tests/effects/tstrict_funcs_imports_js.nim20
-rw-r--r--tests/effects/tstrictfuncs_misc.nim65
-rw-r--r--tests/enum/m16462_1.nim3
-rw-r--r--tests/enum/m16462_2.nim3
-rw-r--r--tests/enum/mcrossmodule.nim6
-rw-r--r--tests/enum/t16462.nim5
-rw-r--r--tests/enum/t21863.nim28
-rw-r--r--tests/enum/tambiguousoverloads.nim26
-rw-r--r--tests/enum/tcrossmodule.nim15
-rw-r--r--tests/enum/tenum.nim267
-rw-r--r--tests/enum/tenum_duplicate.nim10
-rw-r--r--tests/enum/tenum_invalid.nim8
-rw-r--r--tests/enum/tenum_no_rtti.nim12
-rw-r--r--tests/enum/tenum_self.nim11
-rw-r--r--tests/enum/tenumfieldpragma.nim22
-rw-r--r--tests/enum/tenumfieldpragmanoannot.nim10
-rw-r--r--tests/enum/tenumitems.nim7
-rw-r--r--tests/enum/tenumitems2.nim14
-rw-r--r--tests/enum/tenummix.nim11
-rw-r--r--tests/enum/toverloadable_enums.nim120
-rw-r--r--tests/enum/toverloadedname.nim7
-rw-r--r--tests/enum/tpure_enums_conflict.nim27
-rw-r--r--tests/enum/tpure_enums_conflict_legacy.nim25
-rw-r--r--tests/enum/tredefinition.nim9
-rw-r--r--tests/enum/ttypenameconflict.nim13
-rw-r--r--tests/errmsgs/m8794.nim2
-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/mb.nim2
-rw-r--r--tests/errmsgs/mc.nim3
-rw-r--r--tests/errmsgs/t10251.nim19
-rw-r--r--tests/errmsgs/t10376.nim32
-rw-r--r--tests/errmsgs/t10489_a.nim9
-rw-r--r--tests/errmsgs/t10489_b.nim9
-rw-r--r--tests/errmsgs/t10542.nim24
-rw-r--r--tests/errmsgs/t10594.nim7
-rw-r--r--tests/errmsgs/t10734.nim20
-rw-r--r--tests/errmsgs/t10735.nim68
-rw-r--r--tests/errmsgs/t1154.nim11
-rw-r--r--tests/errmsgs/t12844.nim13
-rw-r--r--tests/errmsgs/t14444.nim14
-rw-r--r--tests/errmsgs/t16654.nim12
-rw-r--r--tests/errmsgs/t17460.nim19
-rw-r--r--tests/errmsgs/t18327.nim5
-rw-r--r--tests/errmsgs/t18886.nim18
-rw-r--r--tests/errmsgs/t18983.nim7
-rw-r--r--tests/errmsgs/t19224.nim12
-rw-r--r--tests/errmsgs/t19882.nim10
-rw-r--r--tests/errmsgs/t19882_2.nim5
-rw-r--r--tests/errmsgs/t21257.nim20
-rw-r--r--tests/errmsgs/t22097.nim9
-rw-r--r--tests/errmsgs/t22284.nim25
-rw-r--r--tests/errmsgs/t22753.nim52
-rw-r--r--tests/errmsgs/t22852.nim9
-rw-r--r--tests/errmsgs/t22996.nim7
-rw-r--r--tests/errmsgs/t23060.nim5
-rw-r--r--tests/errmsgs/t23419.nim5
-rw-r--r--tests/errmsgs/t23435.nim12
-rw-r--r--tests/errmsgs/t23536.nim26
-rw-r--r--tests/errmsgs/t2614.nim21
-rw-r--r--tests/errmsgs/t4756.nim16
-rw-r--r--tests/errmsgs/t5167_1.nim17
-rw-r--r--tests/errmsgs/t5167_2.nim12
-rw-r--r--tests/errmsgs/t5167_3.nim25
-rw-r--r--tests/errmsgs/t5167_4.nim20
-rw-r--r--tests/errmsgs/t5167_5.nim25
-rw-r--r--tests/errmsgs/t5282.nim5
-rw-r--r--tests/errmsgs/t5870.nim17
-rw-r--r--tests/errmsgs/t6281.nim9
-rw-r--r--tests/errmsgs/t6483.nim31
-rw-r--r--tests/errmsgs/t6499.nim6
-rw-r--r--tests/errmsgs/t6608.nim15
-rw-r--r--tests/errmsgs/t8064.nim9
-rw-r--r--tests/errmsgs/t8339.nim8
-rw-r--r--tests/errmsgs/t8434.nim15
-rw-r--r--tests/errmsgs/t8610.nim5
-rw-r--r--tests/errmsgs/t8794.nim23
-rw-r--r--tests/errmsgs/t9768.nim31
-rw-r--r--tests/errmsgs/t9908_01.nim10
-rw-r--r--tests/errmsgs/t9908_02.nim10
-rw-r--r--tests/errmsgs/ta.nim12
-rw-r--r--tests/errmsgs/tambparam.nim16
-rw-r--r--tests/errmsgs/tambparam_legacy.nim14
-rw-r--r--tests/errmsgs/tassignunpack.nim3
-rw-r--r--tests/errmsgs/tcall_with_default_arg.nim18
-rw-r--r--tests/errmsgs/tcannot_capture_builtin.nim8
-rw-r--r--tests/errmsgs/tcant_overload_by_return_type.nim9
-rw-r--r--tests/errmsgs/tcase_stmt.nim29
-rw-r--r--tests/errmsgs/tconceptconstraint.nim20
-rw-r--r--tests/errmsgs/tconcisetypemismatch.nim23
-rw-r--r--tests/errmsgs/tconstinfo.nim7
-rw-r--r--tests/errmsgs/tconsttypemismatch.nim7
-rw-r--r--tests/errmsgs/tdeclaredlocs.nim92
-rw-r--r--tests/errmsgs/tdetailed_position.nim22
-rw-r--r--tests/errmsgs/tdistinct_nil.nim23
-rw-r--r--tests/errmsgs/tdont_show_system.nim13
-rw-r--r--tests/errmsgs/temptysetparam.nim5
-rw-r--r--tests/errmsgs/tgcsafety.nim32
-rw-r--r--tests/errmsgs/tgeneral_excepts.nim10
-rw-r--r--tests/errmsgs/tgenericconstraint.nim14
-rw-r--r--tests/errmsgs/tgenericmismatchsegfault.nim13
-rw-r--r--tests/errmsgs/tgenericmismatchsegfault_legacy.nim10
-rw-r--r--tests/errmsgs/tinconsistentgensym.nim25
-rw-r--r--tests/errmsgs/tinteger_literals.nim14
-rw-r--r--tests/errmsgs/tinvalidinout.nim26
-rw-r--r--tests/errmsgs/tmacroerrorproc.nim13
-rw-r--r--tests/errmsgs/tmake_tuple_visible.nim20
-rw-r--r--tests/errmsgs/tmetaobjectfields.nim75
-rw-r--r--tests/errmsgs/tmultiple_finally.nim12
-rw-r--r--tests/errmsgs/tnested_empty_seq.nim8
-rw-r--r--tests/errmsgs/tnested_generic_instantiation.nim24
-rw-r--r--tests/errmsgs/tnested_generic_instantiation2.nim27
-rw-r--r--tests/errmsgs/tnnodeadd.nim8
-rw-r--r--tests/errmsgs/tnnodeindex.nim8
-rw-r--r--tests/errmsgs/tnnodeindexkind.nim8
-rw-r--r--tests/errmsgs/tnon_concrete_cast.nim47
-rw-r--r--tests/errmsgs/tnoop.nim12
-rw-r--r--tests/errmsgs/tproc_mismatch.nim74
-rw-r--r--tests/errmsgs/tproper_stacktrace.nim142
-rw-r--r--tests/errmsgs/tproper_stacktrace2.nim23
-rw-r--r--tests/errmsgs/tproper_stacktrace3.nim24
-rw-r--r--tests/errmsgs/treportunused.nim65
-rw-r--r--tests/errmsgs/tshow_asgn.nim15
-rw-r--r--tests/errmsgs/tsigmatch.nim172
-rw-r--r--tests/errmsgs/tsigmatch2.nim47
-rw-r--r--tests/errmsgs/tsimpletypecheck.nim10
-rw-r--r--tests/errmsgs/tstaticexprnotype.nim5
-rw-r--r--tests/errmsgs/tstaticexprscope.nim11
-rw-r--r--tests/errmsgs/tstaticresult.nim10
-rw-r--r--tests/errmsgs/tsubscriptmismatch.nim11
-rw-r--r--tests/errmsgs/tsubscriptmismatch_legacy.nim10
-rw-r--r--tests/errmsgs/ttupleindexoutofbounds.nim2
-rw-r--r--tests/errmsgs/ttypeAllowed.nim28
-rw-r--r--tests/errmsgs/tuncheckedarrayvar.nim7
-rw-r--r--tests/errmsgs/tundeclared_field.nim50
-rw-r--r--tests/errmsgs/tundeclared_routine.nim44
-rw-r--r--tests/errmsgs/tundeclared_routine_compiles.nim11
-rw-r--r--tests/errmsgs/tunknown_named_parameter.nim27
-rw-r--r--tests/errmsgs/tunresolvedinnerproc.nim10
-rw-r--r--tests/errmsgs/tuntypedoverload.nim37
-rw-r--r--tests/errmsgs/twrong_at_operator.nim21
-rw-r--r--tests/errmsgs/twrong_explicit_typeargs.nim26
-rw-r--r--tests/errmsgs/twrong_explicit_typeargs_legacy.nim25
-rw-r--r--tests/errmsgs/twrongcolon.nim10
-rw-r--r--tests/exception/m21261.nim1
-rw-r--r--tests/exception/m22469.nim4
-rw-r--r--tests/exception/t13115.nim31
-rw-r--r--tests/exception/t18620.nim17
-rw-r--r--tests/exception/t20613.nim8
-rw-r--r--tests/exception/t21261.nim9
-rw-r--r--tests/exception/t22008.nim8
-rw-r--r--tests/exception/t22469.nim16
-rw-r--r--tests/exception/t9657.nim12
-rw-r--r--tests/exception/tcontinuexc.nim26
-rw-r--r--tests/exception/tcpp_imported_exc.nim136
-rw-r--r--tests/exception/tcpp_imported_exc2.nim10
-rw-r--r--tests/exception/tdefer1.nim35
-rw-r--r--tests/exception/tdont_overwrite_typename.nim30
-rw-r--r--tests/exception/testindexerroroutput.nims23
-rw-r--r--tests/exception/texcas.nim43
-rw-r--r--tests/exception/texception_inference.nim32
-rw-r--r--tests/exception/texceptionbreak.nim44
-rw-r--r--tests/exception/texceptions.nim130
-rw-r--r--tests/exception/texceptions2.nim130
-rw-r--r--tests/exception/texcpt1.nim45
-rw-r--r--tests/exception/texcsub.nim13
-rw-r--r--tests/exception/tfinally.nim62
-rw-r--r--tests/exception/tfinally2.nim28
-rw-r--r--tests/exception/tfinally3.nim27
-rw-r--r--tests/exception/tfinally4.nim73
-rw-r--r--tests/exception/tnestedreturn.nim40
-rw-r--r--tests/exception/tnestedreturn2.nim19
-rw-r--r--tests/exception/treraise.nim20
-rw-r--r--tests/exception/tsetexceptions.nim11
-rw-r--r--tests/exception/tshow_real_exception_name.nim28
-rw-r--r--tests/exception/tunhandledexc.nim23
-rw-r--r--tests/exception/twrongexc.nim8
-rw-r--r--tests/exprs/t22604.nim36
-rw-r--r--tests/exprs/texprstmt.nim12
-rw-r--r--tests/exprs/thighCString.nim6
-rw-r--r--tests/exprs/tifexpr_typeinference.nim24
-rw-r--r--tests/exprs/tresultwarning.nim6
-rw-r--r--tests/exprs/tstmtexp.nim8
-rw-r--r--tests/exprs/tstmtexprs.nim163
-rw-r--r--tests/float/tfloat1.nim12
-rw-r--r--tests/float/tfloat2.nim12
-rw-r--r--tests/float/tfloat3.nim21
-rw-r--r--tests/float/tfloat4.nim69
-rw-r--r--tests/float/tfloat5.nim16
-rw-r--r--tests/float/tfloat7.nim27
-rw-r--r--tests/float/tfloatmod.nim130
-rw-r--r--tests/float/tfloatnan.nim57
-rw-r--r--tests/float/tfloatrange.nim50
-rw-r--r--tests/float/tfloats.nim163
-rw-r--r--tests/float/tissue5821.nim15
-rw-r--r--tests/float/tlenientops.nim100
-rw-r--r--tests/fragmentation/data.nim7629
-rw-r--r--tests/fragmentation/tfragment_alloc.nim35
-rw-r--r--tests/fragmentation/tfragment_gc.nim31
-rw-r--r--tests/gc/bintrees.nim54
-rw-r--r--tests/gc/closureleak.nim52
-rw-r--r--tests/gc/cyclecollector.nim23
-rw-r--r--tests/gc/cycleleak.nim56
-rw-r--r--tests/gc/foreign_thr.nim88
-rw-r--r--tests/gc/gcbench.nim180
-rw-r--r--tests/gc/gcemscripten.nim59
-rw-r--r--tests/gc/gcleak.nim29
-rw-r--r--tests/gc/gcleak2.nim38
-rw-r--r--tests/gc/gcleak3.nim26
-rw-r--r--tests/gc/gcleak4.nim46
-rw-r--r--tests/gc/gcleak5.nim25
-rw-r--r--[-rwxr-xr-x]tests/gc/gctest.nim (renamed from tests/gctest.nim)125
-rw-r--r--tests/gc/gctest.nim.cfg1
-rw-r--r--tests/gc/growobjcrash.nim24
-rw-r--r--tests/gc/panicoverride.nim14
-rw-r--r--tests/gc/refarrayleak.nim39
-rw-r--r--tests/gc/stackrefleak.nim32
-rw-r--r--tests/gc/tdisable_orc.nim9
-rw-r--r--tests/gc/thavlak.nim441
-rw-r--r--tests/gc/tlists.nim35
-rw-r--r--tests/gc/trace_globals.nim33
-rw-r--r--tests/gc/tregionleak.nim23
-rw-r--r--tests/gc/tstandalone.nim14
-rw-r--r--tests/gc/weakrefs.nim57
-rwxr-xr-xtests/gcbench.nim171
-rw-r--r--tests/generics/m14509.nim16
-rw-r--r--tests/generics/m22373a.nim7
-rw-r--r--tests/generics/m22373b.nim18
-rw-r--r--tests/generics/m3770.nim11
-rw-r--r--tests/generics/mbind_bracket.nim17
-rw-r--r--tests/generics/mclosed_sym.nim10
-rw-r--r--tests/generics/mdotlookup.nim28
-rw-r--r--tests/generics/mfriends.nim11
-rw-r--r--tests/generics/mmodule_same_as_proc.nim2
-rw-r--r--tests/generics/module_with_generics.nim14
-rw-r--r--tests/generics/mopensymimport1.nim34
-rw-r--r--tests/generics/mopensymimport2.nim16
-rw-r--r--tests/generics/moverloading_typedesc.nim11
-rw-r--r--tests/generics/mtypenodes.nim6
-rw-r--r--tests/generics/muninstantiatedgenericcalls.nim26
-rw-r--r--tests/generics/t12938.nim9
-rw-r--r--tests/generics/t13525.nim6
-rw-r--r--tests/generics/t14193.nim6
-rw-r--r--tests/generics/t14509.nim4
-rw-r--r--tests/generics/t1500.nim8
-rw-r--r--tests/generics/t17509.nim25
-rw-r--r--tests/generics/t18823.nim6
-rw-r--r--tests/generics/t18859.nim17
-rw-r--r--tests/generics/t19848.nim16
-rw-r--r--tests/generics/t20996.nim15
-rw-r--r--tests/generics/t21742.nim10
-rw-r--r--tests/generics/t21760.nim8
-rw-r--r--tests/generics/t21958.nim11
-rw-r--r--tests/generics/t22373.nim16
-rw-r--r--tests/generics/t22826.nim8
-rw-r--r--tests/generics/t23186.nim155
-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/t2tables.nim15
-rw-r--r--tests/generics/t3770.nim13
-rw-r--r--tests/generics/t4668.nim166
-rw-r--r--tests/generics/t500.nim8
-rw-r--r--tests/generics/t5602_inheritence.nim24
-rw-r--r--tests/generics/t5926.nim22
-rw-r--r--tests/generics/t6060.nim11
-rw-r--r--tests/generics/t6137.nim28
-rw-r--r--tests/generics/t6637.nim9
-rw-r--r--tests/generics/t7141.nim9
-rw-r--r--tests/generics/t7446.nim10
-rw-r--r--tests/generics/t7839.nim9
-rw-r--r--tests/generics/t8270.nim7
-rw-r--r--tests/generics/taliashijack.nim8
-rw-r--r--tests/generics/tarc_misc.nim21
-rw-r--r--tests/generics/tbadcache.nim26
-rw-r--r--tests/generics/tbaddeprecated.nim55
-rw-r--r--tests/generics/tbadgenericlambda.nim7
-rw-r--r--tests/generics/tbindoncevsbindmany.nim68
-rw-r--r--[-rwxr-xr-x]tests/generics/tbintree.nim (renamed from tests/tbintree.nim)33
-rw-r--r--tests/generics/tbracketinstantiation.nim86
-rw-r--r--tests/generics/tcalltype.nim26
-rw-r--r--tests/generics/tcan.nim46
-rw-r--r--tests/generics/tcannot_pass_empty_seq_to_generic.nim17
-rw-r--r--tests/generics/tconstraints.nim16
-rw-r--r--tests/generics/tcritical.nim19
-rw-r--r--tests/generics/texplicitgeneric1.nim36
-rw-r--r--tests/generics/texplicitgeneric2.nim35
-rw-r--r--tests/generics/tfakecovariance.nim78
-rw-r--r--tests/generics/tforwardgeneric.nim28
-rw-r--r--tests/generics/tforwardgenericconstrained.nim73
-rw-r--r--tests/generics/tfriends.nim11
-rw-r--r--tests/generics/tgeneric0.nim196
-rw-r--r--tests/generics/tgeneric3.nim487
-rw-r--r--tests/generics/tgeneric_recursionlimit.nim123
-rw-r--r--tests/generics/tgenericdotrettype.nim29
-rw-r--r--tests/generics/tgenericlambda.nim23
-rw-r--r--tests/generics/tgenericmatcher.nim40
-rw-r--r--tests/generics/tgenericprocvar.nim37
-rw-r--r--tests/generics/tgenerics_issues.nim894
-rw-r--r--tests/generics/tgenerics_various.nim254
-rw-r--r--tests/generics/tgenerictmpl2.nim31
-rw-r--r--tests/generics/tgenericvariant.nim36
-rw-r--r--tests/generics/tgenericwhen.nim58
-rw-r--r--tests/generics/tgensyminst.nim29
-rw-r--r--tests/generics/timpl_ast.nim80
-rw-r--r--tests/generics/timplicit_and_explicit.nim65
-rw-r--r--tests/generics/timports.nim63
-rw-r--r--tests/generics/tinheritable_importcpp.nim10
-rw-r--r--tests/generics/tlateboundgenericparams.nim145
-rw-r--r--tests/generics/tlateboundstatic.nim16
-rw-r--r--tests/generics/tmacroinjectedsym.nim186
-rw-r--r--tests/generics/tmacroinjectedsymwarning.nim59
-rw-r--r--tests/generics/tmapping_generic_alias.nim28
-rw-r--r--tests/generics/tmetafield.nim30
-rw-r--r--tests/generics/tnestedissues.nim24
-rw-r--r--tests/generics/tnestedtemplate.nim9
-rw-r--r--tests/generics/tnullary_generics.nim26
-rw-r--r--tests/generics/tobjecttyperel.nim89
-rw-r--r--tests/generics/tobjecttyperel2.nim42
-rw-r--r--tests/generics/topensymimport.nim5
-rw-r--r--tests/generics/toverloading_typedesc.nim19
-rw-r--r--tests/generics/tparam_binding.nim29
-rw-r--r--tests/generics/tparser_generator.nim415
-rw-r--r--tests/generics/tpointerprocs.nim28
-rw-r--r--tests/generics/tprevent_double_bind.nim21
-rw-r--r--tests/generics/trecursivegenerics.nim96
-rw-r--r--tests/generics/treentranttypes.nim114
-rw-r--r--tests/generics/treturn_inference.nim184
-rw-r--r--tests/generics/tstatic_constrained.nim79
-rw-r--r--tests/generics/tsubclassgenericerror.nim11
-rw-r--r--tests/generics/tthread_generic.nim39
-rw-r--r--tests/generics/tuninstantiated_failure.nim16
-rw-r--r--tests/generics/tuninstantiatedgenericcalls.nim517
-rw-r--r--tests/generics/tunique_type.nim67
-rw-r--r--tests/generics/tvarseq_caching.nim48
-rw-r--r--tests/generics/twrong_field_caching.nim68
-rw-r--r--tests/generics/twrong_floatlit_type.nim118
-rw-r--r--tests/generics/twrong_generic_object.nim21
-rw-r--r--tests/global/a_module.nim6
-rw-r--r--tests/global/globalaux.nim15
-rw-r--r--tests/global/globalaux2.nim4
-rw-r--r--tests/global/t15005.nim18
-rw-r--r--tests/global/t21896.nim9
-rw-r--r--tests/global/t3505.nim41
-rw-r--r--tests/global/t5958.nim9
-rw-r--r--tests/global/tglobal.nim16
-rw-r--r--tests/global/tglobal2.nim9
-rw-r--r--tests/global/tglobalforvar.nim9
-rwxr-xr-xtests/gtk/ex1.nim14
-rwxr-xr-xtests/gtk/ex2.nim21
-rwxr-xr-xtests/gtk/ex3.nim39
-rwxr-xr-xtests/gtk/ex4.nim31
-rwxr-xr-xtests/gtk/ex5.nim24
-rwxr-xr-xtests/gtk/ex6.nim52
-rwxr-xr-xtests/gtk/ex7.nim43
-rwxr-xr-xtests/gtk/ex8.nim32
-rwxr-xr-xtests/gtk/ex9.nim47
-rwxr-xr-xtests/hallo.nim34
-rw-r--r--tests/ic/config.nims1
-rw-r--r--tests/ic/mbaseobj.nim7
-rw-r--r--tests/ic/mcompiletime_counter.nim15
-rw-r--r--tests/ic/mdefconverter.nim2
-rw-r--r--tests/ic/mimports.nim9
-rw-r--r--tests/ic/mimportsb.nim4
-rw-r--r--tests/ic/tcompiletime_counter.nim24
-rw-r--r--tests/ic/tconverter.nim18
-rw-r--r--tests/ic/tgenericinst.nim11
-rw-r--r--tests/ic/tgenerics.nim38
-rw-r--r--tests/ic/thallo.nim28
-rw-r--r--tests/ic/timports.nim29
-rw-r--r--tests/ic/tmethods.nim28
-rw-r--r--tests/ic/tstdlib_import_changed.nim15
-rw-r--r--tests/import/buzz/m21496.nim1
-rw-r--r--tests/import/fizz/m21496.nim1
-rw-r--r--tests/import/t21496.nim9
-rw-r--r--tests/import/t22065.nim5
-rw-r--r--tests/import/t22208.nim6
-rw-r--r--tests/import/t23167.nim5
-rw-r--r--tests/import_in_config/nim.cfg2
-rw-r--r--tests/import_in_config/other.nim0
-rw-r--r--tests/import_in_config/tmain.nim0
-rw-r--r--tests/importalls/m1.nim70
-rw-r--r--tests/importalls/m2.nim3
-rw-r--r--tests/importalls/m3.nim5
-rw-r--r--tests/importalls/m4.nim9
-rw-r--r--tests/importalls/mt0.nim9
-rw-r--r--tests/importalls/mt1.nim23
-rw-r--r--tests/importalls/mt2.nim104
-rw-r--r--tests/importalls/mt3.nim12
-rw-r--r--tests/importalls/mt4.nim4
-rw-r--r--tests/importalls/mt4b.nim3
-rw-r--r--tests/importalls/mt5.nim9
-rw-r--r--tests/importalls/mt6.nim13
-rw-r--r--tests/importalls/mt7.nim14
-rw-r--r--tests/importalls/mt8.nim23
-rw-r--r--tests/importalls/mt9.nim12
-rw-r--r--tests/importalls/tmain2.nim7
-rw-r--r--tests/init/t8314.nim27
-rw-r--r--tests/init/tcompiles.nim101
-rw-r--r--tests/init/tinitchecks_v2.nim83
-rw-r--r--tests/init/tlet.nim55
-rw-r--r--tests/init/tlet_uninit2.nim5
-rw-r--r--tests/init/tlet_uninit3.nim24
-rw-r--r--tests/init/tlet_uninit4.nim12
-rw-r--r--tests/init/toutparam_subtype.nim24
-rw-r--r--tests/init/toutparams.nim14
-rw-r--r--tests/init/tproveinit.nim18
-rw-r--r--tests/init/treturns.nim106
-rw-r--r--tests/init/tuninit1.nim36
-rw-r--r--tests/init/tuninit2.nim54
-rw-r--r--tests/init/tzeroarray.nim18
-rw-r--r--tests/int/t1.nim61
-rw-r--r--tests/int/tarithm.nim187
-rw-r--r--tests/int/tashr.nim46
-rw-r--r--tests/int/tdiv.nim19
-rw-r--r--tests/int/tints.nim150
-rw-r--r--tests/int/tunsigned64mod.nim24
-rw-r--r--tests/int/tunsignedcmp.nim43
-rw-r--r--tests/int/tunsignedcomp.nim136
-rw-r--r--tests/int/tunsignedconv.nim115
-rw-r--r--tests/int/tunsignedinc.nim40
-rw-r--r--tests/int/tunsignedmisc.nim66
-rw-r--r--tests/int/twrongexplicitvarconv.nim16
-rw-r--r--tests/int/twrongvarconv.nim9
-rw-r--r--tests/isolate/tisolate.nim41
-rw-r--r--tests/isolate/tisolate2.nim22
-rw-r--r--tests/isolate/tisolated_lock.nim67
-rw-r--r--tests/iter/t1550.nim24
-rw-r--r--tests/iter/t16076.nim45
-rw-r--r--tests/iter/t20891.nim28
-rw-r--r--tests/iter/t21306.nim118
-rw-r--r--tests/iter/t21737.nim22
-rw-r--r--tests/iter/t22148.nim15
-rw-r--r--tests/iter/t22548.nim21
-rw-r--r--tests/iter/t22619.nim83
-rw-r--r--tests/iter/t2771.nim25
-rw-r--r--tests/iter/tanoniter1.nim33
-rw-r--r--tests/iter/tarrayiter.nim14
-rw-r--r--tests/iter/tchainediterators.nim41
-rw-r--r--tests/iter/tclosureiters.nim176
-rw-r--r--tests/iter/tcountup.nim25
-rw-r--r--tests/iter/tgeniteratorinblock.nim54
-rw-r--r--tests/iter/timplicit_auto.nim18
-rw-r--r--tests/iter/titer.nim147
-rw-r--r--tests/iter/titer10.nim51
-rw-r--r--tests/iter/titer11.nim40
-rw-r--r--tests/iter/titer12.nim83
-rw-r--r--tests/iter/titer13.nim83
-rw-r--r--tests/iter/titer14.nim7
-rw-r--r--tests/iter/titer2.nim66
-rw-r--r--tests/iter/titer3.nim54
-rw-r--r--tests/iter/titer4.nim8
-rw-r--r--tests/iter/titer5.nim13
-rw-r--r--tests/iter/titer6.nim35
-rw-r--r--tests/iter/titer7.nim53
-rw-r--r--tests/iter/titer8.nim117
-rw-r--r--tests/iter/titer9.nim20
-rw-r--r--tests/iter/titer_issues.nim411
-rw-r--r--tests/iter/titer_no_tuple_unpack.nim27
-rw-r--r--tests/iter/titerable.nim29
-rw-r--r--tests/iter/titerautoerr1.nim8
-rw-r--r--tests/iter/titerautoerr2.nim8
-rw-r--r--tests/iter/titerautoerr3.nim9
-rw-r--r--tests/iter/titerconcat.nim24
-rw-r--r--tests/iter/titerovl.nim21
-rw-r--r--tests/iter/titerslice.nim9
-rw-r--r--tests/iter/titertypedesc.nim17
-rw-r--r--[-rwxr-xr-x]tests/iter/titervaropenarray.nim (renamed from tests/titer2.nim)5
-rw-r--r--tests/iter/tmoditer.nim88
-rw-r--r--tests/iter/tpermutations.nim69
-rw-r--r--tests/iter/treciter.nim12
-rw-r--r--tests/iter/tscheduler.nim77
-rw-r--r--tests/iter/tshallowcopy_closures.nim36
-rw-r--r--tests/iter/twrap_walkdir.nim17
-rw-r--r--tests/iter/twrongiter.nim13
-rw-r--r--tests/iter/tyieldintry.nim529
-rw-r--r--[-rwxr-xr-x]tests/js.html (renamed from tests/ecmas.html)10
-rw-r--r--tests/js.nim24
-rw-r--r--tests/js/readme.md5
-rw-r--r--tests/js/t11166.nim20
-rw-r--r--tests/js/t11353.nim14
-rw-r--r--tests/js/t11354.nim20
-rw-r--r--tests/js/t11697.nim5
-rw-r--r--tests/js/t12223.nim20
-rw-r--r--tests/js/t12303.nim16
-rw-r--r--tests/js/t12672.nim12
-rw-r--r--tests/js/t14153.nim22
-rw-r--r--tests/js/t14570.nim11
-rw-r--r--tests/js/t17177.nim10
-rw-r--r--tests/js/t20233.nim7
-rw-r--r--tests/js/t20235.nim11
-rw-r--r--tests/js/t21209.nim6
-rw-r--r--tests/js/t21209.nims1
-rw-r--r--tests/js/t21247.nim15
-rw-r--r--tests/js/t21439.nim11
-rw-r--r--tests/js/t6612.nim24
-rw-r--r--tests/js/t7109.nim8
-rw-r--r--tests/js/t7127.nim2
-rw-r--r--tests/js/t7224.nim28
-rw-r--r--tests/js/t7249.nim21
-rw-r--r--tests/js/t7534.nim7
-rw-r--r--tests/js/t8231.nim3
-rw-r--r--tests/js/t8821.nim9
-rw-r--r--tests/js/t8914.nim12
-rw-r--r--tests/js/t9410.nim471
-rw-r--r--tests/js/tarrayboundscheck.nim50
-rw-r--r--tests/js/tasyncjs.nim107
-rw-r--r--tests/js/tasyncjs_bad.nim22
-rw-r--r--tests/js/tasyncjs_pragma.nim29
-rw-r--r--tests/js/tbasics.nim62
-rw-r--r--tests/js/tbigint_backend.nim57
-rw-r--r--tests/js/tbyvar.nim123
-rw-r--r--tests/js/tclosures.nim95
-rw-r--r--tests/js/tcodegendeclproc.nim11
-rw-r--r--tests/js/tcodegendeclvar.nim10
-rw-r--r--tests/js/tconsole.nim13
-rw-r--r--tests/js/tcopying.nim80
-rw-r--r--tests/js/tcsymbol.nim6
-rw-r--r--tests/js/tdanger.nim17
-rw-r--r--tests/js/tderef.nim20
-rw-r--r--tests/js/tdiscard.nim3
-rw-r--r--tests/js/tdollar_float.nim62
-rw-r--r--tests/js/temptyseq.nim8
-rw-r--r--tests/js/tenumhole.nim12
-rw-r--r--tests/js/tenumnegkey.nim12
-rw-r--r--tests/js/tenumoffset.nim19
-rw-r--r--tests/js/test1.nim52
-rw-r--r--tests/js/test2.nim58
-rw-r--r--tests/js/testmagic.nim12
-rw-r--r--tests/js/testobjs.nim73
-rw-r--r--tests/js/testtojsstr.nim8
-rw-r--r--tests/js/tfieldchecks.nim48
-rw-r--r--tests/js/tfloatround.nim7
-rw-r--r--tests/js/tglobal.nim30
-rw-r--r--tests/js/timplicit_nodecl.nim13
-rw-r--r--tests/js/tindexdefect.nim9
-rw-r--r--tests/js/tjsffi.nim274
-rw-r--r--tests/js/tjsffi_old.nim340
-rw-r--r--tests/js/tjshello.nim10
-rw-r--r--tests/js/tjshello_stacktrace.nim9
-rw-r--r--tests/js/tjsnimscombined.nim1
-rw-r--r--tests/js/tjsnimscombined.nims1
-rw-r--r--tests/js/tlent.nim33
-rw-r--r--tests/js/tmangle.nim106
-rw-r--r--tests/js/tmodify_cstring.nim6
-rw-r--r--tests/js/tnativeexc.nim31
-rw-r--r--tests/js/tneginthash.nim21
-rw-r--r--tests/js/tnilstrs.nim25
-rw-r--r--tests/js/tobjfieldbyvar.nim20
-rw-r--r--tests/js/tos.nim21
-rw-r--r--tests/js/trefbyvar.nim69
-rw-r--r--tests/js/trepr.nim413
-rw-r--r--tests/js/treprinifexpr.nim18
-rw-r--r--tests/js/tseqops.nim48
-rw-r--r--tests/js/tsourcemap.nim96
-rw-r--r--tests/js/tstdlib_imports.nim80
-rw-r--r--tests/js/tstdlib_various.nim174
-rw-r--r--tests/js/tstreams.nim22
-rw-r--r--tests/js/tstring_assignment.nim21
-rw-r--r--tests/js/tstringitems.nim95
-rw-r--r--tests/js/ttempgen.nim79
-rw-r--r--tests/js/tthismangle.nim23
-rw-r--r--tests/js/ttryexceptnewsyntax.nim13
-rw-r--r--tests/js/ttypedarray.nim26
-rw-r--r--tests/js/tunion.nim7
-rw-r--r--tests/js/tunittest_error.nim24
-rw-r--r--tests/js/tunittest_error2.nim16
-rw-r--r--tests/js/tvarargs.nim15
-rw-r--r--tests/js/twritestacktrace.nim12
-rwxr-xr-xtests/jsontest.json22
-rw-r--r--tests/lent/t16898.nim31
-rw-r--r--tests/lent/t17621.nim15
-rw-r--r--tests/lent/tbasic_lent_check.nim62
-rw-r--r--tests/lent/tlent_from_var.nim107
-rw-r--r--tests/lent/tnot_allowed_lent.nim24
-rw-r--r--tests/lent/tnot_allowed_lent2.nim14
-rw-r--r--tests/lent/tvm.nim21
-rw-r--r--tests/let/t7936.nim27
-rw-r--r--tests/let/timportc.nim24
-rw-r--r--tests/let/timportc2.nim8
-rw-r--r--tests/let/tlet.nim10
-rw-r--r--tests/let/tlet2.nim15
-rw-r--r--tests/lexer/mlexerutils.nim9
-rw-r--r--tests/lexer/tcustom_numeric_literals.nim177
-rw-r--r--[-rwxr-xr-x]tests/lexer/tident.nim (renamed from tests/tident.nim)32
-rw-r--r--tests/lexer/tind1.nim25
-rw-r--r--tests/lexer/tindent1.nim42
-rw-r--r--tests/lexer/tintegerliterals.nim9
-rw-r--r--tests/lexer/tinvalidintegerliteral1.nim7
-rw-r--r--tests/lexer/tinvalidintegerliteral2.nim7
-rw-r--r--tests/lexer/tinvalidintegerliteral3.nim7
-rw-r--r--[-rwxr-xr-x]tests/lexer/tlexer.nim (renamed from tests/scantest.nim)122
-rw-r--r--tests/lexer/tlexermisc.nim27
-rw-r--r--tests/lexer/tlexerspaces.nim2
-rw-r--r--tests/lexer/tmissingnl.nim9
-rw-r--r--[-rwxr-xr-x]tests/lexer/trawstr.nim (renamed from tests/trawstr.nim)15
-rw-r--r--tests/lexer/tstrlits.nim19
-rw-r--r--tests/lexer/tunary_minus.nim83
-rw-r--r--tests/lexer/tunderscores.nim11
-rw-r--r--tests/lexer/tunicode_operators.nim16
-rw-r--r--tests/lookups/issue_23032/deep_scope.nim2
-rw-r--r--tests/lookups/issue_23172/m23172.nim6
-rw-r--r--[-rwxr-xr-x]tests/lookups/mambsym1.nim (renamed from tests/mambsym1.nim)20
-rw-r--r--[-rwxr-xr-x]tests/lookups/mambsym2.nim (renamed from tests/mambsym2.nim)6
-rw-r--r--tests/lookups/mambsym3.nim4
-rw-r--r--tests/lookups/mambsym4.nim4
-rw-r--r--[-rwxr-xr-x]tests/lookups/mambsys1.nim (renamed from tests/mambsys1.nim)14
-rw-r--r--[-rwxr-xr-x]tests/lookups/mambsys2.nim (renamed from tests/mambsys2.nim)8
-rw-r--r--tests/lookups/mambtype1.nim1
-rw-r--r--tests/lookups/mambtype2.nim4
-rw-r--r--tests/lookups/mbind3.nim10
-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/t23032.nim13
-rw-r--r--tests/lookups/t23172.nim9
-rw-r--r--tests/lookups/t23749.nim37
-rw-r--r--tests/lookups/tambiguousemit.nim12
-rw-r--r--tests/lookups/tambprocvar.nim19
-rw-r--r--[-rwxr-xr-x]tests/lookups/tambsym.nim (renamed from tests/tambsym.nim)21
-rw-r--r--[-rwxr-xr-x]tests/lookups/tambsym2.nim (renamed from tests/tambsym2.nim)11
-rw-r--r--tests/lookups/tambsym3.nim13
-rw-r--r--tests/lookups/tambsymmanual.nim25
-rw-r--r--[-rwxr-xr-x]tests/lookups/tambsys.nim (renamed from tests/tambsys.nim)17
-rw-r--r--tests/lookups/tambtype.nim20
-rw-r--r--tests/lookups/tbind.nim78
-rw-r--r--tests/lookups/tbind_for_generics.nim17
-rw-r--r--tests/lookups/tdisambsym.nim8
-rw-r--r--tests/lookups/tenumlocalsym.nim22
-rw-r--r--tests/lookups/test.nim23
-rw-r--r--tests/lookups/tgensym.nim16
-rw-r--r--tests/lookups/tgensymgeneric.nim54
-rw-r--r--tests/lookups/tinvalidbindtypedesc.nim10
-rw-r--r--tests/lookups/tkoeniglookup.nim17
-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/lookups/tnicerrorforsymchoice.nim23
-rw-r--r--tests/lookups/told_bind_expr.nim15
-rw-r--r--tests/lookups/tredef.nim29
-rw-r--r--tests/lookups/tundeclaredmixin.nim17
-rw-r--r--tests/m14634.nim48
-rw-r--r--tests/macros/m18235.nim42
-rw-r--r--tests/macros/macro_bug.nim18
-rw-r--r--tests/macros/mparsefile.nim4
-rw-r--r--tests/macros/t14227.nim23
-rw-r--r--tests/macros/t14329.nim4
-rw-r--r--tests/macros/t14511.nim54
-rw-r--r--tests/macros/t14847.nim20
-rw-r--r--tests/macros/t15691.nim22
-rw-r--r--tests/macros/t15751.nim11
-rw-r--r--tests/macros/t16758.nim38
-rw-r--r--tests/macros/t17836.nim15
-rw-r--r--tests/macros/t18203.nim15
-rw-r--r--tests/macros/t18235.nim18
-rw-r--r--tests/macros/t19766_20114.nim16
-rw-r--r--tests/macros/t20067.nim28
-rw-r--r--tests/macros/t20435.nim30
-rw-r--r--tests/macros/t21593.nim13
-rw-r--r--tests/macros/t23032_1.nim19
-rw-r--r--tests/macros/t23032_2.nim20
-rw-r--r--tests/macros/t23547.nim23
-rw-r--r--tests/macros/t23784.nim157
-rw-r--r--tests/macros/t7454.nim8
-rw-r--r--tests/macros/t7875.nim22
-rw-r--r--tests/macros/t8997.nim26
-rw-r--r--tests/macros/tastrepr.nim58
-rw-r--r--tests/macros/tbindsym.nim67
-rw-r--r--tests/macros/tcasestmtmacro.nim33
-rw-r--r--tests/macros/tclosuremacro.nim80
-rw-r--r--tests/macros/tcollect.nim63
-rw-r--r--tests/macros/tcomplexecho.nim42
-rw-r--r--tests/macros/tcprag.nim32
-rw-r--r--tests/macros/tdumpast.nim161
-rw-r--r--tests/macros/tdumpast2.nim36
-rw-r--r--tests/macros/tdumpastgen.nim45
-rw-r--r--tests/macros/tdumptree.nim27
-rw-r--r--tests/macros/tescape_var_into_quotedo_as_const.nim36
-rw-r--r--tests/macros/texpectIdent1.nim18
-rw-r--r--tests/macros/texpectIdent2.nim24
-rw-r--r--tests/macros/tfail_parse.nim15
-rw-r--r--tests/macros/tforloop_macro1.nim44
-rw-r--r--tests/macros/tgetimpl.nim103
-rw-r--r--tests/macros/tgetraiseslist.nim29
-rw-r--r--tests/macros/tgettype.nim85
-rw-r--r--tests/macros/tgettype2.nim99
-rw-r--r--tests/macros/tgettype3.nim48
-rw-r--r--tests/macros/tgettypeinst.nim214
-rw-r--r--tests/macros/tgettypeinst7737.nim61
-rw-r--r--tests/macros/tincremental.nim150
-rw-r--r--tests/macros/tinvalidtypesym.nim14
-rw-r--r--tests/macros/tisexported.nim10
-rw-r--r--tests/macros/tlocktypednode1.nim12
-rw-r--r--tests/macros/tlocktypednode2.nim12
-rw-r--r--tests/macros/tlocktypednode3.nim15
-rw-r--r--tests/macros/tmacro1.nim119
-rw-r--r--tests/macros/tmacro2.nim36
-rw-r--r--tests/macros/tmacro3.nim30
-rw-r--r--tests/macros/tmacro4.nim17
-rw-r--r--tests/macros/tmacro5.nim59
-rw-r--r--tests/macros/tmacro6.nim75
-rw-r--r--tests/macros/tmacro7.nim36
-rw-r--r--tests/macros/tmacro8.nim35
-rw-r--r--tests/macros/tmacroaspragma.nim7
-rw-r--r--tests/macros/tmacrogenerics.nim38
-rw-r--r--tests/macros/tmacrogensym.nim65
-rw-r--r--tests/macros/tmacrogetimpl.nim31
-rw-r--r--tests/macros/tmacros1.nim81
-rw-r--r--tests/macros/tmacros_issues.nim521
-rw-r--r--tests/macros/tmacros_various.nim391
-rw-r--r--tests/macros/tmacrostmt.nim155
-rw-r--r--tests/macros/tmacrotypes.nim157
-rw-r--r--tests/macros/tmemit.nim38
-rw-r--r--tests/macros/tmsginfo.nim24
-rw-r--r--tests/macros/tnewlit.nim194
-rw-r--r--tests/macros/tnewproc.nim51
-rw-r--r--tests/macros/tnodecompare.nim39
-rw-r--r--tests/macros/tparsefile.nim11
-rw-r--r--tests/macros/tprocgettype.nim28
-rw-r--r--tests/macros/tprochelpers.nim22
-rw-r--r--tests/macros/tquotedo.nim51
-rw-r--r--tests/macros/tquotewords.nim22
-rw-r--r--tests/macros/trecmacro.nim14
-rw-r--r--tests/macros/treturnsempty.nim11
-rw-r--r--tests/macros/tsame_name_497.nim6
-rw-r--r--tests/macros/tsametype.nim42
-rw-r--r--tests/macros/tslice.nim38
-rw-r--r--tests/macros/tstaticparamsmacro.nim75
-rw-r--r--tests/macros/tstringinterp.nim73
-rw-r--r--tests/macros/tstructuredlogging.nim154
-rw-r--r--tests/macros/ttemplatesymbols.nim171
-rw-r--r--tests/macros/ttryparseexpr.nim24
-rw-r--r--tests/macros/ttypenodes.nim16
-rw-r--r--tests/macros/tvarargsuntyped.nim108
-rw-r--r--tests/macros/tvtable.nim74
-rw-r--r--tests/macros/twrapiterator.nim19
-rw-r--r--tests/macros/typesafeprintf.nim49
-rw-r--r--tests/macros/typesapi2.nim48
-rw-r--r--tests/manyloc/argument_parser/argument_parser.nim493
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim87
-rw-r--r--tests/manyloc/argument_parser/ex_wget.nim.cfg1
-rw-r--r--tests/manyloc/keineschweine/README.md26
-rw-r--r--tests/manyloc/keineschweine/TODO.md21
-rw-r--r--tests/manyloc/keineschweine/client_settings.json10
-rw-r--r--tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim1514
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/enet.nim611
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/testclient.nim49
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/testserver.nim45
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim287
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim64
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim47
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nake.nim88
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nakefile.nim23
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/README.md13
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml.nim1121
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim899
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim15
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim1
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_client.nim229
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_server.nim294
-rw-r--r--tests/manyloc/keineschweine/enet_server/nakefile.nim13
-rw-r--r--tests/manyloc/keineschweine/enet_server/nim.cfg9
-rw-r--r--tests/manyloc/keineschweine/enet_server/server_settings.json8
-rw-r--r--tests/manyloc/keineschweine/enet_server/server_utils.nim122
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim726
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim.cfg10
-rw-r--r--tests/manyloc/keineschweine/lib/animations.nim75
-rw-r--r--tests/manyloc/keineschweine/lib/client_helpers.nim144
-rw-r--r--tests/manyloc/keineschweine/lib/estreams.nim120
-rw-r--r--tests/manyloc/keineschweine/lib/game_objects.nim34
-rw-r--r--tests/manyloc/keineschweine/lib/gl.nim1536
-rw-r--r--tests/manyloc/keineschweine/lib/glext.nim4673
-rw-r--r--tests/manyloc/keineschweine/lib/glu.nim335
-rw-r--r--tests/manyloc/keineschweine/lib/glut.nim438
-rw-r--r--tests/manyloc/keineschweine/lib/glx.nim153
-rw-r--r--tests/manyloc/keineschweine/lib/idgen.nim23
-rw-r--r--tests/manyloc/keineschweine/lib/input_helpers.nim138
-rw-r--r--tests/manyloc/keineschweine/lib/map_filter.nim41
-rw-r--r--tests/manyloc/keineschweine/lib/math_helpers.nim10
-rw-r--r--tests/manyloc/keineschweine/lib/sfml_stuff.nim37
-rw-r--r--tests/manyloc/keineschweine/lib/sg_assets.nim611
-rw-r--r--tests/manyloc/keineschweine/lib/sg_gui.nim281
-rw-r--r--tests/manyloc/keineschweine/lib/sg_packets.nim110
-rw-r--r--tests/manyloc/keineschweine/lib/sound_buffer.nim38
-rw-r--r--tests/manyloc/keineschweine/lib/vehicles.nim35
-rw-r--r--tests/manyloc/keineschweine/lib/wingl.nim368
-rw-r--r--tests/manyloc/keineschweine/lib/zlib_helpers.nim45
-rw-r--r--tests/manyloc/keineschweine/server/dirserver_settings.json7
-rw-r--r--tests/manyloc/keineschweine/server/nim.cfg5
-rw-r--r--tests/manyloc/keineschweine/server/old_dirserver.nim201
-rw-r--r--tests/manyloc/keineschweine/server/old_server_utils.nim100
-rw-r--r--tests/manyloc/keineschweine/server/old_sg_server.nim254
-rw-r--r--tests/manyloc/keineschweine/server/sg_lobby.nim268
-rw-r--r--tests/manyloc/nake/nake.nim84
-rw-r--r--tests/manyloc/nake/nakefile.nim157
-rw-r--r--tests/manyloc/nake/nakefile.nim.cfg1
-rw-r--r--tests/manyloc/named_argument_bug/gui.nim44
-rw-r--r--tests/manyloc/named_argument_bug/main.nim23
-rw-r--r--tests/manyloc/named_argument_bug/main.nim.cfg3
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/config.nim6
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim54
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim61
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim157
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim103
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim31
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/circle.nim9
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/rect.nim8
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/math/vec.nim55
-rw-r--r--tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim106
-rw-r--r--tests/manyloc/packages/noconflicts.nim16
-rw-r--r--tests/manyloc/packages/noconflicts.nim.cfg1
-rw-r--r--tests/manyloc/packages/os.nim5
-rw-r--r--tests/manyloc/packages/package1/p1.babel0
-rw-r--r--tests/manyloc/packages/package1/strutils.nim5
-rw-r--r--tests/manyloc/packages/package2/p2.babel0
-rw-r--r--tests/manyloc/packages/package2/strutils.nim5
-rw-r--r--tests/manyloc/standalone/barebone.nim16
-rw-r--r--tests/manyloc/standalone/barebone.nim.cfg2
-rw-r--r--tests/manyloc/standalone/panicoverride.nim14
-rw-r--r--tests/manyloc/standalone2/panicoverride.nim14
-rw-r--r--tests/manyloc/standalone2/tavr.nim7
-rw-r--r--tests/manyloc/standalone2/tavr.nim.cfg5
-rw-r--r--tests/metatype/tbindtypedesc.nim95
-rw-r--r--tests/metatype/tcompositetypeclasses.nim59
-rw-r--r--tests/metatype/tcps.nim35
-rw-r--r--tests/metatype/tmatrix1.nim19
-rw-r--r--tests/metatype/tmatrix2.nim22
-rw-r--r--tests/metatype/tmatrix3.nim19
-rw-r--r--tests/metatype/tmatrix4.nim39
-rw-r--r--tests/metatype/tmeta_typeclasses.nim70
-rw-r--r--tests/metatype/tmetatype_issues.nim168
-rw-r--r--tests/metatype/tmetatype_various.nim73
-rw-r--r--tests/metatype/tmetatypematrix.nim46
-rw-r--r--tests/metatype/tsemistatic.nim31
-rw-r--r--tests/metatype/tshacontext.nim44
-rw-r--r--tests/metatype/tstatic_generic_typeclass.nim30
-rw-r--r--tests/metatype/tstaticparammacro.nim76
-rw-r--r--tests/metatype/tstaticparams.nim197
-rw-r--r--tests/metatype/tstaticvector.nim76
-rw-r--r--tests/metatype/ttensor.nim39
-rw-r--r--tests/metatype/ttypedesc1.nim68
-rw-r--r--tests/metatype/ttypedesc2.nim93
-rw-r--r--tests/metatype/ttypedesc3.nim53
-rw-r--r--tests/metatype/ttypedescnotnimnode.nim21
-rw-r--r--tests/metatype/ttypeselectors.nim100
-rw-r--r--tests/metatype/ttypetraits.nim404
-rw-r--r--tests/metatype/tunresolved_return_type.nim20
-rw-r--r--tests/metatype/tvoid_must_not_match.nim21
-rw-r--r--tests/metatype/twildtypedesc.nim43
-rw-r--r--tests/metatype/twrong_same_type.nim28
-rw-r--r--tests/metatype/tymatrix.nim21
-rw-r--r--tests/metatype/typeclassinference.nim43
-rw-r--r--tests/metatype/typedesc_as_value.nim11
-rw-r--r--tests/metatype/utypeclasses.nim13
-rw-r--r--tests/method/mmultim3.nim12
-rw-r--r--tests/method/t20515.nim20
-rw-r--r--tests/method/t22673.nim21
-rw-r--r--tests/method/tcompilegenerics.nim24
-rw-r--r--tests/method/tgeneric_methods.nim42
-rw-r--r--tests/method/tmapper.nim30
-rw-r--r--tests/method/tmethod.nim8
-rw-r--r--tests/method/tmethod_issues.nim170
-rw-r--r--tests/method/tmethod_various.nim79
-rw-r--r--tests/method/tmethods_old.nim12
-rw-r--r--tests/method/tmultim.nim97
-rw-r--r--tests/method/tmultimjs.nim73
-rw-r--r--tests/method/tnildispatcher.nim21
-rw-r--r--tests/method/treturn_var_t.nim25
-rw-r--r--tests/method/tsingle_methods.nim48
-rw-r--r--tests/method/tvtable.nim24
-rw-r--r--tests/misc/99bottles.nim1
-rw-r--r--tests/misc/m15316.nim1
-rw-r--r--tests/misc/m15955.nim4
-rw-r--r--tests/misc/m15955_main.nim11
-rw-r--r--tests/misc/m20149.nim2
-rw-r--r--tests/misc/m20456.nims1
-rw-r--r--tests/misc/mbackend.nim30
-rw-r--r--tests/misc/mbetterrun.nim3
-rw-r--r--tests/misc/mfield_defect.nim30
-rw-r--r--tests/misc/mimportc.nim26
-rw-r--r--[-rwxr-xr-x]tests/misc/minit.nim (renamed from tests/minit.nim)4
-rw-r--r--tests/misc/mjsondoc.nim14
-rw-r--r--tests/misc/modulea.nim2
-rw-r--r--tests/misc/msizeof5.nim131
-rw-r--r--tests/misc/msizeof5.nim.cfg5
-rw-r--r--tests/misc/mtlsemulation.h37
-rw-r--r--tests/misc/mvarious.nim6
-rw-r--r--tests/misc/parsecomb.nim109
-rw-r--r--tests/misc/t11634.nim17
-rw-r--r--tests/misc/t12480.nim5
-rw-r--r--tests/misc/t12869.nim14
-rw-r--r--tests/misc/t14667.nim12
-rw-r--r--tests/misc/t15351.nim5
-rw-r--r--tests/misc/t15955.nim22
-rw-r--r--tests/misc/t16244.nim9
-rw-r--r--tests/misc/t16264.nim2
-rw-r--r--tests/misc/t16541.nim12
-rw-r--r--tests/misc/t17286.nim16
-rw-r--r--tests/misc/t18077.nim21
-rw-r--r--tests/misc/t18079.nim15
-rw-r--r--tests/misc/t19046.nim19
-rw-r--r--tests/misc/t20253.nim10
-rw-r--r--tests/misc/t20289.nim15
-rw-r--r--tests/misc/t20456_2.nim14
-rw-r--r--tests/misc/t20883.nim13
-rw-r--r--tests/misc/t21109.nim13
-rw-r--r--tests/misc/t21443.nim6
-rw-r--r--tests/misc/t23240.nim6
-rw-r--r--tests/misc/t3482.nim15
-rw-r--r--tests/misc/t3907.nim10
-rw-r--r--tests/misc/t5540.nim45
-rw-r--r--tests/misc/t6549.nim4
-rw-r--r--tests/misc/t8404.nim33
-rw-r--r--tests/misc/t8545.nim24
-rw-r--r--tests/misc/t9039.nim24
-rw-r--r--tests/misc/t9091.nim33
-rw-r--r--tests/misc/t9710.nim6
-rw-r--r--tests/misc/t99bott.nim32
-rw-r--r--[-rwxr-xr-x]tests/misc/tack.nim (renamed from tests/tack.nim)34
-rw-r--r--tests/misc/taddr.nim295
-rw-r--r--tests/misc/tapp_lib_staticlib.nim27
-rw-r--r--tests/misc/tbug1217bracketquotes.nim14
-rw-r--r--tests/misc/tbug511622.nim12
-rw-r--r--tests/misc/tcast.nim108
-rw-r--r--tests/misc/tcharinc.nim10
-rw-r--r--tests/misc/tcmdline.nim18
-rw-r--r--tests/misc/tconv.nim143
-rw-r--r--tests/misc/tcsharpusingstatement.nim76
-rw-r--r--tests/misc/tdangerisrelease.nim14
-rw-r--r--tests/misc/tdefine.nim77
-rw-r--r--tests/misc/tdllvar.nim18
-rw-r--r--tests/misc/teventemitter.nim32
-rw-r--r--tests/misc/tfib.nim11
-rw-r--r--tests/misc/tfilter.nim41
-rw-r--r--[-rwxr-xr-x]tests/misc/thallo.nim (renamed from tests/thallo.nim)40
-rw-r--r--tests/misc/theaproots.nim75
-rw-r--r--tests/misc/tinit.nim9
-rw-r--r--[-rwxr-xr-x]tests/misc/tinout.nim (renamed from tests/tinout.nim)23
-rw-r--r--tests/misc/tinvalidnewseq.nim24
-rw-r--r--tests/misc/tissue710.nim10
-rw-r--r--tests/misc/tjoinable.nim3
-rw-r--r--tests/misc/tlastmod.nim25
-rw-r--r--[-rwxr-xr-x]tests/misc/tloops.nim (renamed from tests/tloops.nim)157
-rw-r--r--tests/misc/tmemoization.nim17
-rw-r--r--tests/misc/tmissingnilcheck.nim20
-rw-r--r--tests/misc/tmodulea.nim3
-rw-r--r--tests/misc/tnoforward.nim15
-rw-r--r--tests/misc/tnolen.nim8
-rw-r--r--[-rwxr-xr-x]tests/misc/tparedef.nim (renamed from tests/tparedef.nim)8
-rw-r--r--tests/misc/tparsecombnum.nim55
-rw-r--r--tests/misc/tparseopt.nim156
-rw-r--r--[-rwxr-xr-x]tests/misc/tpos.nim (renamed from tests/tpos.nim)62
-rw-r--r--tests/misc/tprep.nim38
-rw-r--r--tests/misc/tquicksort.nim23
-rw-r--r--tests/misc/tradix.nim254
-rw-r--r--tests/misc/trfc405.nim112
-rw-r--r--tests/misc/trunner.nim444
-rw-r--r--tests/misc/trunner_special.nim37
-rw-r--r--tests/misc/tsamename.nim15
-rw-r--r--tests/misc/tsamename2.nim4
-rw-r--r--tests/misc/tsemfold.nim27
-rw-r--r--tests/misc/tshadow_magic_type.nim29
-rw-r--r--tests/misc/tsimplesort.nim306
-rw-r--r--tests/misc/tsizeof.nim742
-rw-r--r--tests/misc/tsizeof2.nim17
-rw-r--r--tests/misc/tsizeof3.nim58
-rw-r--r--tests/misc/tsizeof4.nim20
-rw-r--r--tests/misc/tsortdev.nim58
-rw-r--r--tests/misc/tstrace.nim36
-rw-r--r--[-rwxr-xr-x]tests/misc/tstrange.nim (renamed from tests/tstrange.nim)45
-rw-r--r--tests/misc/tstrdesc.nim14
-rw-r--r--[-rwxr-xr-x]tests/misc/tstrdist.nim (renamed from tests/tstrdist.nim)2
-rw-r--r--tests/misc/ttlsemulation.nim76
-rw-r--r--tests/misc/tvarious.nim72
-rw-r--r--tests/misc/tvarious1.nim58
-rw-r--r--[-rwxr-xr-x]tests/misc/tvarnums.nim (renamed from tests/tvarnums.nim)275
-rw-r--r--tests/misc/tvcc.nim9
-rw-r--r--tests/misc/åäö.nim11
-rw-r--r--tests/mmaptest.nim36
-rw-r--r--tests/modules/UpperCased.nim6
-rw-r--r--tests/modules/a/module_name_clashes.nim8
-rw-r--r--tests/modules/a/utils.nim2
-rw-r--r--tests/modules/b/module_name_clashes.nim3
-rw-r--r--tests/modules/b/utils.nim2
-rw-r--r--tests/modules/definitions.nim4
-rw-r--r--tests/modules/m9627/a.nim1
-rw-r--r--tests/modules/m9627/b.nim1
-rw-r--r--tests/modules/mexport2a.nim7
-rw-r--r--tests/modules/mexport2b.nim3
-rw-r--r--tests/modules/mexporta.nim8
-rw-r--r--tests/modules/mexportb.nim7
-rw-r--r--tests/modules/mforwarded_pure_enum.nim3
-rw-r--r--tests/modules/mforwarded_pure_enum2.nim4
-rw-r--r--tests/modules/mimport_in_config.nim2
-rw-r--r--tests/modules/mincludeprefix.nim1
-rw-r--r--tests/modules/mincludetemplate.nim1
-rw-r--r--tests/modules/mmodule_same_proc.nim6
-rw-r--r--tests/modules/mmodule_same_proc_client.nim2
-rw-r--r--[-rwxr-xr-x]tests/modules/mnamspc1.nim (renamed from tests/mnamspc1.nim)4
-rw-r--r--[-rwxr-xr-x]tests/modules/mnamspc2.nim (renamed from tests/mnamspc2.nim)6
-rw-r--r--tests/modules/mnotuniquename.nim1
-rw-r--r--[-rwxr-xr-x]tests/modules/mopaque.nim (renamed from tests/mopaque.nim)12
-rw-r--r--tests/modules/morder_depa.nim5
-rw-r--r--tests/modules/morder_depb.nim1
-rw-r--r--tests/modules/mrange.nim5
-rw-r--r--[-rwxr-xr-x]tests/modules/mrecmod.nim (renamed from tests/mrecmod.nim)2
-rw-r--r--[-rwxr-xr-x]tests/modules/mrecmod2.nim (renamed from tests/mrecmod2.nim)4
-rw-r--r--tests/modules/proxy_module.nim3
-rw-r--r--tests/modules/seq.nim5
-rw-r--r--tests/modules/t8665.nim5
-rw-r--r--tests/modules/t9627.nim7
-rw-r--r--tests/modules/tambig_range.nim13
-rw-r--r--tests/modules/tcanimport.nim19
-rw-r--r--tests/modules/texplicit_system_import.nim9
-rw-r--r--tests/modules/texport.nim13
-rw-r--r--tests/modules/texport2.nim18
-rw-r--r--tests/modules/tfowarded_pure_enum.nim7
-rw-r--r--tests/modules/timport_in_config.nim9
-rw-r--r--tests/modules/timport_in_config.nim.cfg2
-rw-r--r--tests/modules/timportas.nim21
-rw-r--r--tests/modules/timportexcept.nim9
-rw-r--r--tests/modules/tincludeas.nim6
-rw-r--r--tests/modules/tincludeprefix.nim3
-rw-r--r--tests/modules/tincludetemplate.nim5
-rw-r--r--tests/modules/tmismatchedvisibility.nim9
-rw-r--r--tests/modules/tmodule_name_clashes.nim17
-rw-r--r--tests/modules/tmodule_same_proc.nim9
-rw-r--r--tests/modules/tmodulesymtype.nim22
-rw-r--r--tests/modules/tnamspc.nim10
-rw-r--r--tests/modules/tnotuniquename.nim10
-rw-r--r--tests/modules/tnotuniquename2.nim8
-rw-r--r--tests/modules/tnotuniquename_dir/mnotuniquename.nim2
-rw-r--r--[-rwxr-xr-x]tests/modules/topaque.nim (renamed from tests/topaque.nim)27
-rw-r--r--tests/modules/torder_dep.nim10
-rw-r--r--tests/modules/trecinca.nim10
-rw-r--r--tests/modules/trecincb.nim11
-rw-r--r--tests/modules/trecmod.nim8
-rw-r--r--[-rwxr-xr-x]tests/modules/trecmod2.nim (renamed from tests/trecmod2.nim)7
-rw-r--r--tests/modules/treorder.nim47
-rw-r--r--tests/modules/tselfimport.nim8
-rw-r--r--tests/modules/tseq.nim8
-rw-r--r--tests/modules/tstrutils_insert_sep.nim13
-rw-r--r--tests/modules/tuppercased.nim8
-rw-r--r--tests/modules/tutils_ab.nim5
-rw-r--r--tests/msgs/mdeprecated3.nim10
-rw-r--r--tests/msgs/mspellsuggest.nim7
-rw-r--r--tests/msgs/mused2a.nim23
-rw-r--r--tests/msgs/mused2b.nim3
-rw-r--r--tests/msgs/mused2c.nim1
-rw-r--r--tests/msgs/mused3.nim76
-rw-r--r--tests/msgs/mused3a.nim41
-rw-r--r--tests/msgs/mused3b.nim12
-rw-r--r--tests/msgs/tdeprecated1.nim15
-rw-r--r--tests/msgs/tdeprecated2.nim42
-rw-r--r--tests/msgs/tdeprecated3.nim33
-rw-r--r--tests/msgs/tdeprecatedequalhook.nim11
-rw-r--r--tests/msgs/texpandmacro.nim18
-rw-r--r--tests/msgs/thints_off.nim4
-rw-r--r--tests/msgs/tspellsuggest.nim45
-rw-r--r--tests/msgs/tspellsuggest2.nim45
-rw-r--r--tests/msgs/tspellsuggest3.nim21
-rw-r--r--tests/msgs/tused2.nim46
-rw-r--r--tests/msgs/twarningaserror.nim35
-rwxr-xr-xtests/mvarious.nim6
-rw-r--r--tests/navigator/minclude.nim2
-rw-r--r--tests/navigator/tincludefile.nim29
-rw-r--r--tests/navigator/tnav1.nim33
-rw-r--r--tests/newconfig/bar/config.nims0
-rw-r--r--tests/newconfig/bar/mfoo.nim0
-rw-r--r--tests/newconfig/bar/mfoo.nim.cfg0
-rw-r--r--tests/newconfig/bar/mfoo.nims0
-rw-r--r--tests/newconfig/bar/nim.cfg0
-rw-r--r--tests/newconfig/foo2/mfoo2.customext2
-rw-r--r--tests/newconfig/mconfigcheck.nims9
-rw-r--r--tests/newconfig/mymath.nim4
-rw-r--r--tests/newconfig/tfoo.nim13
-rw-r--r--tests/newconfig/tfoo.nims108
-rw-r--r--tests/nimble/nimbleDir/linkedPkgs/pkgA-0.1.0/pkgA.nimble-link2
-rw-r--r--tests/nimble/nimbleDir/linkedPkgs/pkgB-#head/pkgB.nimble-link2
-rw-r--r--tests/nimble/nimbleDir/linkedPkgs/pkgB-0.1.0/pkgB.nimble-link2
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA.nimble0
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA/module.nim1
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB.nimble0
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB/module.nim1
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB.nimble0
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB/module.nim1
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC.nimble0
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC/module.nim1
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC.nimble0
-rw-r--r--tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC/module.nim1
-rw-r--r--tests/nimble/readme.md2
-rw-r--r--tests/nimble/tnimblepath.nim11
-rw-r--r--tests/nimble/tnimblepathdollar.nim7
-rw-r--r--tests/nimble/tnimblepathdollar.nims5
-rw-r--r--tests/nimble/tnimblepathdollar_fault.nim13
-rw-r--r--tests/nimble/tnimblepathdollar_fault.nims5
-rw-r--r--tests/nimble/tnimblepathlink.nim9
-rw-r--r--tests/nimdoc/imp.nim1
-rw-r--r--tests/nimdoc/m13129.nim37
-rw-r--r--tests/nimdoc/readme.md3
-rw-r--r--tests/nimdoc/sub/imp.nim1
-rw-r--r--tests/nimdoc/sub/imp2.nim1
-rw-r--r--tests/nimdoc/sub/mmain.nim8
-rw-r--r--tests/nimdoc/t15916.nim16
-rw-r--r--tests/nimdoc/t17615.nim11
-rw-r--r--tests/nimdoc/trunnableexamples.nim213
-rw-r--r--tests/niminaction/Chapter1/various1.nim45
-rw-r--r--tests/niminaction/Chapter2/explicit_discard.nim7
-rw-r--r--tests/niminaction/Chapter2/no_def_eq.nim16
-rw-r--r--tests/niminaction/Chapter2/no_iterator.nim7
-rw-r--r--tests/niminaction/Chapter2/no_seq_type.nim6
-rw-r--r--tests/niminaction/Chapter2/resultaccept.nim28
-rw-r--r--tests/niminaction/Chapter2/resultreject.nim33
-rw-r--r--tests/niminaction/Chapter2/various2.nim369
-rw-r--r--tests/niminaction/Chapter3/ChatApp/readme.markdown26
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/client.nim58
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/client.nim.cfg1
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/protocol.nim55
-rw-r--r--tests/niminaction/Chapter3/ChatApp/src/server.nim88
-rw-r--r--tests/niminaction/Chapter3/various3.nim99
-rw-r--r--tests/niminaction/Chapter3/various3.nim.cfg1
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency.nim83
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency.nim.cfg1
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim68
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim.cfg1
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/naive.nim33
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim76
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim.cfg1
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/race_condition.nim17
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/race_condition.nim.cfg1
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim38
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim20
-rw-r--r--tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim.cfg1
-rw-r--r--tests/niminaction/Chapter7/Tweeter/Tweeter.nimble14
-rw-r--r--tests/niminaction/Chapter7/Tweeter/public/style.css117
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim11
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/database.nim93
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/tweeter.nim68
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/views/general.nim51
-rw-r--r--tests/niminaction/Chapter7/Tweeter/src/views/user.nim49
-rw-r--r--tests/niminaction/Chapter7/Tweeter/tests/database_test.nim33
-rw-r--r--tests/niminaction/Chapter7/Tweeter/tests/database_test.nims2
-rw-r--r--tests/niminaction/Chapter8/canvas/canvas.nim23
-rw-r--r--tests/niminaction/Chapter8/canvas/canvas_test.nim19
-rw-r--r--tests/niminaction/Chapter8/sdl/sdl.nim38
-rw-r--r--tests/niminaction/Chapter8/sdl/sdl_test.nim41
-rw-r--r--tests/niminaction/Chapter8/sfml/sfml.nim26
-rw-r--r--tests/niminaction/Chapter8/sfml/sfml_test.nim14
-rw-r--r--tests/niminaction/Chapter9/configurator/configurator.nim84
-rw-r--r--tests/notnil/tmust_compile.nim75
-rw-r--r--tests/notnil/tnotnil.nim13
-rw-r--r--tests/notnil/tnotnil1.nim27
-rw-r--r--tests/notnil/tnotnil2.nim24
-rw-r--r--tests/notnil/tnotnil3.nim35
-rw-r--r--tests/notnil/tnotnil4.nim23
-rw-r--r--tests/notnil/tnotnil5.nim28
-rw-r--r--tests/notnil/tnotnil_in_generic.nim28
-rw-r--r--tests/notnil/tnotnil_in_objconstr.nim18
-rw-r--r--tests/notnil/tparse.nim18
-rw-r--r--tests/objects/m19342.c12
-rw-r--r--tests/objects/mobject_default_value.nim15
-rw-r--r--tests/objects/t12753.nim22
-rw-r--r--tests/objects/t17437.nim22
-rw-r--r--tests/objects/t19342.nim18
-rw-r--r--tests/objects/t19342_2.nim18
-rw-r--r--tests/objects/t20972.nim15
-rw-r--r--tests/objects/t22301.nim17
-rw-r--r--tests/objects/t3734.nim17
-rw-r--r--tests/objects/t4318.nim17
-rw-r--r--tests/objects/tdefaultfieldscheck.nim16
-rw-r--r--tests/objects/tdefaultrangetypescheck.nim11
-rw-r--r--tests/objects/tillegal_recursion.nim7
-rw-r--r--tests/objects/tillegal_recursion2.nim6
-rw-r--r--tests/objects/tillegal_recursion3.nim6
-rw-r--r--tests/objects/tobj_asgn_dont_slice.nim25
-rw-r--r--tests/objects/tobjconstr.nim79
-rw-r--r--tests/objects/tobjconstr2.nim57
-rw-r--r--tests/objects/tobjcov.nim24
-rw-r--r--tests/objects/tobject.nim74
-rw-r--r--tests/objects/tobject3.nim95
-rw-r--r--tests/objects/tobject_default_value.nim780
-rw-r--r--tests/objects/tobjects_issues.nim117
-rw-r--r--tests/objects/tobjects_various.nim120
-rw-r--r--tests/objects/tobjpragma.nim53
-rw-r--r--[-rwxr-xr-x]tests/objects/toop1.nim (renamed from tests/toop1.nim)39
-rw-r--r--tests/objects/trequireinit.nim10
-rw-r--r--tests/objects/tunsafenew.nim10
-rw-r--r--tests/objects/tunsafenew2.nim15
-rw-r--r--tests/objects/twhen1.nim89
-rw-r--r--tests/objvariant/t14581.nim25
-rw-r--r--tests/objvariant/tadrdisc.nim20
-rw-r--r--tests/objvariant/tcheckedfield1.nim61
-rw-r--r--tests/objvariant/tconstobjvariant.nim18
-rw-r--r--tests/objvariant/tconstructionorder.nim114
-rw-r--r--tests/objvariant/temptycaseobj.nim12
-rw-r--r--tests/objvariant/tfloatrangeobj.nim14
-rw-r--r--tests/objvariant/tnon_zero_discrim_err.nim14
-rw-r--r--tests/objvariant/treassign.nim58
-rw-r--r--tests/objvariant/trt_discrim.nim198
-rw-r--r--tests/objvariant/trt_discrim_err0.nim17
-rw-r--r--tests/objvariant/trt_discrim_err1.nim17
-rw-r--r--tests/objvariant/trt_discrim_err2.nim14
-rw-r--r--tests/objvariant/trt_discrim_err3.nim17
-rw-r--r--tests/objvariant/tvariantstack.nim77
-rw-r--r--tests/objvariant/tyaoption.nim70
-rw-r--r--tests/openarray/t6163.nim17
-rw-r--r--tests/openarray/t8259.nim7
-rw-r--r--tests/openarray/topena1.nim9
-rw-r--r--tests/openarray/topenarray.nim88
-rw-r--r--tests/openarray/topenarrayrepr.nim13
-rw-r--r--[-rwxr-xr-x]tests/openarray/topenlen.nim (renamed from tests/topenlen.nim)5
-rw-r--r--tests/openarray/tptrarrayderef.nim84
-rw-r--r--tests/openarray/tuncheckedarray.nim19
-rw-r--r--tests/options/tnimbasepattern.nim26
-rw-r--r--tests/osproc/passenv.nim32
-rw-r--r--tests/osproc/tclose.nim24
-rw-r--r--tests/osproc/texecps.nim30
-rw-r--r--tests/osproc/texitsignal.nim39
-rw-r--r--tests/osproc/tnoexe.nim27
-rw-r--r--tests/osproc/treadlines.nim23
-rw-r--r--tests/osproc/twaitforexit.nim38
-rw-r--r--tests/osproc/tworkingdir.nim21
-rw-r--r--tests/overflow/tdistinct_range.nim6
-rw-r--r--tests/overflow/toverflow.nim82
-rw-r--r--tests/overflow/toverflow2.nim7
-rw-r--r--tests/overflow/toverflow_reorder.nim84
-rw-r--r--[-rwxr-xr-x]tests/overflow/tovfint.nim (renamed from tests/tovfint.nim)37
-rw-r--r--tests/overflow/trangechecks.nim48
-rw-r--r--tests/overflow/twronginference.nim10
-rw-r--r--tests/overload/importA.nim5
-rw-r--r--tests/overload/importB.nim15
-rw-r--r--tests/overload/issue22142/tfail_implicit_ambiguous.nim10
-rw-r--r--tests/overload/issue22142/tfail_nested_pointers.nim12
-rw-r--r--tests/overload/issue22142/tfail_object_is_generic.nim16
-rw-r--r--tests/overload/issue22142/tfail_typeclass_var_invar.nim9
-rw-r--r--tests/overload/issue22142/tissue22142_shouldpass.nim68
-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/t23249.nim17
-rw-r--r--tests/overload/t23755.nim62
-rw-r--r--tests/overload/t7416.nim9
-rw-r--r--tests/overload/t8829.nim18
-rw-r--r--tests/overload/tconverter_to_string.nim22
-rw-r--r--tests/overload/tgenericalias.nim13
-rw-r--r--tests/overload/tissue966.nim12
-rw-r--r--tests/overload/tnamedparamoverloading.nim14
-rw-r--r--tests/overload/tor_isnt_better.nim41
-rw-r--r--[-rwxr-xr-x]tests/overload/toverl.nim (renamed from tests/toverl.nim)17
-rw-r--r--tests/overload/toverl4.nim101
-rw-r--r--tests/overload/toverload_issues.nim200
-rw-r--r--tests/overload/toverload_various.nim568
-rw-r--r--tests/overload/tparam_forwarding.nim53
-rw-r--r--tests/overload/tproc_types_dont_like_subtypes.nim20
-rw-r--r--tests/overload/tspec.nim118
-rw-r--r--tests/overload/tstatic_with_converter.nim48
-rw-r--r--tests/overload/tsystemcmp.nim24
-rw-r--r--tests/overload/tuntypedarg.nim19
-rw-r--r--tests/overload/tvartypeclass.nim11
-rw-r--r--tests/overload/tvaruintconv.nim207
-rw-r--r--tests/package/stdlib/stdlib.nimble0
-rw-r--r--tests/package/stdlib/system.nim2
-rw-r--r--tests/package/tstdlib_name_not_special.nim3
-rw-r--r--tests/package_level_objects/definefoo.nim3
-rw-r--r--tests/package_level_objects/mypackage.nimble0
-rw-r--r--tests/package_level_objects/tusefoo.nim16
-rw-r--r--tests/package_level_objects/tusefoo2.nim19
-rw-r--r--tests/parallel/nim.cfg2
-rw-r--r--tests/parallel/t10913.nim20
-rw-r--r--tests/parallel/t5000.nim25
-rw-r--r--tests/parallel/t7535.nim11
-rw-r--r--tests/parallel/t9691.nim9
-rw-r--r--tests/parallel/tarray_of_channels.nim39
-rw-r--r--tests/parallel/tblocking_channel.nim39
-rw-r--r--tests/parallel/tconvexhull.nim60
-rw-r--r--tests/parallel/tdeepcopy.nim55
-rw-r--r--tests/parallel/tdeepcopy2.nim38
-rw-r--r--tests/parallel/tdisjoint_slice1.nim51
-rw-r--r--tests/parallel/tflowvar.nim38
-rw-r--r--tests/parallel/tforstmt.nim25
-rw-r--r--tests/parallel/tgc_unsafe.nim32
-rw-r--r--tests/parallel/tgc_unsafe2.nim38
-rw-r--r--tests/parallel/tguard1.nim41
-rw-r--r--tests/parallel/tguard2.nim27
-rw-r--r--tests/parallel/tinvalid_array_bounds.nim26
-rw-r--r--tests/parallel/tinvalid_counter_usage.nim26
-rw-r--r--tests/parallel/tlet_spawn.nim28
-rw-r--r--tests/parallel/tmissing_deepcopy.nim42
-rw-r--r--tests/parallel/tnon_disjoint_slice1.nim26
-rw-r--r--tests/parallel/tparfind.nim29
-rw-r--r--tests/parallel/tpi.nim27
-rw-r--r--tests/parallel/tptr_to_ref.nim71
-rw-r--r--tests/parallel/treadafterwrite.nim31
-rw-r--r--tests/parallel/tsendtwice.nim65
-rw-r--r--tests/parallel/tsimple_array_checks.nim75
-rw-r--r--tests/parallel/tsysspawn.nim64
-rw-r--r--tests/parallel/tsysspawnbadarg.nim9
-rw-r--r--tests/parallel/tuseafterdef.nim34
-rw-r--r--tests/parallel/twaitany.nim34
-rw-r--r--tests/parser/t12274.nim13
-rw-r--r--tests/parser/t15667.nim61
-rw-r--r--tests/parser/t19430.nim3
-rw-r--r--tests/parser/t19662.nim6
-rw-r--r--tests/parser/t20922.nim35
-rw-r--r--tests/parser/tbinarynotindented.nim3
-rw-r--r--tests/parser/tbinarynotsameline.nim10
-rw-r--r--tests/parser/tcommand_as_expr.nim47
-rw-r--r--tests/parser/tcommandequals.nim17
-rw-r--r--tests/parser/tcommandindent.nim16
-rw-r--r--tests/parser/tdo.nim94
-rw-r--r--tests/parser/tdoc_comments.nim75
-rw-r--r--tests/parser/tdomulttest.nim17
-rw-r--r--tests/parser/tdotlikeoperators.nim30
-rw-r--r--tests/parser/tdoublenotnil.nim3
-rw-r--r--tests/parser/tifexprs.nim12
-rw-r--r--tests/parser/tifextracolon.nim8
-rw-r--r--tests/parser/tinvcolonlocation1.nim12
-rw-r--r--tests/parser/tinvcolonlocation2.nim15
-rw-r--r--tests/parser/tinvcolonlocation3.nim12
-rw-r--r--tests/parser/tinvifstmt.nim12
-rw-r--r--[-rwxr-xr-x]tests/parser/tinvwhen.nim (renamed from tests/tinvwhen.nim)21
-rw-r--r--tests/parser/tletcolon.nim75
-rw-r--r--tests/parser/tmultiline_comments.nim64
-rw-r--r--tests/parser/toprprec.nim37
-rw-r--r--tests/parser/tpostexprblocks.nim668
-rw-r--r--tests/parser/tprecedence.nim63
-rw-r--r--tests/parser/tprocexprasstmt.nim14
-rw-r--r--tests/parser/tproctype_pragmas.nim19
-rw-r--r--tests/parser/tstatementoperators.nim12
-rw-r--r--tests/parser/tstmtlists.nim180
-rw-r--r--tests/parser/ttry.nim27
-rw-r--r--tests/parser/ttupleunpack.nim94
-rw-r--r--tests/parser/ttypeclasses.nim46
-rw-r--r--tests/parser/ttypecommandcomma.nim9
-rw-r--r--tests/parser/ttypecommandindent1.nim9
-rw-r--r--tests/parser/ttypecommandindent2.nim11
-rw-r--r--tests/parser/ttypecommandindent3.nim11
-rw-r--r--tests/parser/ttypeexprobject.nim10
-rw-r--r--tests/parser/ttypeexprs.nim25
-rw-r--r--tests/parser/ttypemodifiers.nim526
-rw-r--r--tests/parser/ttypeof.nim26
-rw-r--r--tests/parser/ttypesectioncalls.nim328
-rw-r--r--tests/parser/twhen_in_enum.nim11
-rw-r--r--tests/parser/twrongcmdsyntax.nim6
-rw-r--r--tests/pragmas/cfunction.c4
-rw-r--r--tests/pragmas/custom_pragma.nim5
-rw-r--r--tests/pragmas/foobar.nim3
-rw-r--r--tests/pragmas/monoff1.nim1
-rw-r--r--tests/pragmas/mpushexperimental.nim30
-rw-r--r--tests/pragmas/mqualifiedmacro.nim10
-rw-r--r--tests/pragmas/t12558.nim15
-rw-r--r--tests/pragmas/t12640.nim26
-rw-r--r--tests/pragmas/t13306.nim10
-rw-r--r--tests/pragmas/t22713.nim12
-rw-r--r--tests/pragmas/t4384.nim3
-rw-r--r--tests/pragmas/t5149.nim12
-rw-r--r--tests/pragmas/t6448.nim17
-rw-r--r--tests/pragmas/t8741.nim29
-rw-r--r--tests/pragmas/tbitsize.nim22
-rw-r--r--tests/pragmas/tcompile_missing_file.nim5
-rw-r--r--tests/pragmas/tcompile_pragma.nim10
-rw-r--r--tests/pragmas/tcustom_pragma.nim540
-rw-r--r--tests/pragmas/tdeprecated.nim10
-rw-r--r--tests/pragmas/thintprocessing.nim18
-rw-r--r--tests/pragmas/tinvalid_user_pragma.nim9
-rw-r--r--tests/pragmas/tinvalidcustompragma.nim23
-rw-r--r--tests/pragmas/tlocks.nim12
-rw-r--r--tests/pragmas/tnoreturn.nim27
-rw-r--r--tests/pragmas/tonoff1.nim8
-rw-r--r--tests/pragmas/tonoff2.nim14
-rw-r--r--tests/pragmas/tpragmas_misc.nim75
-rw-r--r--tests/pragmas/tpragmas_reorder.nim19
-rw-r--r--tests/pragmas/tpush.nim144
-rw-r--r--tests/pragmas/tpushexperimental.nim13
-rw-r--r--tests/pragmas/tpushnotes.nim13
-rw-r--r--tests/pragmas/tqualifiedmacro.nim14
-rw-r--r--tests/pragmas/treorder.nim75
-rw-r--r--tests/pragmas/tsym_as_pragma.nim8
-rw-r--r--tests/pragmas/ttypedef_macro.nim66
-rw-r--r--tests/pragmas/tused.nim43
-rw-r--r--tests/pragmas/tuserpragma.nim7
-rw-r--r--tests/pragmas/tuserpragma2.nim12
-rw-r--r--tests/pragmas/tuserpragmaargs.nim5
-rw-r--r--tests/pragmas/tvar_macro.nim128
-rw-r--r--tests/pragmas/twarning_off.nim15
-rw-r--r--tests/pragmas/warn_module.nim7
-rw-r--r--tests/proc/mdefaultprocparam.nim5
-rw-r--r--tests/proc/t15949.nim16
-rw-r--r--tests/proc/t17157.nim6
-rw-r--r--tests/proc/t19795.nim19
-rw-r--r--tests/proc/t23874.nim26
-rw-r--r--tests/proc/tcolonisproc.nim19
-rw-r--r--tests/proc/tdefaultprocparam.nim90
-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/tfunc_type.nim14
-rw-r--r--tests/proc/tgenericdefaultparam.nim98
-rw-r--r--tests/proc/tillegalreturntype.nim21
-rw-r--r--tests/proc/tinferlambdareturn.nim36
-rw-r--r--tests/proc/tlambdadonotation.nim78
-rw-r--r--tests/proc/tlambdapragma.nim7
-rw-r--r--tests/proc/tnamedparams.nim12
-rw-r--r--tests/proc/tnamedparams2.nim15
-rw-r--r--tests/proc/tnamedparams3.nim10
-rw-r--r--tests/proc/tparamsindefault.nim120
-rw-r--r--tests/proc/tproc.nim31
-rw-r--r--tests/proc/tprocredef.nim8
-rw-r--r--tests/proc/tprocvar.nim39
-rw-r--r--tests/proc/tprocvarmismatch.nim18
-rw-r--r--tests/proc/tstaticsignature.nim268
-rw-r--r--tests/proc/tunderscoreparam.nim122
-rw-r--r--tests/proc/twrongdefaultvalue.nim25
-rw-r--r--tests/proc/typed.nim7
-rw-r--r--tests/proc/untyped.nim15
-rw-r--r--tests/range/compilehelpers.nim5
-rw-r--r--tests/range/t19678.nim17
-rw-r--r--tests/range/tcompiletime_range_checks.nim52
-rw-r--r--tests/range/tenums.nim33
-rw-r--r--tests/range/texplicitvarconv.nim13
-rw-r--r--tests/range/toutofrangevarconv.nim14
-rw-r--r--tests/range/trange.nim156
-rw-r--r--tests/range/tsubrange.nim20
-rw-r--r--tests/range/tsubrange2.nim15
-rw-r--r--tests/range/tsubrange3.nim17
-rw-r--r--tests/readme.md39
-rwxr-xr-xtests/readme.txt24
-rw-r--r--tests/realtimeGC/shared.nim59
-rw-r--r--tests/realtimeGC/tmain.nim62
-rw-r--r--[-rwxr-xr-x]tests/rectest.nim12
-rw-r--r--tests/refc/tsinkbug.nim26
-rw-r--r--tests/sandwich/generic_library.nim6
-rw-r--r--tests/sandwich/helper_module.nim3
-rw-r--r--tests/sandwich/module_using_generic_library.nim12
-rw-r--r--tests/sandwich/tmain.nim9
-rwxr-xr-xtests/sdltest.nim26
-rw-r--r--tests/sets/m17385.nim11
-rw-r--r--tests/sets/t13764.nim6
-rw-r--r--tests/sets/t15435.nim29
-rw-r--r--tests/sets/t17385.nim4
-rw-r--r--tests/sets/t20997.nim18
-rw-r--r--tests/sets/t2669.nim6
-rw-r--r--tests/sets/t5792.nim17
-rw-r--r--tests/sets/thugeset.nim10
-rw-r--r--[-rwxr-xr-x]tests/sets/tnewsets.nim (renamed from tests/tnewsets.nim)12
-rw-r--r--tests/sets/trangeincompatible.nim32
-rw-r--r--tests/sets/tsets.nim133
-rw-r--r--tests/sets/tsets_various.nim286
-rw-r--r--tests/sets/twrongenumrange.nim50
-rw-r--r--tests/showoff/tdrdobbs_examples.nim134
-rw-r--r--tests/showoff/tformatopt.nim57
-rw-r--r--tests/showoff/tgenericmacrotypes.nim55
-rw-r--r--tests/showoff/thello2.nim11
-rw-r--r--tests/showoff/thtml1.nim11
-rw-r--r--tests/showoff/thtml2.nim37
-rw-r--r--tests/showoff/tonce.nim22
-rw-r--r--tests/showoff/tquasiquote.nim14
-rw-r--r--tests/specialops/tcallops.nim49
-rw-r--r--tests/specialops/tcallprecedence.nim44
-rw-r--r--tests/specialops/tdotops.nim97
-rw-r--r--tests/specialops/terrmsgs.nim76
-rw-r--r--tests/specialops/tnewseq.nim22
-rw-r--r--tests/specialops/tsetter.nim10
-rw-r--r--tests/statictypes/t20148.nim8
-rw-r--r--tests/statictypes/t3784.nim20
-rw-r--r--tests/statictypes/t5780.nim3
-rw-r--r--tests/statictypes/t9255.nim13
-rw-r--r--tests/statictypes/tcryptodigest.nim44
-rw-r--r--tests/statictypes/texplicitprocparams.nim19
-rw-r--r--tests/statictypes/tgenericcomputedrange.nim125
-rw-r--r--tests/statictypes/tpassthruarith.nim50
-rw-r--r--tests/statictypes/tstackmatrix.nim29
-rw-r--r--tests/statictypes/tstatic.nim56
-rw-r--r--tests/statictypes/tstaticgenericparam.nim24
-rw-r--r--tests/statictypes/tstaticimportcpp.nim63
-rw-r--r--tests/statictypes/tstaticprocparams.nim16
-rw-r--r--tests/statictypes/tstatictypes.nim459
-rw-r--r--[-rwxr-xr-x]tests/stckovfl.nim8
-rw-r--r--tests/stdlib/concurrency/atomicSample.nim9
-rw-r--r--tests/stdlib/concurrency/tatomic_import.nim11
-rw-r--r--tests/stdlib/concurrency/tatomics.nim637
-rw-r--r--tests/stdlib/concurrency/tatomics_size.nim21
-rw-r--r--tests/stdlib/config.nims5
-rw-r--r--tests/stdlib/genericstrformat.nim16
-rw-r--r--tests/stdlib/mgenast.nim57
-rw-r--r--tests/stdlib/mimportutils.nim38
-rw-r--r--tests/stdlib/mintsets.nim11
-rw-r--r--tests/stdlib/mjsonexternproc.nim10
-rw-r--r--tests/stdlib/mstackframes.nim38
-rw-r--r--tests/stdlib/nre/captures.nim64
-rw-r--r--tests/stdlib/nre/escape.nim7
-rw-r--r--tests/stdlib/nre/find.nim41
-rw-r--r--tests/stdlib/nre/init.nim36
-rw-r--r--tests/stdlib/nre/match.nim18
-rw-r--r--tests/stdlib/nre/misc.nim16
-rw-r--r--tests/stdlib/nre/optional_nonstrict.nim3
-rw-r--r--tests/stdlib/nre/replace.nim22
-rw-r--r--tests/stdlib/nre/split.nim53
-rw-r--r--tests/stdlib/osproctest.nim8
-rw-r--r--tests/stdlib/somesql.sql298
-rw-r--r--tests/stdlib/t10231.nim16
-rw-r--r--tests/stdlib/t14139.nim10
-rw-r--r--tests/stdlib/t15663.nim9
-rw-r--r--tests/stdlib/t19304.nim7
-rw-r--r--tests/stdlib/t20023.nim10
-rw-r--r--tests/stdlib/t21251.nim6
-rw-r--r--tests/stdlib/t21406.nim7
-rw-r--r--tests/stdlib/t21564.nim32
-rw-r--r--tests/stdlib/t7686.nim10
-rw-r--r--tests/stdlib/t8925.nim16
-rw-r--r--tests/stdlib/t9754.nim6
-rw-r--r--tests/stdlib/talgorithm.nim275
-rw-r--r--tests/stdlib/tarithmetics.nim50
-rw-r--r--tests/stdlib/tasynchttpserver.nim121
-rw-r--r--tests/stdlib/tasynchttpserver_transferencoding.nim91
-rw-r--r--tests/stdlib/tbase64.nim63
-rw-r--r--tests/stdlib/tbitops.nim351
-rw-r--r--tests/stdlib/tbitops.nim.cfg1
-rw-r--r--tests/stdlib/tbitops_utils.nim19
-rw-r--r--tests/stdlib/tcasts.nim26
-rw-r--r--tests/stdlib/tcgi.nim31
-rw-r--r--tests/stdlib/tclosures.nim47
-rw-r--r--tests/stdlib/tcmdline.nim13
-rw-r--r--tests/stdlib/tcomplex.nim115
-rw-r--r--tests/stdlib/tcookies.nim22
-rw-r--r--tests/stdlib/tcritbits.nim89
-rw-r--r--tests/stdlib/tcstring.nim93
-rw-r--r--tests/stdlib/tcstrutils.nim39
-rw-r--r--tests/stdlib/tdb.nim0
-rw-r--r--tests/stdlib/tdb.nims1
-rw-r--r--tests/stdlib/tdb_mysql.nim0
-rw-r--r--tests/stdlib/tdecls.nim50
-rw-r--r--tests/stdlib/tdecode_helpers.nim27
-rw-r--r--tests/stdlib/tdeques.nim243
-rw-r--r--tests/stdlib/tdiff.nim75
-rw-r--r--tests/stdlib/tdistros_detect.nim16
-rw-r--r--tests/stdlib/tdochelpers.nim221
-rw-r--r--tests/stdlib/teditdistance.nim45
-rw-r--r--tests/stdlib/tencodings.nim107
-rw-r--r--tests/stdlib/tenumerate.nim24
-rw-r--r--tests/stdlib/tenumutils.nim49
-rw-r--r--tests/stdlib/tenvvars.nim162
-rw-r--r--tests/stdlib/texitprocs.nim22
-rw-r--r--tests/stdlib/tfdleak.nim152
-rw-r--r--tests/stdlib/tfdleak_multiple.nim31
-rw-r--r--tests/stdlib/tfenv.nim8
-rw-r--r--tests/stdlib/tfilesanddirs.nim36
-rw-r--r--tests/stdlib/tfrexp1.nim55
-rw-r--r--tests/stdlib/tgenast.nim274
-rw-r--r--tests/stdlib/tgetaddrinfo.nim38
-rw-r--r--tests/stdlib/tgetfileinfo.nim164
-rw-r--r--tests/stdlib/tgetprotobyname.nim19
-rw-r--r--tests/stdlib/tglobs.nim25
-rw-r--r--tests/stdlib/thashes.nim242
-rw-r--r--tests/stdlib/theapqueue.nim106
-rw-r--r--tests/stdlib/thighlite.nim45
-rw-r--r--tests/stdlib/thtmlparser.nim159
-rw-r--r--tests/stdlib/thttpclient.nim187
-rw-r--r--tests/stdlib/thttpclient_ssl.nim150
-rw-r--r--tests/stdlib/thttpclient_ssl_cert.pem29
-rw-r--r--tests/stdlib/thttpclient_ssl_key.pem52
-rw-r--r--tests/stdlib/thttpclient_standalone.nim59
-rw-r--r--tests/stdlib/thttpcore.nim103
-rw-r--r--tests/stdlib/timportutils.nim151
-rw-r--r--tests/stdlib/tintsets.nim6
-rw-r--r--tests/stdlib/tio.nim60
-rw-r--r--tests/stdlib/tisolation.nim135
-rw-r--r--tests/stdlib/tjsbigints.nim46
-rw-r--r--tests/stdlib/tjson.nim382
-rw-r--r--tests/stdlib/tjsonexternproc.nim11
-rw-r--r--tests/stdlib/tjsonmacro.nim650
-rw-r--r--tests/stdlib/tjsonmacro_reject.nim18
-rw-r--r--tests/stdlib/tjsontestsuite.nim388
-rw-r--r--tests/stdlib/tjsonutils.nim476
-rw-r--r--tests/stdlib/tlists.nim277
-rw-r--r--tests/stdlib/tlocks.nim11
-rw-r--r--tests/stdlib/tlwip.nim30
-rw-r--r--tests/stdlib/tmacros.nim349
-rw-r--r--tests/stdlib/tmarshal.nim233
-rw-r--r--tests/stdlib/tmarshalsegfault.nim54
-rw-r--r--tests/stdlib/tmath.nim473
-rw-r--r--tests/stdlib/tmemfiles1.nim11
-rw-r--r--tests/stdlib/tmemfiles2.nim43
-rw-r--r--tests/stdlib/tmemlines.nim9
-rw-r--r--tests/stdlib/tmemlinesBuf.nim9
-rw-r--r--tests/stdlib/tmemmapstreams.nim55
-rw-r--r--tests/stdlib/tmemslices.nim12
-rw-r--r--tests/stdlib/tmersenne.nim13
-rw-r--r--tests/stdlib/tmget.nim158
-rw-r--r--tests/stdlib/tmimetypes.nim28
-rw-r--r--tests/stdlib/tmisc_issues.nim39
-rw-r--r--tests/stdlib/tmitems.nim164
-rw-r--r--tests/stdlib/tmonotimes.nim22
-rw-r--r--tests/stdlib/tnativesockets.nim30
-rw-r--r--tests/stdlib/tnet.nim130
-rw-r--r--tests/stdlib/tnet_ll.nim52
-rw-r--r--tests/stdlib/tnetbind.nim25
-rw-r--r--tests/stdlib/tnetconnect.nim30
-rw-r--r--tests/stdlib/tnetdial.nim62
-rw-r--r--tests/stdlib/tnre.nim16
-rw-r--r--tests/stdlib/tntpath.nim50
-rw-r--r--tests/stdlib/tobjectdollar.nim14
-rw-r--r--tests/stdlib/toids.nim15
-rw-r--r--tests/stdlib/topenssl.nim46
-rw-r--r--tests/stdlib/toptions.nim207
-rw-r--r--tests/stdlib/tos.nim875
-rw-r--r--tests/stdlib/tos_unc.nim11
-rw-r--r--tests/stdlib/tosenv.nim163
-rw-r--r--tests/stdlib/toserrors.nim9
-rw-r--r--tests/stdlib/tosproc.nim316
-rw-r--r--tests/stdlib/tosprocterminate.nim44
-rw-r--r--tests/stdlib/tpackedsets.nim265
-rw-r--r--tests/stdlib/tparsecfg.nim132
-rw-r--r--tests/stdlib/tparsecsv.nim36
-rw-r--r--tests/stdlib/tparseipv6.nim226
-rw-r--r--tests/stdlib/tparsesql.nim245
-rw-r--r--tests/stdlib/tparseuints.nim11
-rw-r--r--tests/stdlib/tparseutils.nim112
-rw-r--r--tests/stdlib/tparsopt.nim35
-rw-r--r--tests/stdlib/tpathnorm.nim36
-rw-r--r--tests/stdlib/tpaths.nim238
-rw-r--r--tests/stdlib/tpegs.nim344
-rw-r--r--tests/stdlib/tposix.nim88
-rw-r--r--tests/stdlib/tprelude.nim16
-rw-r--r--tests/stdlib/trandom.nim310
-rw-r--r--tests/stdlib/trat_float.nim9
-rw-r--r--tests/stdlib/trat_init.nim14
-rw-r--r--tests/stdlib/trationals.nim117
-rw-r--r--tests/stdlib/tre.nim122
-rw-r--r--tests/stdlib/treadln.nim23
-rw-r--r--tests/stdlib/tregex.nim29
-rw-r--r--tests/stdlib/tregistry.nim16
-rw-r--r--tests/stdlib/trepr.nim328
-rw-r--r--tests/stdlib/trlocks.nim14
-rw-r--r--tests/stdlib/tropes.nim104
-rw-r--r--tests/stdlib/trst.nim1994
-rw-r--r--tests/stdlib/trstgen.nim1692
-rw-r--r--tests/stdlib/tsequtils.nim547
-rw-r--r--tests/stdlib/tsetutils.nim49
-rw-r--r--tests/stdlib/tsharedlist.nim49
-rw-r--r--tests/stdlib/tsharedtable.nim90
-rw-r--r--tests/stdlib/tsince.nim32
-rw-r--r--tests/stdlib/tsocketstreams.nim65
-rw-r--r--tests/stdlib/tsortcall.nim69
-rw-r--r--tests/stdlib/tsqlitebindatas.nim0
-rw-r--r--tests/stdlib/tsqlparser.nim13
-rw-r--r--tests/stdlib/tssl.nim138
-rw-r--r--tests/stdlib/tssl.nims5
-rw-r--r--tests/stdlib/tstackframes.nim34
-rw-r--r--tests/stdlib/tstaticos.nim8
-rw-r--r--tests/stdlib/tstats.nim61
-rw-r--r--tests/stdlib/tstdlib_issues.nim110
-rw-r--r--tests/stdlib/tstdlib_various.nim240
-rw-r--r--tests/stdlib/tstrbasics.nim103
-rw-r--r--tests/stdlib/tstreams.nim107
-rw-r--r--tests/stdlib/tstrformat.nim590
-rw-r--r--tests/stdlib/tstrformatlineinfo.nim8
-rw-r--r--tests/stdlib/tstrimpl.nim12
-rw-r--r--tests/stdlib/tstring.nim124
-rw-r--r--tests/stdlib/tstrmiscs.nim27
-rw-r--r--tests/stdlib/tstrscans.nim288
-rw-r--r--[-rwxr-xr-x]tests/stdlib/tstrset.nim (renamed from tests/tstrset.nim)28
-rw-r--r--tests/stdlib/tstrtabs.nim117
-rw-r--r--tests/stdlib/tstrtabs.nims5
-rw-r--r--tests/stdlib/tstrtabs2.nim32
-rw-r--r--tests/stdlib/tstrutils.nim913
-rw-r--r--tests/stdlib/tsugar.nim310
-rw-r--r--tests/stdlib/tsums.nim27
-rw-r--r--tests/stdlib/tsysrand.nim34
-rw-r--r--tests/stdlib/tsystem.nim200
-rw-r--r--tests/stdlib/ttables.nim316
-rw-r--r--tests/stdlib/ttasks.nim561
-rw-r--r--tests/stdlib/ttempfiles.nim51
-rw-r--r--tests/stdlib/tterminal.nim7
-rw-r--r--tests/stdlib/tterminal_12759.nim11
-rw-r--r--tests/stdlib/tterminal_15874.nim8
-rw-r--r--tests/stdlib/ttestutils.nim40
-rw-r--r--tests/stdlib/tthreadpool.nim14
-rw-r--r--tests/stdlib/ttimes.nim784
-rw-r--r--tests/stdlib/ttypeinfo.nim93
-rw-r--r--tests/stdlib/ttypeinfo.nims1
-rw-r--r--tests/stdlib/ttypetraits.nim94
-rw-r--r--tests/stdlib/tunicode.nim228
-rw-r--r--tests/stdlib/tunidecode.nim13
-rw-r--r--tests/stdlib/tunittest.nim194
-rw-r--r--tests/stdlib/tunittest_error.nim22
-rw-r--r--tests/stdlib/tunittestexceptiontype.nim10
-rw-r--r--tests/stdlib/tunittestpass.nim20
-rw-r--r--tests/stdlib/tunittesttemplate.nim25
-rw-r--r--tests/stdlib/tunixsocket.nim35
-rw-r--r--tests/stdlib/turi.nim323
-rw-r--r--tests/stdlib/tuserlocks.nim21
-rw-r--r--tests/stdlib/tvarargs.nim18
-rw-r--r--tests/stdlib/tvarints.nim73
-rw-r--r--tests/stdlib/tvmutils.nim31
-rw-r--r--tests/stdlib/tvolatile.nim15
-rw-r--r--tests/stdlib/twchartoutf8.nim112
-rw-r--r--tests/stdlib/twith.nim44
-rw-r--r--tests/stdlib/twordwrap.nim48
-rw-r--r--tests/stdlib/twrapnils.nim224
-rw-r--r--tests/stdlib/twrongstattype.nim14
-rw-r--r--tests/stdlib/txmltree.nim120
-rw-r--r--tests/stdlib/tyield.nim258
-rw-r--r--tests/stdlib/unixsockettest.nim26
-rw-r--r--tests/stdlib/uselocks.nim16
-rw-r--r--tests/stmt/tforloop_tuple_multiple_underscore.nim10
-rw-r--r--tests/stmt/tforloop_tuple_underscore.nim16
-rw-r--r--tests/stmt/tforloop_underscore.nim6
-rw-r--r--tests/stmt/tgenericsunderscore.nim4
-rw-r--r--tests/stmt/tmiscunderscore.nim15
-rw-r--r--tests/strictnotnil/tnilcheck.nim381
-rw-r--r--tests/strictnotnil/tnilcheck_no_warnings.nim182
-rw-r--r--tests/stylecheck/fileinfo.nim2
-rw-r--r--tests/stylecheck/foreign_package/foreign_package.nim1
-rw-r--r--tests/stylecheck/foreign_package/foreign_package.nimble2
-rw-r--r--tests/stylecheck/t20397.nim4
-rw-r--r--tests/stylecheck/t20397_1.nim8
-rw-r--r--tests/stylecheck/t20397_2.nim7
-rw-r--r--tests/stylecheck/taccept.nim22
-rw-r--r--tests/stylecheck/tforeign_package.nim16
-rw-r--r--tests/stylecheck/thint.nim43
-rw-r--r--tests/stylecheck/treject.nim17
-rw-r--r--tests/stylecheck/tusages.nim22
-rw-r--r--tests/system/helpers/readall_echo.nim2
-rw-r--r--tests/system/t10307.nim24
-rw-r--r--tests/system/t20938.nim12
-rw-r--r--tests/system/t7894.nim23
-rw-r--r--tests/system/talloc.nim59
-rw-r--r--tests/system/talloc2.nim46
-rw-r--r--tests/system/tatomics1.nim9
-rw-r--r--tests/system/tcomparisons.nim51
-rw-r--r--tests/system/tconcat.nim11
-rw-r--r--tests/system/tdeepcopy.nim95
-rw-r--r--tests/system/tdollars.nim199
-rw-r--r--tests/system/techo_unicode.nim41
-rw-r--r--tests/system/temptyecho.nim6
-rw-r--r--tests/system/tensuremove.nim131
-rw-r--r--tests/system/tensuremove1.nim16
-rw-r--r--tests/system/tensuremove2.nim15
-rw-r--r--tests/system/tensuremove3.nim28
-rw-r--r--tests/system/tenum_array_repr.nim23
-rw-r--r--tests/system/tfielditerator.nim126
-rw-r--r--tests/system/tfields.nim108
-rw-r--r--tests/system/tgcnone.nim7
-rw-r--r--tests/system/tgcregions.nim6
-rw-r--r--tests/system/tgogc.nim7
-rw-r--r--tests/system/timmutableinc.nim8
-rw-r--r--[-rwxr-xr-x]tests/system/tinvalidnot.nim (renamed from tests/tnot.nim)14
-rw-r--r--tests/system/tio.nim55
-rw-r--r--tests/system/tlocals.nim76
-rw-r--r--tests/system/tlowhigh.nim32
-rw-r--r--tests/system/tmagics.nim62
-rw-r--r--tests/system/tmemory.nim16
-rw-r--r--[-rwxr-xr-x]tests/system/tnew.nim (renamed from tests/tnew.nim)110
-rw-r--r--tests/system/tnewderef.nim11
-rw-r--r--tests/system/tnewstring_uninitialized.nim11
-rw-r--r--tests/system/tnilconcats.nim33
-rw-r--r--tests/system/tnim_stacktrace_override.nim18
-rw-r--r--tests/system/tostring.nim125
-rw-r--r--tests/system/tparams.nim22
-rw-r--r--tests/system/trealloc.nim23
-rw-r--r--tests/system/trefs.nim15
-rw-r--r--tests/system/tsigexitcode.nim23
-rw-r--r--tests/system/tslices.nim65
-rw-r--r--tests/system/tslimsystem.nim6
-rw-r--r--tests/system/tstatic.nim58
-rw-r--r--tests/system/tstatic_callable.nim12
-rw-r--r--tests/system/tstatic_callable_error.nim14
-rw-r--r--tests/system/tsystem_misc.nim227
-rw-r--r--tests/system/tuse_version16.nim49
-rw-r--r--tests/system/tvarargslen.nim60
-rwxr-xr-xtests/tambsym3.nim8
-rwxr-xr-xtests/tarray.nim27
-rwxr-xr-xtests/tarray2.nim18
-rwxr-xr-xtests/tarrindx.nim13
-rwxr-xr-xtests/tassert.nim16
-rwxr-xr-xtests/tassign.nim31
-rwxr-xr-xtests/tcasestm.nim32
-rwxr-xr-xtests/tclosure.nim26
-rwxr-xr-xtests/tcmdline.nim14
-rwxr-xr-xtests/tcopy.nim19
-rwxr-xr-xtests/tcurrncy.nim32
-rwxr-xr-xtests/tdialogs.nim17
-rwxr-xr-xtests/techo.nim3
-rw-r--r--tests/template/annotate.nim113
-rw-r--r--tests/template/i2416.nim1
-rw-r--r--tests/template/m1027a.nim1
-rw-r--r--tests/template/m1027b.nim1
-rw-r--r--tests/template/m19277_1.nim2
-rw-r--r--tests/template/m19277_2.nim2
-rw-r--r--tests/template/mcan_access_hidden_field.nim8
-rw-r--r--tests/template/mdotcall.nim82
-rw-r--r--tests/template/mdotcall2.nim7
-rw-r--r--tests/template/mgensym_generic_cross_module.nim14
-rw-r--r--tests/template/mlt.nim3
-rw-r--r--tests/template/mqualifiedtype1.nim2
-rw-r--r--tests/template/mqualifiedtype2.nim2
-rw-r--r--tests/template/mtempl5.nim24
-rw-r--r--tests/template/otests.nim219
-rw-r--r--[-rwxr-xr-x]tests/template/sunset.nimf (renamed from tests/sunset.tmpl)3
-rw-r--r--tests/template/t1027.nim22
-rw-r--r--tests/template/t11705.nim17
-rw-r--r--tests/template/t13426.nim87
-rw-r--r--tests/template/t17433.nim16
-rw-r--r--tests/template/t18113.nim14
-rw-r--r--tests/template/t19149.nim19
-rw-r--r--tests/template/t19277.nim19
-rw-r--r--tests/template/t19700.nim10
-rw-r--r--tests/template/t21231.nim10
-rw-r--r--tests/template/t21532.nim8
-rw-r--r--tests/template/t24112.nim19
-rw-r--r--tests/template/t6217.nim19
-rw-r--r--tests/template/t9534.nim21
-rw-r--r--tests/template/t_otemplates.nim345
-rw-r--r--tests/template/taliassyntax.nim74
-rw-r--r--tests/template/taliassyntaxerrors.nim28
-rw-r--r--tests/template/tcallsitelineinfo.nim17
-rw-r--r--tests/template/tcallsitelineinfo2.nim20
-rw-r--r--tests/template/tconfusinglocal.nim21
-rw-r--r--tests/template/tdefaultparam.nim56
-rw-r--r--tests/template/tdefined_overload.nim46
-rw-r--r--tests/template/tdotcall.nim32
-rw-r--r--tests/template/template_issues.nim304
-rw-r--r--tests/template/template_pragmas.nim9
-rw-r--r--tests/template/template_various.nim406
-rw-r--r--tests/template/texponential_eval.nim51
-rw-r--r--tests/template/tgenericparam.nim93
-rw-r--r--tests/template/tgensym_instantiationinfo.nim24
-rw-r--r--tests/template/tgensymhijack.nim37
-rw-r--r--tests/template/tgensymregression.nim88
-rw-r--r--tests/template/thygienictempl.nim22
-rw-r--r--tests/template/tidentconcatenations.nim31
-rw-r--r--tests/template/tinnerouterproc.nim20
-rw-r--r--tests/template/tmethodcall.nim24
-rw-r--r--tests/template/tmixin_in_proc.nim22
-rw-r--r--tests/template/tmodulealias.nim19
-rw-r--r--tests/template/tmore_regressions.nim44
-rw-r--r--tests/template/tnested.nim38
-rw-r--r--tests/template/tobjectdeclfield.nim21
-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/tparams_gensymed.nim405
-rw-r--r--tests/template/tparamscope.nim10
-rw-r--r--tests/template/tqualifiedident.nim8
-rw-r--r--tests/template/tqualifiedtype.nim25
-rw-r--r--tests/template/tredefinition.nim13
-rw-r--r--tests/template/tredefinition_override.nim33
-rw-r--r--tests/template/tscope.nim12
-rw-r--r--tests/template/tshadow.nim29
-rw-r--r--tests/template/tsighash_regression.nim8
-rw-r--r--tests/template/tstempl.nim24
-rw-r--r--tests/template/ttempl2.nim18
-rw-r--r--tests/template/ttempl3.nim83
-rw-r--r--tests/template/tunderscore1.nim11
-rw-r--r--tests/template/twhenintemplates.nim11
-rw-r--r--tests/template/twrong_getast.nim19
-rw-r--r--tests/template/twrongmapit.nim30
-rw-r--r--tests/template/twrongopensymchoice.nim24
-rw-r--r--tests/template/twrongsymkind.nim20
-rw-r--r--tests/template/utemplates.nim36
-rwxr-xr-xtests/tendian.nim3
-rwxr-xr-xtests/tenum.nim8
-rw-r--r--tests/test_nimscript.nims138
-rw-r--r--tests/testament/t16576.nim7
-rw-r--r--tests/testament/tinlinemsg.nim8
-rw-r--r--tests/testament/tjoinable.nim9
-rw-r--r--tests/testament/treject.nim6
-rw-r--r--tests/testament/tshould_not_work.nim53
-rw-r--r--tests/testament/tspecialpaths.nim9
-rw-r--r--[-rwxr-xr-x]tests/testdata/csvtest.csv (renamed from tests/csvtest.csv)0
-rw-r--r--[-rwxr-xr-x]tests/testdata/data.csv (renamed from tests/data.csv)0
-rw-r--r--tests/testdata/doc1.xml15
-rw-r--r--tests/testdata/jsontest.json26
-rw-r--r--tests/testdata/jsontest2.json80
-rw-r--r--tests/testdata/jsonwithextradata.json6
-rw-r--r--tests/testdata/mycert.pem81
-rw-r--r--tests/testdata/string.txt1
-rw-r--r--tests/testdata/wildhtml.html25
-rw-r--r--[-rwxr-xr-x]tests/testdata/xmltest.html (renamed from tests/xmltest.html)3
-rwxr-xr-xtests/tester.nim177
-rwxr-xr-xtests/tformat.nim6
-rwxr-xr-xtests/tgtk.nim61
-rw-r--r--tests/threads/nim.cfg1
-rw-r--r--tests/threads/t7172.nim34
-rw-r--r--tests/threads/t8535.nim30
-rw-r--r--tests/threads/threadex.nim50
-rw-r--r--tests/threads/tjsthreads.nim6
-rw-r--r--tests/threads/tmanyjoin.nim31
-rw-r--r--tests/threads/tmembug.nim51
-rw-r--r--tests/threads/tonthreadcreation.nim26
-rw-r--r--tests/threads/tracy_allocator.nim26
-rw-r--r--tests/threads/treusetvar.nim29
-rw-r--r--tests/threads/tthreadanalysis.nim52
-rw-r--r--tests/threads/tthreadheapviolation1.nim18
-rw-r--r--tests/threads/tthreadvars.nim79
-rw-r--r--tests/threads/ttryrecv.nim36
-rwxr-xr-xtests/tinit.nim6
-rwxr-xr-xtests/tints.nim41
-rwxr-xr-xtests/tio.nim7
-rwxr-xr-xtests/tisopr.nim20
-rwxr-xr-xtests/titer.nim44
-rwxr-xr-xtests/titer3.nim17
-rwxr-xr-xtests/tlastmod.nim18
-rwxr-xr-xtests/tlibs.nim21
-rwxr-xr-xtests/tlowhigh.nim18
-rwxr-xr-xtests/tmath.nim85
-rwxr-xr-xtests/tnamspc.nim5
-rwxr-xr-xtests/tnestif.nim18
-rwxr-xr-xtests/tnewuns.nim12
-rwxr-xr-xtests/tnoop.nim6
-rwxr-xr-xtests/tobject2.nim21
-rwxr-xr-xtests/tobjects.nim42
-rw-r--r--tests/tools/compile/config.nims1
-rw-r--r--tests/tools/compile/readme.md1
-rw-r--r--tests/tools/compile/tdeps.nim5
-rw-r--r--tests/tools/compile/tdetect.nim5
-rw-r--r--tests/tools/compile/tkoch.nim5
-rw-r--r--tests/tools/compile/tniminst.nim5
-rw-r--r--tests/tools/config.nims3
-rw-r--r--tests/tools/dontmentionme.nim3
-rw-r--r--tests/tools/second.nim3
-rw-r--r--tests/tools/tlinter.nim40
-rw-r--r--tests/tools/tnimgrep.nim404
-rw-r--r--tests/tools/tnimscriptwithmacro.nims22
-rw-r--r--tests/tools/tunused_imports.nim41
-rwxr-xr-xtests/topena1.nim5
-rwxr-xr-xtests/toptions.nim22
-rwxr-xr-xtests/tos.nim12
-rwxr-xr-xtests/toverflw.nim15
-rwxr-xr-xtests/toverlop.nim10
-rwxr-xr-xtests/toverwr.nim7
-rwxr-xr-xtests/tparscfg.nim25
-rwxr-xr-xtests/tparsopt.nim27
-rwxr-xr-xtests/tposix.nim13
-rwxr-xr-xtests/tprep.nim28
-rwxr-xr-xtests/tprintf.nim10
-rwxr-xr-xtests/tprocvar.nim26
-rwxr-xr-xtests/tpush.nim15
-rwxr-xr-xtests/tquit.nim6
-rwxr-xr-xtests/tradix.nim319
-rwxr-xr-xtests/treadln.nim12
-rwxr-xr-xtests/trecmod.nim2
-rwxr-xr-xtests/tregex.nim19
-rwxr-xr-xtests/treguse.nim21
-rwxr-xr-xtests/trepr.nim32
-rw-r--r--tests/trmacros/tdisallowif.nim28
-rw-r--r--tests/trmacros/tnorewrite.nim20
-rw-r--r--tests/trmacros/tor.nim34
-rw-r--r--tests/trmacros/trmacros_various.nim111
-rw-r--r--tests/trmacros/trmacros_various2.nim91
-rw-r--r--tests/trmacros/tstmtlist.nim34
-rwxr-xr-xtests/tseq2.nim13
-rwxr-xr-xtests/tseqcon.nim45
-rwxr-xr-xtests/tsets.nim58
-rwxr-xr-xtests/tsimmeth.nim8
-rwxr-xr-xtests/tsimtych.nim5
-rwxr-xr-xtests/tsizeof.nim10
-rwxr-xr-xtests/tstatret.nim5
-rwxr-xr-xtests/tstmtexp.nim3
-rwxr-xr-xtests/tstrace.nim16
-rwxr-xr-xtests/tstrdesc.nim14
-rwxr-xr-xtests/tstreams.nim7
-rwxr-xr-xtests/tstrtabs.nim12
-rwxr-xr-xtests/tstrutil.nim24
-rwxr-xr-xtests/ttempl.nim27
-rwxr-xr-xtests/ttempl2.nim14
-rwxr-xr-xtests/ttempl3.nim26
-rwxr-xr-xtests/ttime.nim6
-rw-r--r--tests/tuples/mnimsconstunpack.nim4
-rw-r--r--tests/tuples/t12892.nim8
-rw-r--r--tests/tuples/t18125_1.nim14
-rw-r--r--tests/tuples/t18125_2.nim20
-rw-r--r--tests/tuples/t7012.nim7
-rw-r--r--tests/tuples/t9177.nim15
-rw-r--r--tests/tuples/tfortupleunpack.nim52
-rw-r--r--tests/tuples/tinferred_generic_const.nim14
-rw-r--r--tests/tuples/tnimsconstunpack.nim8
-rw-r--r--tests/tuples/ttuples_issues.nim133
-rw-r--r--tests/tuples/ttuples_various.nim211
-rw-r--r--tests/tuples/ttypedesc_in_tuple_a.nim5
-rw-r--r--tests/tuples/ttypedesc_in_tuple_b.nim5
-rw-r--r--tests/tuples/tuple_with_nil.nim758
-rw-r--r--tests/tuples/twrong_generic_caching.nim4
-rw-r--r--tests/tuples/twrongtupleaccess.nim9
-rwxr-xr-xtests/tvardecl.nim9
-rwxr-xr-xtests/tvarious.nim43
-rwxr-xr-xtests/twalker.nim13
-rw-r--r--tests/typerel/t2plus.nim22
-rw-r--r--tests/typerel/t4799.nim246
-rw-r--r--tests/typerel/t4799_1.nim22
-rw-r--r--tests/typerel/t4799_2.nim22
-rw-r--r--tests/typerel/t4799_3.nim22
-rw-r--r--tests/typerel/t7600_1.nim21
-rw-r--r--tests/typerel/t7600_2.nim20
-rw-r--r--tests/typerel/t7734.nim19
-rw-r--r--tests/typerel/t8172.nim11
-rw-r--r--tests/typerel/t8905.nim7
-rw-r--r--tests/typerel/tclosure_nil_as_default.nim11
-rw-r--r--tests/typerel/tcommontype.nim20
-rw-r--r--tests/typerel/temptynode.nim16
-rw-r--r--tests/typerel/texplicitcmp.nim31
-rw-r--r--tests/typerel/tgeneric_subtype_regression.nim19
-rw-r--r--tests/typerel/tno_gcmem_in_shared.nim23
-rw-r--r--tests/typerel/tno_int_in_bool_context.nim7
-rw-r--r--tests/typerel/tnocontains.nim11
-rw-r--r--tests/typerel/tproctypeclass.nim89
-rw-r--r--tests/typerel/tptrs.nim8
-rw-r--r--tests/typerel/trectuple.nim16
-rw-r--r--tests/typerel/trectuples.nim14
-rw-r--r--[-rwxr-xr-x]tests/typerel/trectype.nim (renamed from tests/trectype.nim)35
-rw-r--r--[-rwxr-xr-x]tests/typerel/trefs.nim (renamed from tests/trefs.nim)36
-rw-r--r--tests/typerel/tregionptrs2.nim23
-rw-r--r--tests/typerel/trettypeinference.nim33
-rw-r--r--tests/typerel/tsecondarrayproperty.nim31
-rw-r--r--tests/typerel/tsigmatch.nim6
-rw-r--r--tests/typerel/tstr_as_openarray.nim22
-rw-r--r--tests/typerel/tsymchoice_for_expr.nim15
-rw-r--r--tests/typerel/ttuple1.nim20
-rw-r--r--tests/typerel/ttynilinstantiation.nim7
-rw-r--r--tests/typerel/ttypedesc_as_genericparam1.nim7
-rw-r--r--tests/typerel/ttypedesc_as_genericparam1_orc.nim5
-rw-r--r--tests/typerel/ttypedesc_as_genericparam2.nim10
-rw-r--r--tests/typerel/ttypelessemptyset.nim6
-rw-r--r--tests/typerel/ttypenoval.nim53
-rw-r--r--tests/typerel/ttypenovalue.nim10
-rw-r--r--tests/typerel/tuncheckedarray_eq.nim2
-rw-r--r--tests/typerel/tvarargsexpr.nim29
-rw-r--r--tests/typerel/tvoid.nim98
-rw-r--r--[-rwxr-xr-x]tests/typerel/typalias.nim (renamed from tests/typalias.nim)10
-rw-r--r--tests/typerel/typedescs.nim22
-rw-r--r--tests/typerel/typedescs2.nim17
-rw-r--r--tests/typerel/typeof_in_template.nim16
-rw-r--r--tests/typerel/typredef.nim7
-rw-r--r--tests/types/t14127_cast_number.nim30
-rw-r--r--tests/types/t15836.nim11
-rw-r--r--tests/types/t15836_2.nim21
-rw-r--r--tests/types/t21027.nim5
-rw-r--r--tests/types/t21260.nim13
-rw-r--r--tests/types/t5648.nim32
-rw-r--r--tests/types/t6456.nim7
-rw-r--r--tests/types/t6969.nim6
-rw-r--r--tests/types/taliasbugs.nim169
-rw-r--r--tests/types/tassignemptytuple.nim11
-rw-r--r--tests/types/tauto_canbe_void.nim15
-rw-r--r--tests/types/tauto_excessive.nim20
-rw-r--r--tests/types/tcast1.nim63
-rw-r--r--tests/types/tcyclic.nim135
-rw-r--r--tests/types/temptyseqs.nim90
-rw-r--r--tests/types/texportgeneric.nim8
-rw-r--r--tests/types/tfinalobj.nim15
-rw-r--r--[-rwxr-xr-x]tests/types/tforwty.nim (renamed from tests/tforwty.nim)18
-rw-r--r--[-rwxr-xr-x]tests/types/tforwty2.nim (renamed from tests/tforwty2.nim)44
-rw-r--r--tests/types/thard_tyforward.nim22
-rw-r--r--tests/types/tillegalrecursion3.nim12
-rw-r--r--tests/types/tillegalseqrecursion.nim6
-rw-r--r--tests/types/tillegaltuplerecursion.nim40
-rw-r--r--tests/types/tillegaltuplerecursiongeneric.nim7
-rw-r--r--tests/types/tillegaltuplerecursiongeneric2.nim9
-rw-r--r--tests/types/tillegaltyperecursion.nim17
-rw-r--r--tests/types/tillegaltyperecursion2.nim8
-rw-r--r--tests/types/tillegaltyperecursion3.nim10
-rw-r--r--[-rwxr-xr-x]tests/types/tillrec.nim (renamed from tests/tillrec.nim)25
-rw-r--r--tests/types/tinfiniterecursion.nim8
-rw-r--r--tests/types/tinheritgenericparameter.nim39
-rw-r--r--tests/types/tinheritpartialgeneric.nim43
-rw-r--r--tests/types/tinheritref.nim83
-rw-r--r--tests/types/tisopr.nim171
-rw-r--r--tests/types/tissues_types.nim118
-rw-r--r--tests/types/titerable.nim143
-rw-r--r--tests/types/tlent_var.nim25
-rw-r--r--tests/types/tnontype.nim9
-rw-r--r--tests/types/told_pragma_syntax1.nim5
-rw-r--r--tests/types/told_pragma_syntax2.nim5
-rw-r--r--tests/types/tparameterizedparent0.nim15
-rw-r--r--tests/types/tparameterizedparent1.nim14
-rw-r--r--tests/types/tparameterizedparent2.nim77
-rw-r--r--tests/types/tparameterizedparent3.nim15
-rw-r--r--tests/types/tparameterizedparent4.nim30
-rw-r--r--tests/types/ttopdowninference.nim333
-rw-r--r--tests/types/tyet_another_generic_regression.nim41
-rwxr-xr-xtests/typredef.nim3
-rw-r--r--tests/untestable/gdb/gdb_pretty_printer_test.py64
-rw-r--r--tests/untestable/gdb/gdb_pretty_printer_test_program.nim89
-rwxr-xr-xtests/untestable/gdb/gdb_pretty_printer_test_run.sh13
-rw-r--r--tests/untestable/network/README.md8
-rw-r--r--tests/untestable/network/stdlib/tnet.nim16
-rw-r--r--tests/untestable/readme.markdown9
-rw-r--r--tests/untestable/thttpclient_ssl_disabled.nim36
-rw-r--r--tests/untestable/thttpclient_ssl_env_var.nim74
-rw-r--r--tests/untestable/thttpclient_ssl_remotenetwork.nim230
-rw-r--r--tests/untestable/tpostgres.nim1
-rw-r--r--tests/untestable/tssl.nim36
-rw-r--r--tests/usingstmt/tusingstmt.nim16
-rw-r--r--tests/valgrind/tbasic_valgrind.nim6
-rw-r--r--tests/valgrind/tleak_arc.nim14
-rw-r--r--tests/varres/tnewseq_on_result_vart.nim9
-rw-r--r--tests/varres/tprevent_forloopvar_mutations.nim16
-rw-r--r--tests/varres/tvarres0.nim141
-rw-r--r--tests/varres/tvarres1.nim16
-rw-r--r--tests/varres/tvarres2.nim15
-rw-r--r--tests/varres/tvarres3.nim15
-rw-r--r--tests/varres/tvarres4.nim20
-rw-r--r--tests/varres/tvarres_via_forwarding.nim12
-rw-r--r--tests/varres/tvartup.nim10
-rw-r--r--tests/varres/twrong_parameter.nim16
-rw-r--r--tests/varstmt/tlet.nim19
-rw-r--r--tests/varstmt/tvardecl.nim19
-rw-r--r--tests/views/t19986.nim42
-rw-r--r--tests/views/tcan_compile_nim.nim4
-rw-r--r--tests/views/tcannot_borrow.nim22
-rw-r--r--tests/views/tconst_views.nim37
-rw-r--r--tests/views/tdont_mutate.nim58
-rw-r--r--tests/views/tmust_borrow_from_first_parameter.nim9
-rw-r--r--tests/views/tsplit_into_openarray.nim37
-rw-r--r--tests/views/tsplit_into_seq.nim41
-rw-r--r--tests/views/tsplit_into_table.nim40
-rw-r--r--tests/views/tviews1.nim136
-rw-r--r--tests/views/tviews2.nim90
-rw-r--r--tests/vm/meta.nim240
-rw-r--r--tests/vm/mevalffi.nim71
-rw-r--r--tests/vm/mscriptcompiletime.nim7
-rw-r--r--tests/vm/t11637.nim52
-rw-r--r--tests/vm/t17039.nim10
-rw-r--r--tests/vm/t17121.nim9
-rw-r--r--tests/vm/t18103.nim35
-rw-r--r--tests/vm/t19075.nim19
-rw-r--r--tests/vm/t19199.nim6
-rw-r--r--tests/vm/t20746.nim13
-rw-r--r--tests/vm/t21704.nim69
-rw-r--r--tests/vm/t2574.nim14
-rw-r--r--tests/vm/t9622.nim30
-rw-r--r--tests/vm/tableinstatic.nim38
-rw-r--r--tests/vm/taddrof.nim110
-rw-r--r--tests/vm/tanonproc.nim52
-rw-r--r--tests/vm/tarrayboundeval.nim31
-rw-r--r--tests/vm/tasmparser.nim174
-rw-r--r--tests/vm/tbitops.nim45
-rw-r--r--tests/vm/tcastint.nim309
-rw-r--r--tests/vm/tcgemptycallarg.nim3
-rw-r--r--tests/vm/tclosureiterator.nim9
-rw-r--r--tests/vm/tcnstseq.nim68
-rw-r--r--tests/vm/tcompilesetting.nim18
-rw-r--r--tests/vm/tcompiletimerange.nim28
-rw-r--r--tests/vm/tcompiletimesideeffects.nim42
-rw-r--r--tests/vm/tcompiletimetable.nim62
-rw-r--r--tests/vm/tcomponent.nim132
-rw-r--r--tests/vm/tconst.nim58
-rw-r--r--tests/vm/tconst_float_as_int.nim3
-rw-r--r--tests/vm/tconstarrayresem.nim29
-rw-r--r--tests/vm/tconstobj.nim95
-rw-r--r--tests/vm/tconstprocassignments.nim18
-rw-r--r--tests/vm/tconstresem.nim10
-rw-r--r--tests/vm/tconstscope1.nim5
-rw-r--r--tests/vm/tconstscope2.nim5
-rw-r--r--tests/vm/tconsttable.nim34
-rw-r--r--tests/vm/tconsttable2.nim81
-rw-r--r--tests/vm/tconvaddr.nim49
-rw-r--r--tests/vm/tcopy_global_var.nim30
-rw-r--r--tests/vm/teval1.nim42
-rw-r--r--tests/vm/texception.nim14
-rw-r--r--tests/vm/texcl.nim27
-rw-r--r--tests/vm/textensionmap.nim13
-rw-r--r--tests/vm/tfarjump.nim14
-rw-r--r--tests/vm/tfibconst.nim43
-rw-r--r--tests/vm/tfile_rw.nim22
-rw-r--r--tests/vm/tforwardproc.nim17
-rw-r--r--tests/vm/tgenericcompiletimeproc.nim36
-rw-r--r--tests/vm/tgloballetfrommacro.nim13
-rw-r--r--tests/vm/tgorge.bat1
-rw-r--r--tests/vm/tgorge.nim29
-rwxr-xr-xtests/vm/tgorge.sh2
-rw-r--r--tests/vm/tgorgeex.bat2
-rwxr-xr-xtests/vm/tgorgeex.sh3
-rw-r--r--tests/vm/tinheritance.nim94
-rw-r--r--tests/vm/tissues.nim76
-rw-r--r--tests/vm/tldconst.nim14
-rw-r--r--tests/vm/tmanyregs.nim16
-rw-r--r--tests/vm/tmaxloopiterations.nim15
-rw-r--r--tests/vm/tmisc_vm.nim459
-rw-r--r--tests/vm/tmitems_vm.nim45
-rw-r--r--tests/vm/tnewseqofcap.nim14
-rw-r--r--tests/vm/tnilclosurecall.nim8
-rw-r--r--tests/vm/tnilclosurecallstacktrace.nim23
-rw-r--r--tests/vm/tnilref.nim7
-rw-r--r--tests/vm/tnimnode.nim80
-rw-r--r--tests/vm/tnocompiletimefunc.nim14
-rw-r--r--tests/vm/tnocompiletimefunclambda.nim6
-rw-r--r--tests/vm/tnoreturn.nim32
-rw-r--r--tests/vm/topenarrays.nim89
-rw-r--r--tests/vm/toverflowopcaddimmint.nim11
-rw-r--r--tests/vm/toverflowopcaddint.nim12
-rw-r--r--tests/vm/toverflowopcmulint.nim11
-rw-r--r--tests/vm/toverflowopcsubimmint.nim10
-rw-r--r--tests/vm/toverflowopcsubint.nim12
-rw-r--r--tests/vm/tquadplus.nim14
-rw-r--r--tests/vm/tref.nim71
-rw-r--r--tests/vm/treset.nim50
-rw-r--r--tests/vm/triangle_array.nim13
-rw-r--r--tests/vm/tscriptcompiletime.nims9
-rw-r--r--tests/vm/tseq_badinit.nim58
-rw-r--r--tests/vm/tsetlen.nim30
-rw-r--r--tests/vm/tsignaturehash.nim20
-rw-r--r--tests/vm/tsimpleglobals.nim16
-rw-r--r--tests/vm/tslow_tables.nim30
-rw-r--r--tests/vm/tslurp.nim12
-rw-r--r--tests/vm/tstaticprintseq.nim92
-rw-r--r--tests/vm/tstring_openarray.nim33
-rw-r--r--tests/vm/tstringnil.nim50
-rw-r--r--tests/vm/tswap.nim34
-rw-r--r--tests/vm/ttouintconv.nim84
-rw-r--r--tests/vm/ttypedesc.nim31
-rw-r--r--tests/vm/tunsupportedintfloatcast.nim3
-rw-r--r--tests/vm/tvarsection.nim11
-rw-r--r--tests/vm/tvmmisc.nim796
-rw-r--r--tests/vm/tvmops.nim46
-rw-r--r--tests/vm/tvmopsDanger.nim13
-rw-r--r--tests/vm/twrong_concat.nim22
-rw-r--r--tests/vm/twrongarray.nim17
-rw-r--r--tests/vm/twrongconst.nim9
-rw-r--r--tests/vm/twrongwhen.nim13
-rw-r--r--tests/vm/tyaytypedesc.nim17
-rw-r--r--tests/vm/tzero_extend.nim44
-rw-r--r--tests/whenstmt/t12517.nim21
-rw-r--r--tests/whenstmt/t19426.nim16
-rw-r--r--tests/whenstmt/twhen.nim47
-rw-r--r--tests/whenstmt/twhen_macro.nim18
-rwxr-xr-xtests/wingui.nim9
-rwxr-xr-xtests/x11test.nim71
-rw-r--r--tests/xml/ttree_add.nim51
-rw-r--r--tests/xml/ttree_add1.nim53
-rw-r--r--tests/xml/ttree_delete.nim47
-rw-r--r--tests/xml/ttree_delete1.nim48
-rw-r--r--tests/xml/ttree_insert.nim53
-rw-r--r--tests/xml/ttree_insert1.nim51
-rw-r--r--tests/xml/ttree_replace.nim46
-rw-r--r--tests/xml/ttree_replace1.nim53
2956 files changed, 167406 insertions, 3378 deletions
diff --git a/tests/alias/t19349.nim b/tests/alias/t19349.nim
new file mode 100644
index 000000000..1e1e58264
--- /dev/null
+++ b/tests/alias/t19349.nim
@@ -0,0 +1,19 @@
+discard """
+  action: "compile"
+"""
+
+type
+  Vec3[T: SomeNumber] = object
+    arr: array[3, T]
+
+var 
+  cfloatArr: array[3, array[3, cfloat]]
+  cfloatSeq = newSeq[Vec3[cfloat]]()
+for row in cfloatArr:
+  cfloatSeq.add(Vec3[float32](arr: [row[0], row[1], row[2]]))
+
+var 
+  cuintArr: array[3, array[3, cuint]]
+  cuintSeq = newSeq[Vec3[cuint]]()
+for row in cuintArr:
+  cuintSeq.add(Vec3[uint32](arr: [row[0], row[1], row[2]]))
diff --git a/tests/alias/talias.nim b/tests/alias/talias.nim
new file mode 100644
index 000000000..a8f1b0dd0
--- /dev/null
+++ b/tests/alias/talias.nim
@@ -0,0 +1,67 @@
+# Test the alias analysis
+
+type
+  TAnalysisResult* = enum
+    arNo, arMaybe, arYes
+
+proc isPartOf*[S, T](a: S, b: T): TAnalysisResult {.
+  magic: "IsPartOf", noSideEffect.}
+  ## not yet exported properly.
+
+template compileTimeAssert(cond) =
+  when not cond:
+    {.compile: "is false: " & astToStr(cond).}
+
+template `<|` (a, b) =
+  compileTimeAssert isPartOf(a, b) == arYes
+
+template `!<|` (a, b) =
+  compileTimeAssert isPartOf(a, b) == arNo
+
+template `?<|` (a, b) =
+  compileTimeAssert isPartOf(a, b) == arMaybe
+
+type
+  TA {.inheritable.} = object
+  TC = object of TA
+    arr: array[0..3, int]
+    le, ri: ref TC
+    f: string
+    c: char
+    se: seq[TA]
+
+proc p(param1, param2: TC, param3: var TC): TC =
+  var
+    local: TC
+    plocal: ptr TC
+    plocal2: ptr TA
+
+  local.arr <| local
+  local.arr[0] <| local
+  local.arr[2] !<| local.arr[1]
+
+  plocal2[] ?<| local
+
+  param1 ?<| param2
+  local ?<| param3
+
+  local.arr[0] !<| param1
+  local.arr !<| param1
+  local.le[] ?<| param1
+
+  param1 !<| local.arr[0]
+  param1 !<| local.arr
+  param1 ?<| local.le[]
+
+  result !<| local
+  result <| result
+
+var
+  a, b: int
+  x: TC
+
+a <| a
+a !<| b
+
+discard p(x, x, x)
+
diff --git a/tests/align/globalalignas.nim b/tests/align/globalalignas.nim
new file mode 100644
index 000000000..15f564733
--- /dev/null
+++ b/tests/align/globalalignas.nim
@@ -0,0 +1,3 @@
+var myglobal1* {.align(128).}: int32
+var myglobal2* {.align(128).}: int32
+var myglobal3* {.align(128).}: int32
diff --git a/tests/align/talign.nim b/tests/align/talign.nim
new file mode 100644
index 000000000..08373ee49
--- /dev/null
+++ b/tests/align/talign.nim
@@ -0,0 +1,69 @@
+discard """
+ccodeCheck: "\\i @'NIM_ALIGN(128) NI mylocal1' .*"
+targets: "c cpp"
+output: "align ok"
+"""
+
+# This is for Azure. The keyword ``alignof`` only exists in ``c++11``
+# and newer. On Azure gcc does not default to c++11 yet.
+
+import globalalignas
+
+var toplevel1 {.align: 32.} : int32
+var toplevel2 {.align: 32.} : int32
+var toplevel3 {.align: 32.} : int32
+
+proc foobar() =
+  var myvar1 {.global, align(64).}: int = 123
+  var myvar2 {.global, align(64).}: int = 123
+  var myvar3 {.global, align(64).}: int = 123
+
+  doAssert (cast[uint](addr(myglobal1)) and 127) == 0
+  doAssert (cast[uint](addr(myglobal2)) and 127) == 0
+  doAssert (cast[uint](addr(myglobal3)) and 127) == 0
+
+  doAssert (cast[uint](addr(myvar1)) and 63) == 0
+  doAssert (cast[uint](addr(myvar2)) and 63) == 0
+  doAssert (cast[uint](addr(myvar3)) and 63) == 0
+
+  doAssert (cast[uint](addr(toplevel1)) and 31) == 0
+  doAssert (cast[uint](addr(toplevel2)) and 31) == 0
+  doAssert (cast[uint](addr(toplevel3)) and 31) == 0
+
+  # test multiple align expressions
+  var mylocal1 {.align(128), align(32).}: int = 123
+  var mylocal2 {.align(128), align(32).}: int = 123
+  var mylocal3 {.align(32), align(128).}: int = 123
+
+  doAssert (cast[uint](addr(mylocal1)) and 127) == 0
+  doAssert (cast[uint](addr(mylocal2)) and 127) == 0
+  doAssert (cast[uint](addr(mylocal3)) and 127) == 0
+
+  echo "align ok"
+
+foobar()
+
+# bug #13122
+
+type Bug[T] = object
+  bug{.align:64.}: T
+  sideffect{.align:64.}: int
+
+var bug: Bug[int]
+doAssert sizeof(bug) == 128, "Oops my size is " & $sizeof(bug) # 16
+
+
+block: # bug #22419
+  type
+    ValidatorPubKey = object
+      blob: array[96, byte]
+
+  proc f(): auto =
+    return iterator() =
+      var pad: int8 = 0
+      var y {.align: 16.}: ValidatorPubKey
+      let value = cast[uint64](addr y)
+      doAssert value mod 16 == 0
+
+  f()()
+
diff --git a/tests/align/tillegalalign.nim b/tests/align/tillegalalign.nim
new file mode 100644
index 000000000..c4a95f11b
--- /dev/null
+++ b/tests/align/tillegalalign.nim
@@ -0,0 +1,7 @@
+discard """
+cmd: "nim check $options $file"
+errormsg: "power of two expected"
+"""
+
+proc foobar() =
+  let something {.align(33).} = 123
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/amodule.nim b/tests/arc/amodule.nim
new file mode 100644
index 000000000..2b4204a66
--- /dev/null
+++ b/tests/arc/amodule.nim
@@ -0,0 +1,21 @@
+# bug #14219
+var vectors = @["a", "b", "c", "d", "e"]
+
+iterator testVectors(): string =
+  for vector in vectors:
+    yield vector
+
+var r = ""
+for item in testVectors():
+  r.add item
+echo r
+
+# bug #12990
+iterator test(): int {.closure.} =
+  yield 0
+
+let x = test
+while true:
+  let val = x()
+  if finished(x): break
+  echo val
diff --git a/tests/arc/bmodule.nim b/tests/arc/bmodule.nim
new file mode 100644
index 000000000..70c2cc645
--- /dev/null
+++ b/tests/arc/bmodule.nim
@@ -0,0 +1,4 @@
+import cmodule
+
+for i in @[1, 2, 3].cycle():
+  echo i
diff --git a/tests/arc/cmodule.nim b/tests/arc/cmodule.nim
new file mode 100644
index 000000000..6c6e6c0fa
--- /dev/null
+++ b/tests/arc/cmodule.nim
@@ -0,0 +1,4 @@
+iterator cycle*[T](s: openArray[T]): T =
+  let s = @s
+  for x in s:
+    yield x
diff --git a/tests/arc/dmodule.nim b/tests/arc/dmodule.nim
new file mode 100644
index 000000000..455ec7084
--- /dev/null
+++ b/tests/arc/dmodule.nim
@@ -0,0 +1,23 @@
+type
+  MinKind* = enum
+    minDictionary
+    minBool
+  MinValue* = object
+    case kind*: MinKind
+    of minDictionary:
+      symbols: seq[MinOperator]
+    else: discard
+  MinOperator = object
+
+# remove this inline pragma to make it compile
+proc `$`*(a: MinValue): string {.inline.} =
+  case a.kind
+  of minDictionary:
+    result = "hello"
+    for i in a.symbols:
+      result = "hello"
+  else: discard
+
+proc parseMinValue*(): MinValue =
+  # or this echo
+  echo result
diff --git a/tests/arc/nim.cfg b/tests/arc/nim.cfg
new file mode 100644
index 000000000..7c148b797
--- /dev/null
+++ b/tests/arc/nim.cfg
@@ -0,0 +1 @@
+--sinkInference:on
diff --git a/tests/arc/t14383.nim b/tests/arc/t14383.nim
new file mode 100644
index 000000000..96b505166
--- /dev/null
+++ b/tests/arc/t14383.nim
@@ -0,0 +1,217 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: '''
+hello
+hello
+@["a", "b"]
+---------------------
+plain:
+destroying: ('first', 42)
+destroying: ('second', 20)
+destroying: ('third', 12)
+
+Option[T]:
+destroying: ('first', 42)
+destroying: ('second', 20)
+destroying: ('third', 12)
+
+seq[T]:
+destroying: ('first', 42)
+destroying: ('second', 20)
+destroying: ('third', 12)
+
+1 1
+'''
+"""
+
+import dmodule
+
+var val = parseMinValue()
+if val.kind == minDictionary:
+  echo val
+
+#------------------------------------------------------------------------------
+# Issue #15238
+#------------------------------------------------------------------------------
+
+proc sinkArg(x: sink seq[string]) =
+  discard
+
+proc varArg(lst: var seq[string]) = 
+  sinkArg(lst)
+
+var x = @["a", "b"]
+varArg(x)
+echo x
+
+
+#------------------------------------------------------------------------------
+# Issue #15286
+#------------------------------------------------------------------------------
+
+import std/os
+discard getFileInfo(".")
+
+
+#------------------------------------------------------------------------------
+# Issue #15707
+#------------------------------------------------------------------------------
+
+type
+  JVMObject = ref object
+proc freeJVMObject(o: JVMObject) =
+  discard
+proc fromJObject(T: typedesc[JVMObject]): T =
+  result.new(cast[proc(r: T) {.nimcall.}](freeJVMObject))
+
+discard JVMObject.fromJObject()
+
+
+#------------------------------------------------------------------------------
+# Issue #15910
+#------------------------------------------------------------------------------
+
+import options
+
+type
+  Thing = object
+    name: string
+    age: int
+
+proc `=destroy`(thing: var Thing) =
+  if thing.name != "":
+    echo "destroying: ('", thing.name, "', ", thing.age, ")"
+  `=destroy`(thing.name)
+  `=destroy`(thing.age)
+
+proc plain() =
+  var t = Thing(name: "first", age: 42)
+  t = Thing(name: "second", age: 20)
+  t = Thing()
+  let u = Thing(name: "third", age: 12)
+
+proc optionT() =
+  var t = Thing(name: "first", age: 42).some
+  t = Thing(name: "second", age: 20).some
+  t = none(Thing)
+  let u = Thing(name: "third", age: 12).some
+
+proc seqT() =
+  var t = @[Thing(name: "first", age: 42)]
+  t = @[Thing(name: "second", age: 20)]
+  t = @[]
+  let u = @[Thing(name: "third", age: 12)]
+
+echo "---------------------"
+echo "plain:"
+plain()
+echo()
+
+echo "Option[T]:"
+optionT()
+echo()
+
+echo "seq[T]:"
+seqT()
+echo()
+
+
+#------------------------------------------------------------------------------
+# Issue #16120, const seq into sink
+#------------------------------------------------------------------------------
+
+proc main =
+  let avals = @[@[1.0'f32, 4.0, 7.0, 10.0]]
+  let rankdef = avals
+  echo avals.len, " ", rankdef.len
+
+main()
+
+
+#------------------------------------------------------------------------------
+# Issue #16722, ref on distinct type, wrong destructors called
+#------------------------------------------------------------------------------
+
+type
+  Obj = object of RootObj
+  ObjFinal = object
+  ObjRef = ref Obj
+  ObjFinalRef = ref ObjFinal
+  D = distinct Obj
+  DFinal = distinct ObjFinal
+  DRef = ref D
+  DFinalRef = ref DFinal
+
+proc `=destroy`(o: var Obj) =
+  doAssert false, "no Obj is constructed in this sample"
+
+proc `=destroy`(o: var ObjFinal) =
+  doAssert false, "no ObjFinal is constructed in this sample"
+
+var dDestroyed: int
+proc `=destroy`(d: var D) =
+  dDestroyed.inc
+
+proc `=destroy`(d: var DFinal) =
+  dDestroyed.inc
+
+func newD(): DRef =
+  DRef ObjRef()
+
+func newDFinal(): DFinalRef =
+  DFinalRef ObjFinalRef()
+
+proc testRefs() =
+  discard newD()
+  discard newDFinal()
+
+testRefs()
+
+doAssert(dDestroyed == 2)
+
+
+#------------------------------------------------------------------------------
+# Issue #16185, complex self-assingment elimination
+#------------------------------------------------------------------------------
+
+type
+  CpuStorage*[T] = ref CpuStorageObj[T]
+  CpuStorageObj[T] = object
+    size*: int
+    raw_buffer*: ptr UncheckedArray[T]
+  Tensor[T] = object
+    buf*: CpuStorage[T]
+  TestObject = object
+    x: Tensor[float]
+
+proc `=destroy`[T](s: var CpuStorageObj[T]) =
+  if s.raw_buffer != nil:
+    s.raw_buffer.deallocShared()
+    s.size = 0
+    s.raw_buffer = nil
+
+proc `=`[T](a: var CpuStorageObj[T]; b: CpuStorageObj[T]) {.error.}
+
+proc allocCpuStorage[T](s: var CpuStorage[T], size: int) =
+  new(s)
+  s.raw_buffer = cast[ptr UncheckedArray[T]](allocShared0(sizeof(T) * size))
+  s.size = size
+
+proc newTensor[T](size: int): Tensor[T] =
+  allocCpuStorage(result.buf, size)
+
+proc `[]`[T](t: Tensor[T], idx: int): T = t.buf.raw_buffer[idx]
+proc `[]=`[T](t: Tensor[T], idx: int, val: T) = t.buf.raw_buffer[idx] = val
+
+proc toTensor[T](s: seq[T]): Tensor[T] =
+  result = newTensor[T](s.len)
+  for i, x in s:
+    result[i] = x
+
+proc main2() =
+  var t: TestObject
+  t.x = toTensor(@[1.0, 2, 3, 4])
+  t.x = t.x  
+  doAssert(t.x.buf != nil) # self-assignment above should be eliminated
+
+main2()
diff --git a/tests/arc/t14472.nim b/tests/arc/t14472.nim
new file mode 100644
index 000000000..4ef661161
--- /dev/null
+++ b/tests/arc/t14472.nim
@@ -0,0 +1,43 @@
+discard """
+  valgrind: true
+  cmd: "nim cpp --gc:arc -d:useMalloc --deepcopy:on $file"
+"""
+
+type
+  ImportMaterial* = object
+    # Adding a field here makes the problem go away.
+
+  Mesh* = object
+    vertices: seq[float32]
+    material: ImportMaterial
+
+  ImportedScene* = object
+    meshes*: seq[Mesh]
+
+proc bork() : ImportedScene =
+  var mats: seq[ImportMaterial]
+
+  setLen(mats, 1)
+  add(result.meshes, Mesh(material: mats[0]))
+
+var s = bork()
+
+
+#------------------------------------------------------------------------
+# issue #15543
+
+import tables
+
+type
+  cdbl {.importc: "double".} = object
+
+  MyObject = ref object of RootObj
+    y: Table[string, cdbl]
+        
+
+proc test =
+  var x = new(MyObject)
+
+test()
+
+
diff --git a/tests/arc/t14864.nim b/tests/arc/t14864.nim
new file mode 100644
index 000000000..f59b14d2c
--- /dev/null
+++ b/tests/arc/t14864.nim
@@ -0,0 +1,5 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+"""
+
+import bmodule
diff --git a/tests/arc/t15909.nim b/tests/arc/t15909.nim
new file mode 100644
index 000000000..f25c89daf
--- /dev/null
+++ b/tests/arc/t15909.nim
@@ -0,0 +1,16 @@
+discard """
+  action: run
+  cmd: "nim c --gc:arc $file"
+"""
+
+proc f1() {.noreturn.} = raise newException(CatchableError, "")
+
+proc f2(y: int): int =
+  if y != 0:
+    y
+  else:
+    f1()
+
+doAssert f2(5) == 5
+doAssertRaises(CatchableError):
+  discard f2(0)
diff --git a/tests/arc/t16033.nim b/tests/arc/t16033.nim
new file mode 100644
index 000000000..59ed22e4d
--- /dev/null
+++ b/tests/arc/t16033.nim
@@ -0,0 +1,10 @@
+discard """
+  targets: "c js"
+  matrix: "--gc:arc"
+"""
+
+# bug #16033
+when defined js:
+  doAssert not compileOption("gc", "arc")
+else:
+  doAssert compileOption("gc", "arc")
diff --git a/tests/arc/t16458.nim b/tests/arc/t16458.nim
new file mode 100644
index 000000000..6ae114287
--- /dev/null
+++ b/tests/arc/t16458.nim
@@ -0,0 +1,6 @@
+discard """
+  matrix: "--gc:orc --d:useNimRtl"
+  action: "compile"
+"""
+
+echo 134
\ No newline at end of file
diff --git a/tests/arc/t16558.nim b/tests/arc/t16558.nim
new file mode 100644
index 000000000..0dbe02b33
--- /dev/null
+++ b/tests/arc/t16558.nim
@@ -0,0 +1,9 @@
+discard """
+  matrix: "--gc:arc"
+  errormsg: "expression cannot be cast to 'int'"
+"""
+
+block: # bug #16558
+  var value = "hi there"
+  var keepInt: int
+  keepInt = cast[int](value)
diff --git a/tests/arc/t17025.nim b/tests/arc/t17025.nim
new file mode 100644
index 000000000..a64c59ac1
--- /dev/null
+++ b/tests/arc/t17025.nim
@@ -0,0 +1,56 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: '''
+{"Package": {"name": "hello"}, "Author": {"name": "name", "qq": "123456789", "email": "email"}}
+hello
+name
+123456789
+email
+hello
+name2
+987654321
+liame
+'''
+"""
+
+import parsecfg, streams, tables
+
+const cfg = """[Package]
+name=hello
+[Author]
+name=name
+qq=123456789
+email="email""""
+
+proc main() =
+    let stream = newStringStream(cfg)
+    let dict = loadConfig(stream)
+    var pname = dict.getSectionValue("Package","name")
+    var name = dict.getSectionValue("Author","name")
+    var qq = dict.getSectionValue("Author","qq")
+    var email = dict.getSectionValue("Author","email")
+    echo dict[]
+    echo pname & "\n" & name & "\n" & qq & "\n" & email
+    stream.close()
+
+main()
+
+proc getDict(): OrderedTableRef[string, OrderedTableRef[string, string]] =
+    result = newOrderedTable[string, OrderedTableRef[string, string]]()
+    result["Package"] = newOrderedTable[string, string]()
+    result["Package"]["name"] = "hello"
+    result["Author"] = newOrderedTable[string, string]()
+    result["Author"]["name"] = "name2"
+    result["Author"]["qq"] = "987654321"
+    result["Author"]["email"] = "liame"
+
+proc main2() =
+    let dict = getDict()
+    var pname = dict.getSectionValue("Package","name")
+    var name = dict.getSectionValue("Author","name")
+    var qq = dict.getSectionValue("Author","qq")
+    var email = dict.getSectionValue("Author","email")
+    echo pname & "\n" & name & "\n" & qq & "\n" & email
+
+main2()
+
diff --git a/tests/arc/t17173.nim b/tests/arc/t17173.nim
new file mode 100644
index 000000000..0acd886a2
--- /dev/null
+++ b/tests/arc/t17173.nim
@@ -0,0 +1,10 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+import std/strbasics
+
+
+var a = "  vhellov   "
+strip(a)
+doAssert a == "vhellov"
diff --git a/tests/arc/t17812.nim b/tests/arc/t17812.nim
new file mode 100644
index 000000000..dd8ac89b0
--- /dev/null
+++ b/tests/arc/t17812.nim
@@ -0,0 +1,41 @@
+discard """
+  targets: "c js"
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+import std/times
+
+block: # bug #17812
+  block:
+    type
+      Task = object
+        cb: proc ()
+
+    proc hello() = discard
+
+
+    let t = Task(cb: hello)
+
+    doAssert t.repr.len > 0
+
+
+  block:
+    type MyObj = object
+      field: DateTime
+
+
+    proc `$`(o: MyObj): string = o.repr
+
+    doAssert ($MyObj()).len > 0
+
+# bug #22175
+
+type Xxx = object
+  value: string
+
+proc complete(xxx: ref Xxx, v: sink string) =
+  xxx.value = move(v)
+
+let yyy = (ref Xxx)()
+
+yyy.complete("test")
diff --git a/tests/arc/t18645.nim b/tests/arc/t18645.nim
new file mode 100644
index 000000000..c5fddd4bb
--- /dev/null
+++ b/tests/arc/t18645.nim
@@ -0,0 +1,18 @@
+discard """
+  matrix: "--gc:arc; --gc:refc"
+  output: '''
+1
+2
+3
+'''
+"""
+
+proc bitTypeIdUnion() =
+  var bitId {.global.} = block:
+    0
+  inc bitId
+  echo bitId
+
+bitTypeIdUnion()
+bitTypeIdUnion()
+bitTypeIdUnion()
diff --git a/tests/arc/t18971.nim b/tests/arc/t18971.nim
new file mode 100644
index 000000000..9b587d956
--- /dev/null
+++ b/tests/arc/t18971.nim
@@ -0,0 +1,10 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+"""
+
+type MyObj = ref object
+
+var o = MyObj()
+proc x: var MyObj = o
+
+var o2 = x()
diff --git a/tests/arc/t18977.nim b/tests/arc/t18977.nim
new file mode 100644
index 000000000..c775551a4
--- /dev/null
+++ b/tests/arc/t18977.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:arc"
+"""
+
+type
+  E = enum
+    a, b, c, d
+  X = object
+    v: int
+  O = object
+    case kind: E
+    of a:
+      a: int
+    of {b, c}:
+      b: float
+    else:
+      d: X
+
+proc `=destroy`(x: var X) =
+  echo "x destroyed"
+
+var o = O(kind: d, d: X(v: 12345))
+doAssert o.d.v == 12345
+
+doAssertRaises(FieldDefect):
+  o.kind = a
diff --git a/tests/arc/t19231.nim b/tests/arc/t19231.nim
new file mode 100644
index 000000000..40fcf277c
--- /dev/null
+++ b/tests/arc/t19231.nim
@@ -0,0 +1,18 @@
+discard """
+  matrix: "--mm:orc"
+  targets: "c cpp"
+"""
+
+type
+  Game* = ref object
+
+proc free*(game: Game) =
+  var mixNumOpened:cint = 0
+  for i in 0..<mixNumOpened:
+    mixNumOpened -= 1
+
+proc newGame*(): Game =
+  new result, free
+
+var
+  game*: Game
diff --git a/tests/arc/t19364.nim b/tests/arc/t19364.nim
new file mode 100644
index 000000000..f520f3291
--- /dev/null
+++ b/tests/arc/t19364.nim
@@ -0,0 +1,30 @@
+discard """
+  cmd: '''nim c --gc:arc --expandArc:fooLeaks $file'''
+  nimout: '''
+--expandArc: fooLeaks
+
+var
+  tmpTuple_cursor
+  a_cursor
+  b_cursor
+  c_cursor
+tmpTuple_cursor = refTuple
+a_cursor = tmpTuple_cursor[0]
+b_cursor = tmpTuple_cursor[1]
+c_cursor = tmpTuple_cursor[2]
+-- end of expandArc ------------------------
+'''
+"""
+
+func fooLeaks(refTuple: tuple[a,
+                              b,
+                              c: seq[float]]): float =
+  let (a, b, c) = refTuple
+
+let refset = (a: newSeq[float](25_000_000),
+              b: newSeq[float](25_000_000),
+              c: newSeq[float](25_000_000))
+
+var res = newSeq[float](1_000_000)
+for i in 0 .. res.high:
+  res[i] = fooLeaks(refset)
diff --git a/tests/arc/t19401.nim b/tests/arc/t19401.nim
new file mode 100644
index 000000000..56702a4a2
--- /dev/null
+++ b/tests/arc/t19401.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''
+delete foo
+delete foo
+delete foo
+'''
+  matrix: "--mm:arc"
+"""
+
+type Foo = ref object
+  data: int
+proc delete(self: Foo) 
+proc newFoo: Foo =
+  let x = 12
+  discard x
+  new(result, delete)
+  result.data = x
+proc delete(self: Foo) =
+  doAssert self.data == 12
+  echo("delete foo")
+
+if isMainModule:
+  proc test() =
+    let x1 = newFoo()
+    let x2 = newFoo()
+    discard x1
+    discard x2
+    var x3: Foo
+    new(x3, delete)
+    x3.data = 12
+    discard x3
+  test()
diff --git a/tests/arc/t19402.nim b/tests/arc/t19402.nim
new file mode 100644
index 000000000..5ee6fc798
--- /dev/null
+++ b/tests/arc/t19402.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''
+delete foo
+delete foo
+delete foo
+'''
+  matrix: "--mm:arc"
+"""
+
+type Foo = ref object of RootObj
+  data: int
+proc delete(self: Foo)
+proc newFoo: Foo =
+  let x = 12
+  discard x
+  new(result, delete)
+  result.data = x
+proc delete(self: Foo) =
+  doAssert self.data == 12
+  echo("delete foo")
+
+if isMainModule:
+  proc test() =
+    let x1 = newFoo()
+    let x2 = newFoo()
+    discard x1
+    discard x2
+    var x3: Foo
+    new(x3, delete)
+    x3.data = 12
+    discard x3
+  test()
\ No newline at end of file
diff --git a/tests/arc/t19435.nim b/tests/arc/t19435.nim
new file mode 100644
index 000000000..519216bad
--- /dev/null
+++ b/tests/arc/t19435.nim
@@ -0,0 +1,29 @@
+discard """
+  matrix: "--gc:arc"
+"""
+
+# bug #19435
+{.experimental: "views".}
+
+type
+  Bar = object
+    placeholder: int
+  Foo = object
+    placeholder: int
+    c: seq[Bar] # remove this line to make things right
+
+func children*(s: var seq[Foo]): openArray[Foo] =
+  s.toOpenArray(0, s.len-1)
+
+proc test =
+  var foos = @[Foo(), Foo()]
+
+  assert foos.children.len == 2
+  var flag = true
+  for a in foos.children:
+    flag = false
+
+  if flag:
+    doAssert false
+
+test()
\ No newline at end of file
diff --git a/tests/arc/t19457.nim b/tests/arc/t19457.nim
new file mode 100644
index 000000000..78447ce82
--- /dev/null
+++ b/tests/arc/t19457.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #19457
+proc gcd(x, y: seq[int]): seq[int] =
+    var
+      a = x
+      b = y
+    while b[0] > 0:
+      let c = @[a[0] mod b[0]]
+      a = b
+      b = c
+    return a
+
+doAssert gcd(@[1], @[2]) == @[1]
\ No newline at end of file
diff --git a/tests/arc/t19862.nim b/tests/arc/t19862.nim
new file mode 100644
index 000000000..6d3f57692
--- /dev/null
+++ b/tests/arc/t19862.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+import std/widestrs
+
+# bug #19862
+type NewString = object
+
+proc len(s: NewString): int = 10
+
+converter toNewString(x: WideCStringObj): NewString = discard
+
+let w = newWideCString("test")
+doAssert len(w) == 4
diff --git a/tests/arc/t20456.nim b/tests/arc/t20456.nim
new file mode 100644
index 000000000..ace79255a
--- /dev/null
+++ b/tests/arc/t20456.nim
@@ -0,0 +1,7 @@
+discard """
+  cmd: "nim check $file"
+  action: "compile"
+"""
+
+when not defined(gcOrc):
+  {.error: "orc".}
diff --git a/tests/arc/t20588.nim b/tests/arc/t20588.nim
new file mode 100644
index 000000000..008bd1dcd
--- /dev/null
+++ b/tests/arc/t20588.nim
@@ -0,0 +1,25 @@
+discard """
+  cmd: "nim check --warnings:off --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t20588.nim(20, 12) Error: illegal type conversion to 'auto'
+t20588.nim(21, 14) Error: illegal type conversion to 'typed'
+t20588.nim(22, 16) Error: illegal type conversion to 'untyped'
+t20588.nim(24, 7) Error: illegal type conversion to 'any'
+'''
+"""
+
+
+
+
+
+
+
+
+
+discard 0.0.auto
+discard typed("abc")
+discard untyped(4)
+var a = newSeq[bool](1000)
+if any(a):
+  echo "ok?"
\ No newline at end of file
diff --git a/tests/arc/t21184.nim b/tests/arc/t21184.nim
new file mode 100644
index 000000000..91d0c42c7
--- /dev/null
+++ b/tests/arc/t21184.nim
@@ -0,0 +1,77 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+import std/[with]
+
+type
+  Node* {.acyclic.} = ref object of RootObj
+    name: string
+    data: pointer
+    children: seq[Node]
+  TextNode = ref object of Node
+    text: string
+
+proc fakeEcho(s: string) =
+  if s.len < 0:
+    echo s
+
+proc newNode[T: Node](parent: Node): T =
+  new result
+  result.data = alloc0(250)
+  parent.children.add(result)
+
+proc newRootNode(): Node =
+  new result
+  result.data = alloc0(250)
+
+method printNode(node: Node) {.base.} =
+  fakeEcho node.name
+
+method printNode(node: TextNode) =
+  procCall printNode(Node(node))
+  fakeEcho node.text
+
+proc printChildren(node: Node) =
+  for child in node.children:
+    child.printNode()
+    printChildren(child)
+
+proc free(node: Node) =
+  for child in node.children:
+    free(child)
+  dealloc(node.data)
+
+template node(parent: Node, body: untyped): untyped =
+  var node = newNode[Node](parent)
+  with node:
+    body
+
+proc textNode(parent: Node, text: string) =
+  var node = newNode[TextNode](parent)
+  node.text = text
+
+template withRootNode(body: untyped): untyped =
+  var root = newRootNode()
+  root.name = "root"
+  with root:
+    body
+  root.printNode()
+  printChildren(root)
+  root.free()
+
+proc doTest() =
+  withRootNode:
+    node:
+      name = "child1"
+      node:
+        name = "child2"
+        node:
+          name = "child3"
+          textNode "Hello, world!"
+
+
+# bug #21171
+if isMainModule:
+  for i in 0..100000:
+    doTest()
diff --git a/tests/arc/t22218.nim b/tests/arc/t22218.nim
new file mode 100644
index 000000000..7837ed1d0
--- /dev/null
+++ b/tests/arc/t22218.nim
@@ -0,0 +1,25 @@
+discard """
+  cmd: "nim c --mm:arc $file"
+  errormsg: "'=copy' is not available for type <Obj>; requires a copy because it's not the last read of 'chan[]'; routine: test"
+"""
+
+# bug #22218
+type Obj[T] = object
+  v: T
+
+proc `=copy`[T](
+    dest: var Obj[T],
+    source: Obj[T]
+  ) {.error: "A channel cannot be copied".}
+
+from system/ansi_c import c_calloc
+
+proc test() =
+    var v: bool = true
+    var chan = cast[ptr Obj[int]](c_calloc(1, csize_t sizeof(Obj[int])))
+    var copy = chan[]
+
+    echo chan.v
+    echo v
+
+test()
\ No newline at end of file
diff --git a/tests/arc/t22237.nim b/tests/arc/t22237.nim
new file mode 100644
index 000000000..c6dbf768a
--- /dev/null
+++ b/tests/arc/t22237.nim
@@ -0,0 +1,55 @@
+discard """
+  matrix: "--mm:arc; --mm:orc"
+"""
+
+import std/macros
+import std/streams
+
+# bug #22237
+
+proc iterlines_closure2(f: File | Stream): iterator (): string =
+  result = iterator(): string =
+    for line in f.lines:
+      if line.len == 0:
+        break
+      yield line
+
+proc test() =
+  let f = newStringStream("""
+    1
+    2
+
+    3
+    4
+
+    5
+    6
+    7
+
+    8
+""")
+  while not f.atEnd():
+    let iterator_inst = iterlines_closure2(f)
+    for item in iterator_inst(): # Fails with "SIGSEGV: Illegal storage access. (Attempt to read from nil?)"
+      discard
+
+test()
+
+# bug #21160
+import sequtils
+
+iterator allMoves(fls: seq[int]): seq[int] =
+  yield fls
+
+proc neighbors(flrs: seq[int]): iterator: seq[int] =
+  return iterator(): seq[int] =
+    for flrs2 in allMoves(flrs):
+      yield flrs2
+      for flrs3 in allMoves(flrs2):
+        yield flrs3
+
+let f = @[1]
+for _ in neighbors(f):
+  discard
+for _ in neighbors(f):
+  discard
diff --git a/tests/arc/t22478.nim b/tests/arc/t22478.nim
new file mode 100644
index 000000000..5373fa161
--- /dev/null
+++ b/tests/arc/t22478.nim
@@ -0,0 +1,46 @@
+discard """
+  matrix: "-d:nimNoLentIterators --mm:arc"
+  output: '''PUSH DATA: {"test.message":{"test":{"nested":"v1"}}}'''
+  joinable: false
+"""
+
+# bug #22748
+import std/[json, typetraits, times]
+
+# publish
+
+proc publish*[T](payload: T) =
+  discard
+
+type MetricsPoint* = JsonNode
+
+proc push*(stat: string, data: JsonNode, usec: int64 = 0) =
+  let payload = newJObject()
+
+  # this results in a infinite recursion unless we deepCopy()
+  payload[stat] = data #.deepCopy
+
+  echo "PUSH DATA: ", payload
+
+  publish[MetricsPoint](payload)
+
+var scopes {.threadvar.}: seq[JsonNode]
+
+type WithTimeCallback*[T] = proc(data: var JsonNode): T
+
+proc pushScoped*[T](metric: string, blk: WithTimeCallback[T]): T {.gcsafe.} =
+  scopes.add newJObject()
+  defer: discard scopes.pop()
+
+  let stc = (cpuTime() * 1000_000).int64
+  result = blk(scopes[^1])
+  let dfc = (cpuTime() * 1000_000).int64 - stc
+
+  push(metric, scopes[^1], dfc)
+
+# demo code
+
+discard pushScoped[int]("test.message") do (data: var JsonNode) -> int:
+  data["test"] = %*{
+    "nested": "v1"
+  }
\ No newline at end of file
diff --git a/tests/arc/t22787.nim b/tests/arc/t22787.nim
new file mode 100644
index 000000000..5840a984b
--- /dev/null
+++ b/tests/arc/t22787.nim
@@ -0,0 +1,37 @@
+discard """
+  joinable: false
+"""
+
+import std/assertions
+
+proc foo =
+  var s:seq[string]
+  var res = ""
+
+  for i in 0..3:
+    s.add ("test" & $i)
+    s.add ("test" & $i)
+
+  var lastname:string
+
+  for i in s:
+    var name = i[0..4]
+
+    if name != lastname:
+      res.add "NEW:" & name & "\n"
+    else:
+      res.add name & ">" & lastname & "\n"
+
+    lastname = name
+
+  doAssert res == """
+NEW:test0
+test0>test0
+NEW:test1
+test1>test1
+NEW:test2
+test2>test2
+NEW:test3
+test3>test3
+"""
+foo()
\ No newline at end of file
diff --git a/tests/arc/t23247.nim b/tests/arc/t23247.nim
new file mode 100644
index 000000000..0fadc50cd
--- /dev/null
+++ b/tests/arc/t23247.nim
@@ -0,0 +1,52 @@
+discard """
+  matrix: ";-d:useMalloc"
+"""
+
+# bug #23247
+import std/hashes
+
+func baseAddr[T](x: openArray[T]): ptr T =
+  # Return the address of the zero:th element of x or `nil` if x is empty
+  if x.len == 0: nil else: cast[ptr T](x)
+
+func makeUncheckedArray[T](p: ptr T): ptr UncheckedArray[T] =
+  cast[ptr UncheckedArray[T]](p)
+
+type
+  LabelKey = object
+    data: seq[string]
+    refs: ptr UncheckedArray[string]
+    refslen: int
+
+  Gauge = ref object
+    metrics: seq[seq[seq[string]]]
+
+template values(key: LabelKey): openArray[string] =
+  if key.refslen > 0:
+    key.refs.toOpenArray(0, key.refslen - 1)
+  else:
+    key.data
+
+proc hash(key: LabelKey): Hash =
+  hash(key.values)
+
+proc view(T: type LabelKey, values: openArray[string]): T =
+  # TODO some day, we might get view types - until then..
+  LabelKey(refs: baseAddr(values).makeUncheckedArray(), refslen: values.len())
+
+template withValue2(k: untyped) =
+  discard hash(k)
+
+proc setGauge(
+    collector: Gauge,
+    labelValues: openArray[string],
+) =
+  let v = LabelKey.view(labelValues)
+  withValue2(v)
+  collector.metrics.add @[@labelValues, @labelValues]
+  discard @labelValues
+
+var nim_gc_mem_bytes = Gauge()
+let threadID = $getThreadId()
+setGauge(nim_gc_mem_bytes, @[threadID])
+setGauge(nim_gc_mem_bytes, @[threadID])
\ No newline at end of file
diff --git a/tests/arc/t9650.nim b/tests/arc/t9650.nim
new file mode 100644
index 000000000..a8182db68
--- /dev/null
+++ b/tests/arc/t9650.nim
@@ -0,0 +1,87 @@
+discard """
+  matrix: "--gc:arc"
+"""
+
+import typetraits
+
+# bug #9650
+type
+  SharedPtr*[T] = object
+    val: ptr tuple[atomicCounter: int, value: T]
+
+  Node*[T] = object
+    value: T
+    next: SharedPtr[Node[T]]
+
+  ForwardList*[T] = object
+    first: SharedPtr[Node[T]]
+
+proc `=destroy`*[T](p: var SharedPtr[T]) =
+  if p.val != nil:
+    let c = atomicDec(p.val[].atomicCounter)
+    if c == 0:
+      when not supportsCopyMem(T):
+         `=destroy`(p.val[])
+      dealloc(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) =
+  if dest.val != src.val:
+    if dest.val != nil:
+      `=destroy`(dest)
+    if src.val != nil:
+      discard atomicInc(src.val[].atomicCounter)
+      dest.val = src.val
+
+proc `=sink`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+ 
+proc newSharedPtr*[T](val: sink T): SharedPtr[T] =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val.atomicCounter = 1
+  result.val.value = val
+
+proc isNil*[T](p: SharedPtr[T]): bool =
+  p.val == nil
+
+template `->`*[T](p: SharedPtr[T], name: untyped): untyped =
+  p.val.value.name
+
+proc createNode[T](val: T): SharedPtr[ Node[T] ]=
+  result = newSharedPtr(Node[T](value: val))
+
+proc push_front*[T](list: var ForwardList[T], val: T) =
+  var newElem = createNode(val)
+  newElem->next = list.first
+  list.first = newElem
+
+proc pop_front*[T](list: var ForwardList[T]) =
+  let head = list.first
+  list.first = head->next
+
+proc toString*[T](list: ForwardList[T]): string =
+  result = "["
+  var head = list.first
+  while not head.isNil:
+    result &= $(head->value) & ", "
+    head = head->next
+  result &= ']'
+
+block:
+  var x: ForwardList[int]
+  x.push_front(1)
+  x.push_front(2)
+  x.push_front(3)
+
+  doAssert toString(x) == "[3, 2, 1, ]"
+
+  x.pop_front()
+  x.pop_front()
+  doAssert toString(x) == "[1, ]"
+
+  x.pop_front()
+  doAssert toString(x) == "[]"
diff --git a/tests/arc/taliased_reassign.nim b/tests/arc/taliased_reassign.nim
new file mode 100644
index 000000000..5563fae8c
--- /dev/null
+++ b/tests/arc/taliased_reassign.nim
@@ -0,0 +1,41 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+# bug #20993
+
+type
+  Dual[int] = object # must be generic (even if fully specified)
+    p: int
+proc D(p: int): Dual[int] = Dual[int](p: p)
+proc `+`(x: Dual[int], y: Dual[int]): Dual[int] = D(x.p + y.p)
+
+type
+  Tensor[T] = object
+    buf: seq[T]
+proc newTensor*[T](s: int): Tensor[T] = Tensor[T](buf: newSeq[T](s))
+proc `[]`*[T](t: Tensor[T], idx: int): T = t.buf[idx]
+proc `[]=`*[T](t: var Tensor[T], idx: int, val: T) = t.buf[idx] = val
+
+proc `+.`[T](t1, t2: Tensor[T]): Tensor[T] =
+  let n = t1.buf.len
+  result = newTensor[T](n)
+  for i in 0 ..< n:
+    result[i] = t1[i] + t2[i]
+
+proc toTensor*[T](a: sink seq[T]): Tensor[T] =
+  ## This breaks it: Using `T` instead makes it work
+  type U = typeof(a[0])
+  var t: Tensor[U] # Tensor[T] works
+  t.buf = a
+  result = t
+
+proc loss() =
+  var B = toTensor(@[D(123)])
+  let a = toTensor(@[D(-10)])
+  B = B +. a
+  doAssert B[0].p == 113, "I want to be 113, but I am " & $B[0].p
+
+loss()
+
+
diff --git a/tests/arc/tamemfiles.nim b/tests/arc/tamemfiles.nim
new file mode 100644
index 000000000..97deb489f
--- /dev/null
+++ b/tests/arc/tamemfiles.nim
@@ -0,0 +1,110 @@
+discard """
+  output: '''
+loop 1a
+loop 1b; cols: @[1, x]
+loop 1c
+loop 1d
+loop 1a
+loop 1b; cols: @[2, y]
+loop 1c
+loop 1d
+'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #13596
+
+import tables, memfiles, strutils, os
+
+type Splitr* = tuple[ repeat: bool, chrDlm: char, setDlm: set[char], n: int ]
+
+type csize = uint
+proc cmemchr*(s: pointer, c: char, n: csize): pointer {.
+  importc: "memchr", header: "<string.h>" .}
+proc `-!`*(p, q: pointer): int {.inline.} =
+  (cast[int](p) -% cast[int](q)).int
+proc `+!`*(p: pointer, i: int): pointer {.inline.} =
+  cast[pointer](cast[int](p) +% i)
+proc `+!`*(p: pointer, i: uint64): pointer {.inline.} =
+  cast[pointer](cast[uint64](p) + i)
+
+proc charEq(x, c: char): bool {.inline.} = x == c
+
+proc initSplitr*(delim: string): Splitr =
+  if delim == "white":          #User can use any other permutation if needed
+    result.repeat = true
+    result.chrDlm = ' '
+    result.setDlm = { ' ', '\t', '\n' }
+    result.n      = result.setDlm.card
+    return
+  for c in delim:
+    if c in result.setDlm:
+      result.repeat = true
+      continue
+    result.setDlm.incl(c)
+    inc(result.n)
+  if result.n == 1:             #support n==1 test to allow memchr optimization
+    result.chrDlm = delim[0]
+
+proc hash(x: MemSlice): int = 55542
+
+template defSplit[T](slc: T, fs: var seq[MemSlice], n: int, repeat: bool,
+                     sep: untyped, nextSep: untyped, isSep: untyped) {.dirty.} =
+  fs.setLen(if n < 1: 16 else: n)
+  var b   = slc.data
+  var eob = b +! slc.size
+  while repeat and eob -! b > 0 and isSep((cast[cstring](b))[0], sep):
+    b = b +! 1
+    if b == eob: fs.setLen(0); return
+  var e = nextSep(b, sep, (eob -! b).csize)
+  while e != nil:
+    if n < 1:                               #Unbounded msplit
+      if result == fs.len - 1:              #Expand capacity
+        fs.setLen(if fs.len < 512: 2*fs.len else: fs.len + 512)
+    elif result == n - 1:                   #Need 1 more slot for final field
+      break
+    fs[result].data = b
+    fs[result].size = e -! b
+    result += 1
+    while repeat and eob -! e > 0 and isSep((cast[cstring](e))[1], sep):
+      e = e +! 1
+    b = e +! 1
+    if eob -! b <= 0:
+      b = eob
+      break
+    e = nextSep(b, sep, (eob -! b).csize)
+  if not repeat or eob -! b > 0:
+    fs[result].data = b
+    fs[result].size = eob -! b
+    result += 1
+  fs.setLen(result)
+
+proc msplit*(s: MemSlice, fs: var seq[MemSlice], sep=' ', n=0,
+             repeat=false): int =
+  defSplit(s, fs, n, repeat, sep, cmemchr, charEq)
+
+proc split*(s: Splitr, line: MemSlice, cols: var seq[MemSlice],
+            n=0) {.inline.} =
+  discard msplit(line, cols, s.chrDlm, n, s.repeat)
+
+########################################################################
+# Using lines instead of memSlices & split instead of splitr.split seems
+# to mask the arc problem, as does simplifying `Table` to `seq[char]`.
+
+proc load(path: string, delim=" "): Table[MemSlice, seq[char]] =
+  let f = memfiles.open(path)
+  let splitr = initSplitr(delim)
+  var cols: seq[MemSlice] = @[ ]    # re-used seq buffer
+  var nwSq = newSeqOfCap[char](1)   # re-used seq value
+  nwSq.setLen 1
+  for line in memSlices(f, eat='\0'):
+    stderr.write "loop 1a\n"
+    splitr.split(line, cols, 2)
+    stderr.write "loop 1b; cols: ", cols, "\n"
+    let cs = cast[cstring](cols[0].data)
+    stderr.write "loop 1c\n"        #..reports exception here, but
+    nwSq[0] = cs[0]                 #..actually doing out of bounds here
+    stderr.write "loop 1d\n"
+    result[cols[1]] = nwSq
+
+discard load(getAppDir() / "testfile.txt")
diff --git a/tests/arc/tamodule.nim b/tests/arc/tamodule.nim
new file mode 100644
index 000000000..1412e0a7c
--- /dev/null
+++ b/tests/arc/tamodule.nim
@@ -0,0 +1,9 @@
+discard """
+  output: '''
+abcde
+0
+'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+import amodule
diff --git a/tests/arc/tarc_macro.nim b/tests/arc/tarc_macro.nim
new file mode 100644
index 000000000..33ade1da4
--- /dev/null
+++ b/tests/arc/tarc_macro.nim
@@ -0,0 +1,57 @@
+import macros
+
+var destroyCalled = false
+macro bar() =
+  let s = newTree(nnkAccQuoted, ident"=destroy")
+  # let s = ident"`=destroy`" # this would not work
+  result = quote do:
+    type Foo = object
+    # proc `=destroy`(a: var Foo) = destroyCalled = true # this would not work
+    proc `s`(a: var Foo) = destroyCalled = true
+    block:
+      let a = Foo()
+bar()
+doAssert destroyCalled
+
+# custom `op`
+var destroyCalled2 = false
+macro bar(ident) =
+  var x = 1.5
+  result = quote("@") do:
+    type Foo = object
+    let `@ident` = 0 # custom op interpolated symbols need quoted (``)
+    proc `=destroy`(a: var Foo) =
+      doAssert @x == 1.5
+      doAssert compiles(@x == 1.5)
+      let b1 = @[1,2]
+      let b2 = @@[1,2]
+      doAssert $b1 == "[1, 2]"
+      doAssert $b2 == "@[1, 2]"
+      destroyCalled2 = true
+    block:
+      let a = Foo()
+bar(someident)
+doAssert destroyCalled2
+
+proc `&%`(x: int): int = 1
+proc `&%`(x, y: int): int = 2
+
+macro bar2() =
+  var x = 3
+  result = quote("&%") do:
+    var y = &%x # quoting operator
+    doAssert &%&%y == 1 # unary operator => need to escape
+    doAssert y &% y == 2 # binary operator => no need to escape
+    doAssert y == 3
+bar2()
+
+block:
+  macro foo(a: openArray[string] = []): string =
+    echo a # Segfault doesn't happen if this is removed
+    newLit ""
+
+  proc bar(a: static[openArray[string]] = []) =
+    const tmp = foo(a)
+
+  # bug #22909
+  doAssert not compiles(bar())
diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim
new file mode 100644
index 000000000..f2c7de2fc
--- /dev/null
+++ b/tests/arc/tarc_orc.nim
@@ -0,0 +1,186 @@
+discard """
+  targets: "c cpp"
+  matrix: "--mm:arc; --mm:orc"
+"""
+
+block:
+  type
+    PublicKey = array[32, uint8]
+    PrivateKey = array[64, uint8]
+
+  proc ed25519_create_keypair(publicKey: ptr PublicKey; privateKey: ptr PrivateKey) =
+    publicKey[][0] = uint8(88)
+
+  type
+    KeyPair = object
+      public: PublicKey
+      private: PrivateKey
+
+  proc initKeyPair(): KeyPair =
+    ed25519_create_keypair(result.public.addr, result.private.addr)
+
+  let keys = initKeyPair()
+  doAssert keys.public[0] == 88
+
+
+template minIndexByIt: untyped =
+  var other = 3
+  other
+
+proc bug20303() =
+  var hlibs = @["hello", "world", "how", "are", "you"]
+  let res = hlibs[minIndexByIt()]
+  doAssert res == "are"
+
+bug20303()
+
+proc main() = # todo bug with templates
+  block: # bug #11267
+    var a: seq[char] = block: @[]
+    doAssert a == @[]
+    # 2
+    proc b: seq[string] =
+      discard
+      @[]
+    doAssert b() == @[]
+static: main()
+main()
+
+
+type Obj = tuple
+  value: int
+  arr: seq[int]
+
+proc bug(): seq[Obj] =
+  result.add (value: 0, arr: @[])
+  result[^1].value = 1
+  result[^1].arr.add 1
+
+# bug #19990
+let s = bug()
+doAssert s[0] == (value: 1, arr: @[1])
+
+block: # bug #21974
+  type Test[T] = ref object
+      values : seq[T]
+      counter: int
+
+  proc newTest[T](): Test[T] =
+      result         = new(Test[T])
+      result.values  = newSeq[T](16)
+      result.counter = 0
+
+  proc push[T](self: Test[T], value: T) =
+      self.counter += 1
+      if self.counter >= self.values.len:
+          self.values.setLen(self.values.len * 2)
+      self.values[self.counter - 1] = value
+
+  proc pop[T](self: Test[T]): T =
+      result         = self.values[0]
+      self.values[0] = self.values[self.counter - 1] # <--- This line
+      self.counter  -= 1
+
+
+  type X = tuple
+      priority: int
+      value   : string
+
+  var a = newTest[X]()
+  a.push((1, "One"))
+  doAssert a.pop.value == "One"
+
+# bug #21987
+
+type
+  EmbeddedImage* = distinct Image
+  Image = object
+    len: int
+
+proc imageCopy*(image: Image): Image {.nodestroy.}
+
+proc `=destroy`*(x: var Image) =
+  discard
+proc `=sink`*(dest: var Image; source: Image) =
+  `=destroy`(dest)
+  wasMoved(dest)
+
+proc `=dup`*(source: Image): Image {.nodestroy.} =
+  result = imageCopy(source)
+
+proc `=copy`*(dest: var Image; source: Image) =
+  dest = imageCopy(source) # calls =sink implicitly
+
+proc `=destroy`*(x: var EmbeddedImage) = discard
+
+proc `=dup`*(source: EmbeddedImage): EmbeddedImage {.nodestroy.} = source
+
+proc `=copy`*(dest: var EmbeddedImage; source: EmbeddedImage) {.nodestroy.} =
+  dest = source
+
+proc imageCopy*(image: Image): Image =
+  result = image
+
+proc main2 =
+  block:
+    var a = Image(len: 2).EmbeddedImage
+    var b = Image(len: 1).EmbeddedImage
+    b = a
+    doAssert Image(a).len == 2
+    doAssert Image(b).len == 2
+
+  block:
+    var a = Image(len: 2)
+    var b = Image(len: 1)
+    b = a
+    doAssert a.len == 2
+    doAssert b.len == 0
+
+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
new file mode 100644
index 000000000..b4476ef4f
--- /dev/null
+++ b/tests/arc/tarcmisc.nim
@@ -0,0 +1,836 @@
+discard """
+  output: '''
+Destructor for TestTestObj
+=destroy called
+123xyzabc
+destroyed: false
+destroyed: false
+destroyed2: false
+destroyed2: false
+destroying variable: 2
+destroying variable: 1
+whiley ends :(
+1
+(x: "0")
+(x: "1")
+(x: "2")
+(x: "3")
+(x: "4")
+(x: "5")
+(x: "6")
+(x: "7")
+(x: "8")
+(x: "9")
+(x: "10")
+0
+new line before - @['a']
+new line after - @['a']
+finalizer
+aaaaa
+hello
+true
+copying
+123
+42
+@["", "d", ""]
+ok
+destroying variable: 20
+destroying variable: 10
+closed
+'''
+  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
+  MyObj = object
+    len: int
+    data: ptr UncheckedArray[float]
+
+proc `=destroy`*(m: MyObj) =
+
+  echo "=destroy called"
+
+  if m.data != nil:
+    deallocShared(m.data)
+
+type
+  MyObjDistinct = distinct MyObj
+
+proc `=copy`*(m: var MyObj, m2: MyObj) =
+  if m.data == m2.data: return
+  if m.data != nil:
+    `=destroy`(m)
+  m.len = m2.len
+  if m.len > 0:
+    m.data = cast[ptr UncheckedArray[float]](allocShared(sizeof(float) * m.len))
+    copyMem(m.data, m2.data, sizeof(float) * m.len)
+
+
+proc `=sink`*(m: var MyObj, m2: MyObj) =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc newMyObj(len: int): MyObj =
+  result.len = len
+  result.data = cast[ptr UncheckedArray[float]](allocShared(sizeof(float) * len))
+
+proc newMyObjDistinct(len: int): MyObjDistinct =
+  MyObjDistinct(newMyObj(len))
+
+proc fooDistinct =
+  doAssert newMyObjDistinct(2).MyObj.len == 2
+
+fooDistinct()
+
+
+proc takeSink(x: sink string): bool = true
+
+proc b(x: sink string): string =
+  if takeSink(x):
+    return x & "abc"
+
+proc bbb(inp: string) =
+  let y = inp & "xyz"
+  echo b(y)
+
+bbb("123")
+
+
+# bug #13691
+type Variable = ref object
+  value: int
+
+proc `=destroy`(self: typeof(Variable()[])) =
+  echo "destroying variable: ",self.value
+
+proc newVariable(value: int): Variable =
+  result = Variable()
+  result.value = value
+  #echo "creating variable: ",result.value
+
+proc test(count: int) =
+  var v {.global.} = newVariable(10)
+
+  var count = count - 1
+  if count == 0: return
+
+  test(count)
+  echo "destroyed: ", v.isNil
+
+test(3)
+
+proc test2(count: int) =
+  block: #XXX: Fails with block currently
+    var v {.global.} = newVariable(20)
+
+    var count = count - 1
+    if count == 0: return
+
+    test2(count)
+    echo "destroyed2: ", v.isNil
+
+test2(3)
+
+proc whiley =
+  var a = newVariable(1)
+  while true:
+    var b = newVariable(2)
+    if true: raise newException(CatchableError, "test")
+
+try:
+  whiley()
+except CatchableError:
+  echo "whiley ends :("
+
+#------------------------------------------------------------------------------
+# issue #13810
+
+import streams
+
+type
+  A = ref AObj
+  AObj = object of RootObj
+    io: Stream
+  B = ref object of A
+    x: int
+
+proc `=destroy`(x: AObj) =
+  close(x.io)
+  echo "closed"
+
+var x = B(io: newStringStream("thestream"))
+
+
+#------------------------------------------------------------------------------
+# issue #14003
+
+proc cryptCTR*(nonce: var openArray[char]) =
+  nonce[1] = 'A'
+
+proc main() =
+  var nonce1 = "0123456701234567"
+  cryptCTR(nonce1)
+  doAssert(nonce1 == "0A23456701234567")
+  var nonce2 = "01234567"
+  cryptCTR(nonce2.toOpenArray(0, nonce2.len-1))
+  doAssert(nonce2 == "0A234567")
+
+main()
+
+# bug #14079
+import std/algorithm
+
+let
+  n = @["c", "b"]
+  q = @[("c", "2"), ("b", "1")]
+
+doAssert n.sortedByIt(it) == @["b", "c"], "fine"
+doAssert q.sortedByIt(it[0]) == @[("b", "1"), ("c", "2")], "fails under arc"
+
+
+#------------------------------------------------------------------------------
+# issue #14236
+
+type
+  MyType = object
+    a: seq[int]
+
+proc re(x: static[string]): static MyType =
+  MyType()
+
+proc match(inp: string, rg: static MyType) =
+  doAssert rg.a.len == 0
+
+match("ac", re"a(b|c)")
+
+#------------------------------------------------------------------------------
+# issue #14243
+
+type
+  Game* = ref object
+
+proc free*(game: Game) =
+  let a = 5
+
+proc newGame*(): Game =
+  new(result, free)
+
+var game*: Game
+
+
+#------------------------------------------------------------------------------
+# issue #14333
+
+type
+  SimpleLoop = object
+
+  Lsg = object
+    loops: seq[ref SimpleLoop]
+    root: ref SimpleLoop
+
+var lsg: Lsg
+lsg.loops.add lsg.root
+echo lsg.loops.len
+
+# bug #14495
+type
+  Gah = ref object
+    x: string
+
+proc bug14495 =
+  var owners: seq[Gah]
+  for i in 0..10:
+    owners.add Gah(x: $i)
+
+  var x: seq[Gah]
+  for i in 0..10:
+    x.add owners[i]
+
+  for i in 0..100:
+    setLen(x, 0)
+    setLen(x, 10)
+
+  for i in 0..x.len-1:
+    if x[i] != nil:
+      echo x[i][]
+
+  for o in owners:
+    echo o[]
+
+bug14495()
+
+# bug #14396
+type
+  Spinny = ref object
+    t: ref int
+    text: string
+
+proc newSpinny*(): Spinny =
+  Spinny(t: new(int), text: "hello")
+
+proc spinnyLoop(x: ref int, spinny: sink Spinny) =
+  echo x[]
+
+proc start*(spinny: sink Spinny) =
+  spinnyLoop(spinny.t, spinny)
+
+var spinner1 = newSpinny()
+spinner1.start()
+
+# bug #14345
+
+type
+  SimpleLoopB = ref object
+    children: seq[SimpleLoopB]
+    parent: SimpleLoopB
+
+proc addChildLoop(self: SimpleLoopB, loop: SimpleLoopB) =
+  self.children.add loop
+
+proc setParent(self: SimpleLoopB, parent: SimpleLoopB) =
+  self.parent = parent
+  self.parent.addChildLoop(self)
+
+var l = SimpleLoopB()
+l.setParent(l)
+
+
+# bug #14968
+import times
+let currentTime = now().utc
+
+
+# bug #14994
+import sequtils
+var newLine = @['a']
+let indent = newSeq[char]()
+
+echo "new line before - ", newline
+
+newline.insert(indent, 0)
+
+echo "new line after - ", newline
+
+# bug #15044
+
+type
+  Test = ref object
+
+proc test: Test =
+  # broken
+  new(result, proc(x: Test) =
+    echo "finalizer"
+  )
+
+proc tdirectFinalizer =
+  discard test()
+
+tdirectFinalizer()
+
+
+# bug #14480
+proc hello(): int =
+  result = 42
+
+var leaves {.global.} = hello()
+doAssert leaves == 42
+
+# bug #15052
+
+proc mutstrings =
+  var data = "hello"
+  for c in data.mitems():
+    c = 'a'
+  echo data
+
+mutstrings()
+
+# bug #15038
+
+type
+  Machine = ref object
+    hello: string
+
+var machineTypes: seq[tuple[factory: proc(): Machine]]
+
+proc registerMachine(factory: proc(): Machine) =
+  var mCreator = proc(): Machine =
+    result = factory()
+
+  machineTypes.add((factory: mCreator))
+
+proc facproc(): Machine =
+  result = Machine(hello: "hello")
+
+registerMachine(facproc)
+
+proc createMachine =
+  for machine in machineTypes:
+    echo machine.factory().hello
+
+createMachine()
+
+# bug #15122
+
+import tables
+
+type
+  BENodeKind = enum
+    tkBytes,
+    tkList,
+    tkDict
+
+  BENode = object
+    case kind: BENodeKind
+    of tkBytes: strVal: string
+    of tkList: listVal: seq[BENode]
+    of tkDict: dictVal: Table[string, BENode]
+
+var data = {
+  "examples": {
+    "values": BENode(
+      kind: tkList,
+      listVal: @[BENode(kind: tkBytes, strVal: "test")]
+    )
+  }.toTable()
+}.toTable()
+
+# For ARC listVal is empty for some reason
+doAssert data["examples"]["values"].listVal[0].strVal == "test"
+
+
+
+
+###############################################################################
+# bug #15405
+import parsexml
+const test_xml_str = "<A><B>value</B></A>"
+var stream = newStringStream(test_xml_str)
+var xml: XmlParser
+open(xml, stream, "test")
+var xml2 = deepCopy(xml)
+
+proc text_parser(xml: var XmlParser) =
+  var test_passed = false
+  while true:
+    xml.next()
+    case xml.kind
+    of xmlElementStart:
+      if xml.elementName == "B":
+        xml.next()
+        if xml.kind == xmlCharData and xml.charData == "value":
+          test_passed = true
+
+    of xmlEof: break
+    else: discard
+  xml.close()
+  doAssert(test_passed)
+
+text_parser(xml)
+text_parser(xml2)
+
+# bug #15599
+type
+  PixelBuffer = ref object
+
+proc newPixelBuffer(): PixelBuffer =
+  new(result) do (buffer: PixelBuffer):
+    echo "ok"
+
+discard newPixelBuffer()
+
+
+# bug #17199
+
+proc passSeq(data: seq[string]) =
+  # used the system.& proc initially
+  let wat = data & "hello"
+
+proc test2 =
+  let name = @["hello", "world"]
+  passSeq(name)
+  doAssert name == @["hello", "world"]
+
+static: test2() # was buggy
+test2()
+
+proc merge(x: sink seq[string], y: sink string): seq[string] =
+  newSeq(result, x.len + 1)
+  for i in 0..x.len-1:
+    result[i] = move(x[i])
+  result[x.len] = move(y)
+
+proc passSeq2(data: seq[string]) =
+  # used the system.& proc initially
+  let wat = merge(data, "hello")
+
+proc test3 =
+  let name = @["hello", "world"]
+  passSeq2(name)
+  doAssert name == @["hello", "world"]
+
+static: test3() # was buggy
+test3()
+
+# bug #17712
+proc t17712 =
+  var ppv = new int
+  discard @[ppv]
+  var el: ref int
+  el = [ppv][0]
+  echo el != nil
+
+t17712()
+
+# bug #18030
+
+type
+  Foo = object
+    n: int
+
+proc `=copy`(dst: var Foo, src: Foo) =
+  echo "copying"
+  dst.n = src.n
+
+proc `=sink`(dst: var Foo, src: Foo) =
+  echo "sinking"
+  dst.n = src.n
+
+var a: Foo
+
+proc putValue[T](n: T)
+
+proc useForward =
+  putValue(123)
+
+proc putValue[T](n: T) =
+  var b = Foo(n:n)
+  a = b
+  echo b.n
+
+useForward()
+
+
+# bug #17319
+type
+  BrokenObject = ref object
+    brokenType: seq[int]
+
+proc use(obj: BrokenObject) =
+  discard
+
+method testMethod(self: BrokenObject) {.base.} =
+  iterator testMethodIter() {.closure.} =
+    use(self)
+
+  var nameIterVar = testMethodIter
+  nameIterVar()
+
+let mikasa = BrokenObject()
+mikasa.testMethod()
+
+# bug #19205
+type
+  InputSectionBase* = object of RootObj
+    relocations*: seq[int]   # traced reference. string has a similar SIGSEGV.
+  InputSection* = object of InputSectionBase
+
+proc fooz(sec: var InputSectionBase) =
+  if sec of InputSection:  # this line SIGSEGV.
+    echo 42
+
+var sec = create(InputSection)
+sec[] = InputSection(relocations: newSeq[int]())
+fooz sec[]
+
+block:
+  type
+    Data = ref object
+      id: int
+  proc main =
+    var x = Data(id: 99)
+    var y = x
+    x[] = Data(id: 778)[]
+    doAssert y.id == 778
+    doAssert x[].id == 778
+  main()
+
+block: # bug #19857
+  type
+    ValueKind = enum VNull, VFloat, VObject # need 3 elements. Cannot remove VNull or VObject
+
+    Value = object
+      case kind: ValueKind
+      of VFloat: fnum: float
+      of VObject: tab: Table[int, int] # OrderedTable[T, U] also makes it fail.
+                                      # "simpler" types also work though
+      else: discard # VNull can be like this, but VObject must be filled
+
+    # required. Pure proc works
+    FormulaNode = proc(c: OrderedTable[string, int]): Value
+
+  proc toF(v: Value): float =
+    doAssert v.kind == VFloat
+    case v.kind
+    of VFloat: result = v.fnum
+    else: discard
+
+
+  proc foo() =
+    let fuck = initOrderedTable[string, int]()
+    proc cb(fuck: OrderedTable[string, int]): Value =
+                            # works:
+                            #result = Value(kind: VFloat, fnum: fuck["field_that_does_not_exist"].float)
+                            # broken:
+      discard "actuall runs!"
+      let t = fuck["field_that_does_not_exist"]
+      echo "never runs, but we crash after! ", t
+
+    doAssertRaises(KeyError):
+      let fn = FormulaNode(cb)
+      let v = fn(fuck)
+      #echo v
+      let res = v.toF()
+
+  foo()
+
+import std/options
+
+# bug #21592
+type Event* = object
+  code*: string
+
+type App* = ref object of RootObj
+  id*: string
+
+method process*(self: App): Option[Event] {.base.} =
+  raise Exception.new_exception("not impl")
+
+# bug #21617
+type Test2 = ref object of RootObj
+
+method bug(t: Test2): seq[float] {.base.} = discard
+
+block: # bug #22664
+  type
+    ElementKind = enum String, Number
+    Element = object
+      case kind: ElementKind
+      of String:
+        str: string
+      of Number:
+        num: float
+    Calc = ref object
+      stack: seq[Element]
+
+  var calc = new Calc
+
+  calc.stack.add Element(kind: Number, num: 200.0)
+  doAssert $calc.stack == "@[(kind: Number, num: 200.0)]"
+  let calc2 = calc
+  calc2.stack = calc.stack # This nulls out the object in the stack
+  doAssert $calc.stack == "@[(kind: Number, num: 200.0)]"
+  doAssert $calc2.stack == "@[(kind: Number, num: 200.0)]"
+
+block: # bug #19250
+  type
+    Bar[T] = object
+      err: proc(): string
+
+    Foo[T] = object
+      run: proc(): Bar[T]
+
+  proc bar[T](err: proc(): string): Bar[T] =
+    assert not err.isNil
+    Bar[T](err: err)
+
+  proc foo(): Foo[char] = 
+    result.run = proc(): Bar[char] =
+      # works
+      # result = Bar[char](err: proc(): string = "x")
+      # not work
+      result = bar[char](proc(): string = "x")
+
+  proc bug[T](fs: Foo[T]): Foo[T] =
+    result.run = proc(): Bar[T] =
+      let res = fs.run()
+      
+      # works
+      # var errors = @[res.err] 
+      
+      # not work
+      var errors: seq[proc(): string]
+      errors.add res.err
+      
+      return bar[T] do () -> string:
+        for err in errors:
+          result.add res.err()
+
+  doAssert bug(foo()).run().err() == "x"
+
+block: # bug #22259
+  type
+    ProcWrapper = tuple
+      p: proc() {.closure.}
+
+
+  proc f(wrapper: ProcWrapper) =
+    let s = @[wrapper.p]
+    let a = [wrapper.p]
+
+  proc main =
+    # let wrapper: ProcWrapper = ProcWrapper(p: proc {.closure.} = echo 10)
+    let wrapper: ProcWrapper = (p: proc {.closure.} = echo 10)
+    f(wrapper)
+
+  main()
+
+block:
+  block: # bug #22923
+    block:
+      let
+        a: int = 100
+        b: int32 = 200'i32
+
+      let
+        x = arrayWith(a, 8) # compiles
+        y = arrayWith(b, 8) # internal error
+        z = arrayWith(14, 8) # integer literal also results in a crash
+
+      doAssert x == [100, 100, 100, 100, 100, 100, 100, 100]
+      doAssert $y == "[200, 200, 200, 200, 200, 200, 200, 200]"
+      doAssert z == [14, 14, 14, 14, 14, 14, 14, 14]
+
+    block:
+      let a: string = "nim"
+      doAssert arrayWith(a, 3) == ["nim", "nim", "nim"]
+
+      let b: char = 'c'
+      doAssert arrayWith(b, 3) == ['c', 'c', 'c']
+
+      let c: uint = 300'u
+      doAssert $arrayWith(c, 3) == "[300, 300, 300]"
+
+block: # bug #23505
+  type
+    K = object
+    C = object
+      value: ptr K
+
+  proc init(T: type C): C =
+    let tmp = new K
+    C(value: addr tmp[])
+
+  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/tasyncawait.nim b/tests/arc/tasyncawait.nim
new file mode 100644
index 000000000..91a7453cd
--- /dev/null
+++ b/tests/arc/tasyncawait.nim
@@ -0,0 +1,68 @@
+discard """
+  outputsub: "result: 5000"
+  cmd: "nim c --gc:orc $file"
+"""
+
+import asyncdispatch, asyncnet, nativesockets, net, strutils
+from stdtest/netutils import bindAvailablePort
+
+var msgCount = 0
+
+const
+  swarmSize = 50
+  messagesToSend = 100
+
+var clientCount = 0
+
+proc sendMessages(client: AsyncFD) {.async.} =
+  for i in 0 ..< messagesToSend:
+    await send(client, "Message " & $i & "\c\L")
+
+proc launchSwarm(port: Port) {.async.} =
+  for i in 0 ..< swarmSize:
+    var sock = createAsyncNativeSocket()
+
+    await connect(sock, "localhost", port)
+    await sendMessages(sock)
+    closeSocket(sock)
+
+proc readMessages(client: AsyncFD) {.async.} =
+  # wrapping the AsyncFd into a AsyncSocket object
+  var sockObj = newAsyncSocket(client)
+  var (ipaddr, port) = sockObj.getPeerAddr()
+  doAssert ipaddr == "127.0.0.1"
+  (ipaddr, port) = sockObj.getLocalAddr()
+  doAssert ipaddr == "127.0.0.1"
+  while true:
+    var line = await recvLine(sockObj)
+    if line == "":
+      closeSocket(client)
+      clientCount.inc
+      break
+    else:
+      if line.startsWith("Message "):
+        msgCount.inc
+      else:
+        doAssert false
+
+proc createServer(server: AsyncFD) {.async.} =
+  discard server.SocketHandle.listen()
+  while true:
+    asyncCheck readMessages(await accept(server))
+
+proc main =
+  let server = createAsyncNativeSocket()
+  let port = bindAvailablePort(server.SocketHandle)
+  asyncCheck createServer(server)
+  asyncCheck launchSwarm(port)
+  while true:
+    poll()
+    if clientCount == swarmSize: break
+
+let mem = getOccupiedMem()
+main()
+
+doAssert msgCount == swarmSize * messagesToSend
+echo "result: ", msgCount
+GC_fullCollect()
+echo "memory: ", formatSize(getOccupiedMem() - mem)
diff --git a/tests/arc/tasyncleak.nim b/tests/arc/tasyncleak.nim
new file mode 100644
index 000000000..8e3a7b3e7
--- /dev/null
+++ b/tests/arc/tasyncleak.nim
@@ -0,0 +1,21 @@
+discard """
+  outputsub: "(allocCount: 4050, deallocCount: 4048)"
+  cmd: "nim c --gc:orc -d:nimAllocStats $file"
+"""
+
+import asyncdispatch
+# bug #15076
+const
+  # Just to occupy some RAM
+  BigData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+proc doNothing(): Future[void] {.async.} =
+  discard
+
+proc main(): Future[void] {.async.} =
+  for x in 0 .. 1_000:
+    await doNothing()
+
+waitFor main()
+GC_fullCollect()
+echo getAllocStats()
diff --git a/tests/arc/tasyncleak2.nim b/tests/arc/tasyncleak2.nim
new file mode 100644
index 000000000..87d7e73f9
--- /dev/null
+++ b/tests/arc/tasyncleak2.nim
@@ -0,0 +1,88 @@
+discard """
+  output: "success"
+  cmd: "nim c --gc:orc $file"
+"""
+
+# issue #15076
+import deques, strutils, asyncdispatch
+
+proc doNothing(): Future[void] =
+  #[
+  var
+    :env
+    :env_1
+  try:
+    `=destroy`(:env)
+    internalNew(:env)
+    `=sink`(:env.retFuture1, newFuture("doNothing"))
+
+    `=destroy_1`(:env_1)
+    internalNew(:env_1)
+    `=`(:env_1.:up, :env)
+    `=sink_1`(:env.nameIterVar2, (doNothingIter, :env_1))
+
+    (doNothingNimAsyncContinue, :env)()
+    return `=_1`(result, :env.retFuture1)
+  finally:
+    `=destroy`(:env)
+  ]#
+
+  var retFuture = newFuture[void]("doNothing")
+  iterator doNothingIter(): FutureBase {.closure.} =
+    # inspected ARC code: looks correct!
+    block:
+      var qqq = initDeque[string]()
+      for i in 0 .. 1000:
+        qqq.addLast($i)
+    complete(retFuture) # env.up.retFuture1
+
+  var nameIterVar = doNothingIter  # iter_Env -> retFuture ->
+
+  proc doNothingNimAsyncContinue() {.closure.} =
+    # inspected ARC code: looks correct
+    if not nameIterVar.finished:
+      var next_gensym0 = nameIterVar()
+      while (not next_gensym0.isNil) and next_gensym0.finished:
+        next_gensym0 = nameIterVar()
+        if nameIterVar.finished:
+          break
+      if next_gensym0 != nil:
+        {.gcsafe.}:
+          next_gensym0.addCallback cast[proc () {.closure, gcsafe.}](doNothingNimAsyncContinue)
+
+  doNothingNimAsyncContinue()
+  return retFuture
+
+proc main(): Future[void] =
+  template await[T](f_gensym12: Future[T]): auto {.used.} =
+    var internalTmpFuture_gensym12: FutureBase = f_gensym12
+    yield internalTmpFuture_gensym12
+    (cast[typeof(f_gensym12)](internalTmpFuture_gensym12)).read()
+
+  var retFuture = newFuture[void]("main")
+  iterator mainIter(): FutureBase {.closure.} =
+    block:
+      for x in 0 .. 1000:
+        await doNothing()
+    complete(retFuture)
+
+  var nameIterVar_gensym11 = mainIter
+  proc mainNimAsyncContinue() {.closure.} =
+    if not nameIterVar_gensym11.finished:
+      var next_gensym11 = unown nameIterVar_gensym11()
+      while (not next_gensym11.isNil) and next_gensym11.finished:
+        next_gensym11 = unown nameIterVar_gensym11()
+        if nameIterVar_gensym11.finished:
+          break
+      if next_gensym11 != nil:
+        {.gcsafe.}:
+          next_gensym11.addCallback cast[proc () {.closure, gcsafe.}](mainNimAsyncContinue)
+
+  mainNimAsyncContinue()
+  return retFuture
+
+for i in 0..9:
+  waitFor main()
+  GC_fullCollect()
+  doAssert getOccupiedMem() < 1024
+echo "success"
diff --git a/tests/arc/tasyncleak3.nim b/tests/arc/tasyncleak3.nim
new file mode 100644
index 000000000..21e963b7f
--- /dev/null
+++ b/tests/arc/tasyncleak3.nim
@@ -0,0 +1,47 @@
+discard """
+  cmd: "nim c --gc:orc -d:useMalloc $file"
+  output: "true"
+  valgrind: "true"
+"""
+
+import strutils
+
+type
+  FutureBase* = ref object of RootObj  ## Untyped future.
+    finished: bool
+    stackTrace: seq[StackTraceEntry] ## For debugging purposes only.
+
+proc newFuture*(): FutureBase =
+  new(result)
+  result.finished = false
+  result.stackTrace = getStackTraceEntries()
+
+type
+  PDispatcher {.acyclic.} = ref object
+
+var gDisp: PDispatcher
+new gDisp
+
+proc testCompletion(): FutureBase =
+  var retFuture = newFuture()
+
+  iterator testCompletionIter(): FutureBase {.closure.} =
+    retFuture.finished = true
+    when not defined(nobug):
+      let disp = gDisp # even worse memory consumption this way...
+
+  var nameIterVar = testCompletionIter
+  proc testCompletionNimAsyncContinue() {.closure.} =
+    if not nameIterVar.finished:
+      discard nameIterVar()
+  testCompletionNimAsyncContinue()
+  return retFuture
+
+proc main =
+  for i in 0..10_000:
+    discard testCompletion()
+
+main()
+
+GC_fullCollect()
+echo getOccupiedMem() < 1024
diff --git a/tests/arc/tasyncleak4.nim b/tests/arc/tasyncleak4.nim
new file mode 100644
index 000000000..58cd7f0b7
--- /dev/null
+++ b/tests/arc/tasyncleak4.nim
@@ -0,0 +1,21 @@
+discard """
+  cmd: "nim c --gc:orc -d:useMalloc $file"
+  output: '''ok'''
+  valgrind: "leaks"
+"""
+
+# bug #15076
+import asyncdispatch
+
+var futures: seq[Future[void]]
+
+for i in 1..20:
+  futures.add sleepAsync 1
+  futures.add sleepAsync 1
+
+  futures.all.waitFor()
+  futures.setLen 0
+
+setGlobalDispatcher nil
+GC_fullCollect()
+echo "ok"
diff --git a/tests/arc/tasyncorc.nim b/tests/arc/tasyncorc.nim
new file mode 100644
index 000000000..63703b559
--- /dev/null
+++ b/tests/arc/tasyncorc.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''230000'''
+  cmd: '''nim c --gc:orc -d:useMalloc $file'''
+  valgrind: "leaks"
+"""
+
+# bug #14402
+
+import asynchttpserver, asyncdispatch, httpclient, strutils
+
+proc cb(req: Request) {.async, gcsafe.} =
+  const html = " ".repeat(230000)
+  await req.respond(Http200, html)
+
+var server = newAsyncHttpServer()
+asyncCheck server.serve(Port(8080), cb)
+
+proc test {.async.} =
+  var
+    client = newAsyncHttpClient()
+    resp = await client.get("http://localhost:8080")
+
+  let x = (await resp.body).len
+  echo x # crash
+
+waitFor test()
diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim
new file mode 100644
index 000000000..3499f5c1e
--- /dev/null
+++ b/tests/arc/tcaseobj.nim
@@ -0,0 +1,366 @@
+discard """
+  valgrind: true
+  cmd: "nim c --gc:arc -d:useMalloc $file"
+  output: '''myobj destroyed
+myobj destroyed
+myobj destroyed
+A
+B
+begin
+end
+prevented
+(ok: true, value: "ok")
+@[(kind: P, pChildren: @[])]
+myobj destroyed
+'''
+"""
+
+# bug #13102
+
+type
+  D = ref object
+  R = object
+    case o: bool
+    of false:
+      discard
+    of true:
+      field: D
+
+iterator things(): R =
+  when true:
+    var
+      unit = D()
+    while true:
+      yield R(o: true, field: unit)
+  else:
+    while true:
+      var
+        unit = D()
+      yield R(o: true, field: unit)
+
+proc main =
+  var i = 0
+  for item in things():
+    discard item.field
+    inc i
+    if i == 2: break
+
+main()
+
+# bug #13149
+
+type
+  TMyObj = object
+    p: pointer
+    len: int
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil:
+    dealloc o.p
+    o.p = nil
+    echo "myobj destroyed"
+
+proc `=copy`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = alloc(src.len)
+  dst.len = src.len
+
+proc `=sink`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = src.p
+  dst.len = src.len
+
+type
+  TObjKind = enum Z, A, B
+  TCaseObj = object
+    case kind: TObjKind
+    of Z: discard
+    of A:
+      x1: int # this int plays important role
+      x2: TMyObj
+    of B:
+      y: TMyObj
+
+proc testSinks: TCaseObj =
+  result = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
+  result = TCaseObj(kind: B, y: TMyObj(len: 3, p: alloc(3)))
+
+proc use(x: TCaseObj) = discard
+
+proc testCopies(i: int) =
+  var a: array[2, TCaseObj]
+  a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
+  a[i+1] = a[i] # copy, cannot move
+  use(a[i])
+
+let x1 = testSinks()
+testCopies(0)
+
+# bug #12957
+
+type
+  PegKind* = enum
+    pkCharChoice,
+    pkSequence
+  Peg* = object ## type that represents a PEG
+    case kind: PegKind
+    of pkCharChoice: charChoice: ref set[char]
+    else: discard
+    sons: seq[Peg]
+
+proc charSet*(s: set[char]): Peg =
+  ## constructs a PEG from a character set `s`
+  result = Peg(kind: pkCharChoice)
+  new(result.charChoice)
+  result.charChoice[] = s
+
+proc len(a: Peg): int {.inline.} = return a.sons.len
+proc myadd(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
+
+proc sequence*(a: openArray[Peg]): Peg =
+  result = Peg(kind: pkSequence, sons: @[])
+  when false:
+    #works too:
+    result.myadd(a[0])
+    result.myadd(a[1])
+  for x in items(a):
+    # works:
+    #result.sons.add(x)
+    # fails:
+    result.myadd x
+  if result.len == 1:
+    result = result.sons[0] # this must not move!
+
+when true:
+  # bug #12957
+
+  proc p =
+    echo "A"
+    let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'}),
+              charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})])
+    echo "B"
+  p()
+
+  proc testSubObjAssignment =
+    echo "begin"
+    # There must be extactly one element in the array constructor!
+    let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'})])
+    echo "end"
+  testSubObjAssignment()
+
+
+#------------------------------------------------
+
+type
+  MyObject = object
+    x1: string
+    case kind1: bool
+      of false: y1: string
+      of true:
+          y2: seq[string]
+          case kind2: bool
+              of true: z1: string
+              of false:
+                z2: seq[string]
+                flag: bool
+    x2: string
+
+proc test_myobject =
+  var x: MyObject
+  x.x1 = "x1"
+  x.x2 = "x2"
+  x.y1 = "ljhkjhkjh"
+  {.cast(uncheckedAssign).}:
+    x.kind1 = true
+  x.y2 = @["1", "2"]
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
+  x.z1 = "yes"
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+  x.z2 = @["1", "2"]
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
+  x.z1 = "yes"
+  x.kind2 = true # should be no effect
+  doAssert(x.z1 == "yes")
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind1 = x.kind2 # support self assignment with effect
+
+  try:
+    x.kind1 = x.flag # flag is not accesible
+  except FieldDefect:
+    echo "prevented"
+
+  doAssert(x.x1 == "x1")
+  doAssert(x.x2 == "x2")
+
+
+test_myobject()
+
+
+#------------------------------------------------
+# bug #14244
+
+type
+  RocksDBResult*[T] = object
+    case ok*: bool
+    of true:
+      value*: T
+    else:
+      error*: string
+
+proc init(): RocksDBResult[string] =
+  {.cast(uncheckedAssign).}:
+    result.ok = true
+    result.value = "ok"
+
+echo init()
+
+
+#------------------------------------------------
+# bug #14312
+
+type MyObj = object
+  case kind: bool
+    of false: x0: int # would work with a type like seq[int]; value would be reset
+    of true: x1: string
+
+var a = MyObj(kind: false, x0: 1234)
+{.cast(uncheckedAssign).}:
+  a.kind = true
+doAssert(a.x1 == "")
+
+block:
+  # bug #15532
+  type Kind = enum
+    k0, k1
+
+  type Foo = object
+    y: int
+    case kind: Kind
+    of k0: x0: int
+    of k1: x1: int
+
+  const j0 = Foo(y: 1, kind: k0, x0: 2)
+  const j1 = Foo(y: 1, kind: k1, x1: 2)
+
+  doAssert j0.y == 1
+  doAssert j0.kind == k0
+  doAssert j1.kind == k1
+
+  doAssert j1.x1 == 2
+  doAssert j0.x0 == 2
+
+# ------------------------------------
+# bug #20305
+
+type
+  ContentNodeKind = enum
+    P, Br, Text
+  ContentNode = object
+    case kind: ContentNodeKind
+    of P: pChildren: seq[ContentNode]
+    of Br: discard
+    of Text: textStr: string
+
+proc bug20305 =
+  var x = ContentNode(kind: P, pChildren: @[
+    ContentNode(kind: P, pChildren: @[ContentNode(kind: Text, textStr: "brrr")])
+  ])
+  x.pChildren.add ContentNode(kind: Br)
+  x.pChildren.del(0)
+  {.cast(uncheckedAssign).}:
+    x.pChildren[0].kind = P
+  echo x.pChildren
+
+bug20305()
+
+# bug #21023
+block:
+  block:
+    type
+      MGErrorKind = enum
+        mgeUnexpected, mgeNotFound
+
+    type Foo = object
+      kind: MGErrorKind
+      ex: Exception
+
+    type Boo = object
+      a: seq[int]
+
+    type
+      Result2 = object
+        case o: bool
+        of false:
+          e: Foo
+        of true:
+          v: Boo
+
+    proc startSessionSync(): Result2 =
+      return Result2(o: true)
+
+    proc mainSync =
+      let ff = startSessionSync()
+      doAssert ff.o == true
+
+    mainSync()
+
+  block:
+    type
+      MGErrorKind = enum
+        mgeUnexpected, mgeNotFound
+
+    type Foo = object
+      kind: MGErrorKind
+      ex: Exception
+
+    type Boo = object
+      a: seq[int]
+
+    type
+      Result2 = object
+        case o: bool
+        of false:
+          e: Foo
+        of true:
+          v: Boo
+          s: int
+
+    proc startSessionSync(): Result2 =
+      return Result2(o: true, s: 12)
+
+    proc mainSync =
+      let ff = startSessionSync()
+      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/tcaseobjcopy.nim b/tests/arc/tcaseobjcopy.nim
new file mode 100644
index 000000000..fb26a4973
--- /dev/null
+++ b/tests/arc/tcaseobjcopy.nim
@@ -0,0 +1,253 @@
+discard """
+  valgrind: true
+  cmd: "nim c --gc:arc -d:useMalloc $file"
+  output: '''myobj destroyed
+myobj destroyed
+myobj destroyed
+A
+B
+begin
+end
+prevented
+(ok: true, value: "ok")
+myobj destroyed
+'''
+"""
+
+# bug #13102
+
+type
+  D = ref object
+  R = object
+    case o: bool
+    of false:
+      discard
+    of true:
+      field: D
+
+iterator things(): R =
+  when true:
+    var
+      unit = D()
+    while true:
+      yield R(o: true, field: unit)
+  else:
+    while true:
+      var
+        unit = D()
+      yield R(o: true, field: unit)
+
+proc main =
+  var i = 0
+  for item in things():
+    discard item.field
+    inc i
+    if i == 2: break
+
+main()
+
+# bug #13149
+
+type
+  TMyObj = object
+    p: pointer
+    len: int
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil:
+    dealloc o.p
+    o.p = nil
+    echo "myobj destroyed"
+
+proc `=copy`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = alloc(src.len)
+  dst.len = src.len
+
+proc `=sink`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = src.p
+  dst.len = src.len
+
+type
+  TObjKind = enum Z, A, B
+  TCaseObj = object
+    case kind: TObjKind
+    of Z: discard
+    of A:
+      x1: int # this int plays important role
+      x2: TMyObj
+    of B:
+      y: TMyObj
+
+proc testSinks: TCaseObj =
+  result = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
+  result = TCaseObj(kind: B, y: TMyObj(len: 3, p: alloc(3)))
+
+proc use(x: TCaseObj) = discard
+
+proc testCopies(i: int) =
+  var a: array[2, TCaseObj]
+  a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
+  a[i+1] = a[i] # copy, cannot move
+  use(a[i])
+
+let x1 = testSinks()
+testCopies(0)
+
+# bug #12957
+
+type
+  PegKind* = enum
+    pkCharChoice,
+    pkSequence
+  Peg* = object ## type that represents a PEG
+    case kind: PegKind
+    of pkCharChoice: charChoice: ref set[char]
+    else: discard
+    sons: seq[Peg]
+
+proc charSet*(s: set[char]): Peg =
+  ## constructs a PEG from a character set `s`
+  result = Peg(kind: pkCharChoice)
+  new(result.charChoice)
+  result.charChoice[] = s
+
+proc len(a: Peg): int {.inline.} = return a.sons.len
+proc myadd(d: var Peg, s: Peg) {.inline.} = add(d.sons, s)
+
+proc sequence*(a: openArray[Peg]): Peg =
+  result = Peg(kind: pkSequence, sons: @[])
+  when false:
+    #works too:
+    result.myadd(a[0])
+    result.myadd(a[1])
+  for x in items(a):
+    # works:
+    #result.sons.add(x)
+    # fails:
+    result.myadd x
+  if result.len == 1:
+    result = result.sons[0] # this must not move!
+
+when true:
+  # bug #12957
+
+  proc p =
+    echo "A"
+    let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'}),
+              charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})])
+    echo "B"
+  p()
+
+  proc testSubObjAssignment =
+    echo "begin"
+    # There must be extactly one element in the array constructor!
+    let x = sequence([charSet({'a'..'z', 'A'..'Z', '_'})])
+    echo "end"
+  testSubObjAssignment()
+
+
+#------------------------------------------------
+
+type
+  MyObject = object
+    x1: string
+    case kind1: bool
+      of false: y1: string
+      of true:
+          y2: seq[string]
+          case kind2: bool
+              of true: z1: string
+              of false:
+                z2: seq[string]
+                flag: bool
+    x2: string
+
+proc test_myobject =
+  var x: MyObject
+  x.x1 = "x1"
+  x.x2 = "x2"
+  x.y1 = "ljhkjhkjh"
+  {.cast(uncheckedAssign).}:
+    x.kind1 = true
+  x.y2 = @["1", "2"]
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
+  x.z1 = "yes"
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+  x.z2 = @["1", "2"]
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
+  x.z1 = "yes"
+  x.kind2 = true # should be no effect
+  doAssert(x.z1 == "yes")
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+    x.kind1 = x.kind2 # support self assignment with effect
+
+  try:
+    x.kind1 = x.flag # flag is not accesible
+  except FieldDefect:
+    echo "prevented"
+
+  doAssert(x.x1 == "x1")
+  doAssert(x.x2 == "x2")
+
+
+test_myobject()
+
+
+#------------------------------------------------
+# bug #14244
+
+type
+  RocksDBResult*[T] = object
+    case ok*: bool
+    of true:
+      value*: T
+    else:
+      error*: string
+
+proc init(): RocksDBResult[string] =
+  {.cast(uncheckedAssign).}:
+    result.ok = true
+  result.value = "ok"
+
+echo init()
+
+
+#------------------------------------------------
+# bug #14312
+
+type MyObj = object
+  case kind: bool
+    of false: x0: int # would work with a type like seq[int]; value would be reset
+    of true: x1: string
+
+var a = MyObj(kind: false, x0: 1234)
+{.cast(uncheckedAssign).}:
+  a.kind = true
+doAssert(a.x1 == "")
+
+block:
+  # bug #15532
+  type Kind = enum
+    k0, k1
+
+  type Foo = object
+    y: int
+    case kind: Kind
+    of k0: x0: int
+    of k1: x1: int
+
+  const j0 = Foo(y: 1, kind: k0, x0: 2)
+  const j1 = Foo(y: 1, kind: k1, x1: 2)
+
+  doAssert j0.y == 1
+  doAssert j0.kind == k0
+  doAssert j1.kind == k1
+
+  doAssert j1.x1 == 2
+  doAssert j0.x0 == 2
diff --git a/tests/arc/tclosureiter.nim b/tests/arc/tclosureiter.nim
new file mode 100644
index 000000000..e4a2ceac6
--- /dev/null
+++ b/tests/arc/tclosureiter.nim
@@ -0,0 +1,36 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
+  output: '''(allocCount: 102, deallocCount: 102)'''
+"""
+
+type
+  FutureBase = ref object
+    someData: string
+
+const
+  # Just to occupy some RAM
+  BigData = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+
+iterator mainIter(): FutureBase {.closure.} =
+  for x in 0 .. 100:
+    var internalTmpFuture = FutureBase(someData: BigData)
+    yield internalTmpFuture
+
+proc main() =
+  var nameIterVar = mainIter
+  var next = nameIterVar()
+  while not isNil(next):
+    next = nameIterVar()
+    if not isNil(next):
+      doAssert next.someData.len == 97
+    # GC_unref(next)
+    # If you uncomment the GC_ref above,
+    # the program basically uses no memory after the run.
+    # but crashes with refc, which might indicate
+    # that arc/orc simply never frees the result of "next"?
+    if finished(nameIterVar):
+      break
+
+main()
+GC_fullCollect()
+echo getAllocStats()
diff --git a/tests/arc/tcomputedgoto.nim b/tests/arc/tcomputedgoto.nim
new file mode 100644
index 000000000..07487684a
--- /dev/null
+++ b/tests/arc/tcomputedgoto.nim
@@ -0,0 +1,44 @@
+discard """
+  cmd: '''nim c --mm:arc $file'''
+  output: '''
+2
+2
+destroyed
+'''
+"""
+
+type
+  ObjWithDestructor = object
+    a: int
+proc `=destroy`(self: ObjWithDestructor) =
+  echo "destroyed"
+
+proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) =
+  echo "copied"
+
+proc test(a: range[0..1], arg: ObjWithDestructor) =
+  var iteration = 0
+  while true:
+    {.computedGoto.}
+
+    let
+      b = int(a) * 2
+      c = a
+      d = arg
+      e = arg
+
+    discard c
+    discard d
+    discard e
+
+    inc iteration
+
+    case a
+    of 0:
+      assert false
+    of 1:
+      echo b
+      if iteration == 2:
+        break
+
+test(1, ObjWithDestructor())
diff --git a/tests/arc/tcomputedgotocopy.nim b/tests/arc/tcomputedgotocopy.nim
new file mode 100644
index 000000000..07487684a
--- /dev/null
+++ b/tests/arc/tcomputedgotocopy.nim
@@ -0,0 +1,44 @@
+discard """
+  cmd: '''nim c --mm:arc $file'''
+  output: '''
+2
+2
+destroyed
+'''
+"""
+
+type
+  ObjWithDestructor = object
+    a: int
+proc `=destroy`(self: ObjWithDestructor) =
+  echo "destroyed"
+
+proc `=copy`(self: var ObjWithDestructor, other: ObjWithDestructor) =
+  echo "copied"
+
+proc test(a: range[0..1], arg: ObjWithDestructor) =
+  var iteration = 0
+  while true:
+    {.computedGoto.}
+
+    let
+      b = int(a) * 2
+      c = a
+      d = arg
+      e = arg
+
+    discard c
+    discard d
+    discard e
+
+    inc iteration
+
+    case a
+    of 0:
+      assert false
+    of 1:
+      echo b
+      if iteration == 2:
+        break
+
+test(1, ObjWithDestructor())
diff --git a/tests/arc/tconst_to_sink.nim b/tests/arc/tconst_to_sink.nim
new file mode 100644
index 000000000..25f659341
--- /dev/null
+++ b/tests/arc/tconst_to_sink.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''@[(s1: "333", s2: ""), (s1: "abc", s2: "def"), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "3x", s2: ""), (s1: "lastone", s2: "")]'''
+  matrix: "--gc:arc"
+  targets: "c cpp"
+"""
+
+# bug #13240
+
+type
+  Thing = object
+    s1: string
+    s2: string
+
+var box: seq[Thing]
+
+const c = [Thing(s1: "333"), Thing(s1: "abc", s2: "def")]
+
+for i in 0..high(c):
+  box.add c[i]
+
+for i in 0..3:
+  box.add Thing(s1: "3x")
+
+box.add Thing(s1: "lastone")
+
+echo box
diff --git a/tests/arc/tcontrolflow.nim b/tests/arc/tcontrolflow.nim
new file mode 100644
index 000000000..dbc115903
--- /dev/null
+++ b/tests/arc/tcontrolflow.nim
@@ -0,0 +1,118 @@
+discard """
+  output: '''begin A
+elif
+end A
+destroyed
+begin false
+if
+end false
+destroyed
+begin true
+if
+end true
+7
+##index 2 not in 0 .. 1##
+true
+'''
+  cmd: "nim c --gc:arc -d:danger $file"
+"""
+# we use the -d:danger switch to detect uninitialized stack
+# slots more reliably (there shouldn't be any, of course).
+
+type
+  Foo = object
+    id: int
+
+proc `=destroy`(x: var Foo) =
+  if x.id != 0:
+    echo "destroyed"
+    x.id = 0
+
+proc construct(): Foo = Foo(id: 3)
+
+proc elifIsEasy(cond: bool) =
+  echo "begin A"
+  if cond:
+    echo "if"
+  elif construct().id == 3:
+    echo "elif"
+  else:
+    echo "else"
+  echo "end A"
+
+elifIsEasy(false)
+
+
+proc orIsHard(cond: bool) =
+  echo "begin ", cond
+  if cond or construct().id == 3:
+    echo "if"
+  else:
+    echo "else"
+  echo "end ", cond
+
+orIsHard(false)
+orIsHard(true)
+
+type
+  Control = ref object
+    x: int
+
+  MouseEvent = ref object
+    control: Control
+    button: int
+
+proc run(data: Control) =
+  var evt = MouseEvent(button: 1)
+  evt.control = data
+  if evt.button == 1:
+    discard
+  else:
+    return
+
+  echo data.x
+
+var c = Control(x: 7)
+
+run(c)
+
+proc sysFatal(exceptn: typedesc, message: string) {.inline.} =
+  var buf = newStringOfCap(200)
+  add(buf, "##")
+  add(buf, message)
+  add(buf, "##")
+  echo buf
+
+proc ifexpr(i, a, b: int) {.compilerproc, noinline.} =
+  sysFatal(IndexDefect,
+    if b < a: "index out of bounds, the container is empty"
+    else: "index " & $i & " not in " & $a & " .. " & $b)
+
+ifexpr(2, 0, 1)
+
+# bug #14899
+template toSeq(): untyped =
+  block:
+    var result = @[1]
+    result
+
+proc clItems(s: seq[int]) =
+  assert s.len == 1
+
+proc escapeCheck =
+  clItems(toSeq())
+
+escapeCheck()
+
+# bug #14900
+
+proc seqsEqual(a, b: string): bool =
+  if false:
+    false
+  else:
+    (var result1 = a; result1) == (var result2 = b; result2)
+
+# can be const or var too
+let expected = "hello"
+
+echo seqsEqual(expected, expected)
diff --git a/tests/arc/tcursor_field_obj_constr.nim b/tests/arc/tcursor_field_obj_constr.nim
new file mode 100644
index 000000000..b87f734bd
--- /dev/null
+++ b/tests/arc/tcursor_field_obj_constr.nim
@@ -0,0 +1,44 @@
+discard """
+  output: '''a
+b
+c'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #18469
+
+type
+  Edge = object
+    neighbor {.cursor.}: Node
+
+  NodeObj = object
+    neighbors: seq[Edge]
+    label: string
+    visited: bool
+  Node = ref NodeObj
+
+  Graph = object
+    nodes: seq[Node]
+
+proc `=destroy`(x: var NodeObj) =
+  echo x.label
+  `=destroy`(x.neighbors)
+  `=destroy`(x.label)
+
+proc addNode(self: var Graph; label: string): Node =
+  self.nodes.add(Node(label: label))
+  result = self.nodes[^1]
+
+proc addEdge(self: Graph; source, neighbor: Node) =
+  source.neighbors.add(Edge(neighbor: neighbor))
+
+proc main =
+  var graph: Graph
+  let nodeA = graph.addNode("a")
+  let nodeB = graph.addNode("b")
+  let nodeC = graph.addNode("c")
+
+  graph.addEdge(nodeA, neighbor = nodeB)
+  graph.addEdge(nodeA, neighbor = nodeC)
+
+main()
diff --git a/tests/arc/tcursor_on_localvar.nim b/tests/arc/tcursor_on_localvar.nim
new file mode 100644
index 000000000..0f53c5efa
--- /dev/null
+++ b/tests/arc/tcursor_on_localvar.nim
@@ -0,0 +1,161 @@
+discard """
+  output: '''Section: common
+  Param: Floats1
+Section: local
+  Param: Str
+  Param: Bool
+  Param: Floats2
+destroy Foo
+destroy Foo
+'''
+  cmd: '''nim c --gc:arc $file'''
+"""
+
+# bug #15325
+
+import tables
+import strutils
+
+const defaultSection = "***"
+
+type
+    Config* = ref object
+        table: OrderedTableRef[string, OrderedTable[string, string]]
+
+# ----------------------------------------------------------------------------------------------------------------------
+proc newConfig*(): Config =
+    result       = new(Config)
+    result.table = newOrderedTable[string, OrderedTable[string, string]]()
+
+# ----------------------------------------------------------------------------------------------------------------------
+proc add*(self: Config, param, value, section: string) {.nosinks.} =
+    let s = if section == "": defaultSection else: section
+
+    if not self.table.contains(s):
+        self.table[s] = initOrderedTable[string, string]()
+
+    self.table[s][param] = value
+
+# ----------------------------------------------------------------------------------------------------------------------
+proc sections*(self: Config): seq[string] =
+    for i in self.table.keys:
+        let s = if i == defaultSection: "" else: i
+        result.add(s)
+
+# ----------------------------------------------------------------------------------------------------------------------
+proc params*(self: Config, section: string): seq[string] =
+    let s = if section == "": defaultSection else: section
+
+    if self.table.contains(s):
+        for i in self.table[s].keys:
+            result.add(i)
+
+# ----------------------------------------------------------------------------------------------------------------------
+proc extract*(str, start, finish: string): string =
+    let startPos = str.find(start)
+
+    if startPos < 0:
+        return ""
+
+    let endPos = str.find(finish, startPos)
+
+    if endPos < 0:
+        return ""
+
+    return str[startPos + start.len() ..< endPos]
+
+# ----------------------------------------------------------------------------------------------------------------------
+proc loadString*(self: Config, text: string): tuple[valid: bool, errorInLine: int] {.discardable.} =
+    self.table.clear()
+
+    var data = ""
+
+    data = text
+
+    var
+        actualSection = ""
+        lineCount     = 0
+
+    for i in splitLines(data):
+        lineCount += 1
+
+        var line = strip(i)
+
+        if line.len() == 0:
+            continue
+
+        if line[0] == '#' or line[0] == ';':
+            continue
+
+        if line[0] == '[':
+            let section = strip(extract(line, "[", "]"))
+
+            if section.len() != 0:
+                actualSection = section
+            else:
+                self.table.clear()
+                return (false, lineCount)
+        else:
+            let equal = find(line, '=')
+
+            if equal <= 0:
+                self.table.clear()
+                return (false, lineCount)
+            else:
+                let
+                    param = strip(line[0 .. equal - 1])
+                    value = strip(line[equal + 1 .. ^1])
+
+                if param.len() == 0:
+                    self.table.clear()
+                    return (false, lineCount)
+                else:
+                    self.add(param, value, actualSection)
+
+    return (true, 0)
+
+# ----------------------------------------------------------------------------------------------------------------------
+when isMainModule:
+    var cfg = newConfig()
+
+    cfg.loadString("[common]\nFloats1 = 1,2,3\n[local]\nStr = \"String...\"\nBool = true\nFloats2 = 4, 5, 6\n")
+
+    for s in cfg.sections():
+        echo "Section: " & s
+
+        for p in cfg.params(s):
+            echo "  Param: " & p
+
+# bug #16437
+
+type
+  Foo = object
+  FooRef = ref Foo
+
+  Bar = ref object
+    f: FooRef
+
+proc `=destroy`(o: var Foo) =
+  echo "destroy Foo"
+
+proc testMe(x: Bar) =
+  var c = (if x != nil: x.f else: nil)
+  assert c != nil
+
+proc main =
+  var b = Bar(f: FooRef())
+  testMe(b)
+
+main()
+
+proc testMe2(x: Bar) =
+  var c: FooRef
+  c = (if x != nil: x.f else: nil)
+  assert c != nil
+
+proc main2 =
+  var b = Bar(f: FooRef())
+  testMe2(b)
+
+main2()
+
diff --git a/tests/arc/tcursorloop.nim b/tests/arc/tcursorloop.nim
new file mode 100644
index 000000000..a37a6a036
--- /dev/null
+++ b/tests/arc/tcursorloop.nim
@@ -0,0 +1,45 @@
+discard """
+  cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file'''
+  nimout: '''
+--expandArc: traverse
+
+var
+  it
+  jt_cursor
+try:
+  `=copy`(it, root)
+  block :tmp:
+    while (
+      not (it == nil)):
+      if true:
+        echo [it.s]
+        `=copy`(it, it.ri)
+  jt_cursor = root
+  if (
+    not (jt_cursor == nil)):
+    echo [jt_cursor.s]
+    jt_cursor = jt_cursor.ri
+finally:
+  `=destroy`(it)
+-- end of expandArc ------------------------
+'''
+"""
+
+type
+  Node = ref object
+    le, ri: Node
+    s: string
+
+proc traverse(root: Node) =
+  var it = root
+  while it != nil:
+    if true:
+      echo it.s
+      it = it.ri
+
+  var jt = root
+  if jt != nil:
+    echo jt.s
+    jt = jt.ri
+
+traverse(nil)
diff --git a/tests/arc/tcustomtrace.nim b/tests/arc/tcustomtrace.nim
new file mode 100644
index 000000000..5e0ecfb24
--- /dev/null
+++ b/tests/arc/tcustomtrace.nim
@@ -0,0 +1,240 @@
+discard """
+  outputsub: '''1
+2
+3
+4
+5
+6
+89
+90
+90
+0 0 1
+0 1 2
+0 2 3
+1 0 4
+1 1 5
+1 2 6
+1 3 7
+after 6 6
+MEM 0'''
+joinable: false
+  cmd: "nim c --gc:orc -d:useMalloc $file"
+  valgrind: "true"
+"""
+
+import typetraits
+
+type
+  myseq*[T] = object
+    len, cap: int
+    data: ptr UncheckedArray[T]
+
+# XXX make code memory safe for overflows in '*'
+var
+  allocCount, deallocCount: int
+
+proc `=destroy`*[T](x: var myseq[T]) =
+  if x.data != nil:
+    when not supportsCopyMem(T):
+      for i in 0..<x.len: `=destroy`(x[i])
+    dealloc(x.data)
+    inc deallocCount
+    x.data = nil
+    x.len = 0
+    x.cap = 0
+
+proc `=copy`*[T](a: var myseq[T]; b: myseq[T]) =
+  if a.data == b.data: return
+  if a.data != nil:
+    `=destroy`(a)
+    #dealloc(a.data)
+    #inc deallocCount
+    #a.data = nil
+  a.len = b.len
+  a.cap = b.cap
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(a.cap * sizeof(T)))
+    inc allocCount
+    when supportsCopyMem(T):
+      copyMem(a.data, b.data, a.cap * sizeof(T))
+    else:
+      for i in 0..<a.len:
+        a.data[i] = b.data[i]
+
+proc `=sink`*[T](a: var myseq[T]; b: myseq[T]) =
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    inc deallocCount
+  a.len = b.len
+  a.cap = b.cap
+  a.data = b.data
+
+proc `=trace`*[T](x: var myseq[T]; env: pointer) =
+  if x.data != nil:
+    for i in 0..<x.len: `=trace`(x[i], env)
+
+proc resize[T](s: var myseq[T]) =
+  let oldCap = s.cap
+  if oldCap == 0: s.cap = 8
+  else: s.cap = (s.cap * 3) shr 1
+  if s.data == nil: inc allocCount
+  s.data = cast[typeof(s.data)](realloc0(s.data, oldCap * sizeof(T), s.cap * sizeof(T)))
+
+proc reserveSlot[T](x: var myseq[T]): ptr T =
+  if x.len >= x.cap: resize(x)
+  result = addr(x.data[x.len])
+  inc x.len
+
+template add*[T](x: var myseq[T]; y: T) =
+  reserveSlot(x)[] = y
+
+proc shrink*[T](x: var myseq[T]; newLen: int) =
+  assert newLen <= x.len
+  assert newLen >= 0
+  when not supportsCopyMem(T):
+    for i in countdown(x.len - 1, newLen - 1):
+      `=destroy`(x.data[i])
+  x.len = newLen
+
+proc grow*[T](x: var myseq[T]; newLen: int; value: T) =
+  if newLen <= x.len: return
+  assert newLen >= 0
+  let oldCap = x.cap
+  if oldCap == 0: x.cap = newLen
+  else: x.cap = max(newLen, (oldCap * 3) shr 1)
+  if x.data == nil: inc allocCount
+  x.data = cast[type(x.data)](realloc0(x.data, oldCap * sizeof(T), x.cap * sizeof(T)))
+  for i in x.len..<newLen:
+    x.data[i] = value
+  x.len = newLen
+
+template default[T](t: typedesc[T]): T =
+  var v: T
+  v
+
+proc setLen*[T](x: var myseq[T]; newLen: int) {.deprecated.} =
+  if newlen < x.len: shrink(x, newLen)
+  else: grow(x, newLen, default(T))
+
+template `[]`*[T](x: myseq[T]; i: Natural): T =
+  assert i < x.len
+  x.data[i]
+
+template `[]=`*[T](x: myseq[T]; i: Natural; y: T) =
+  assert i < x.len
+  x.data[i] = y
+
+proc createSeq*[T](elems: varargs[T]): myseq[T] =
+  result.cap = max(elems.len, 2)
+  result.len = elems.len
+  result.data = cast[type(result.data)](alloc0(result.cap * sizeof(T)))
+  inc allocCount
+  when supportsCopyMem(T):
+    copyMem(result.data, addr(elems[0]), result.cap * sizeof(T))
+  else:
+    for i in 0..<result.len:
+      result.data[i] = elems[i]
+
+proc len*[T](x: myseq[T]): int {.inline.} = x.len
+
+proc main =
+  var s = createSeq(1, 2, 3, 4, 5, 6)
+  s.add 89
+  s.grow s.len + 2, 90
+  for i in 0 ..< s.len:
+    echo s[i]
+
+  var nested = createSeq(createSeq(1, 2, 3), createSeq(4, 5, 6, 7))
+  for i in 0 ..< nested.len:
+    for j in 0 ..< nested[i].len:
+      echo i, " ", j, " ", nested[i][j]
+
+main()
+echo "after ", allocCount, " ", deallocCount
+
+type
+  Node = ref object
+    name: char
+    sccId: int
+    kids: myseq[Node]
+    rc: int
+
+proc edge(a, b: Node) =
+  inc b.rc
+  a.kids.add b
+
+proc createNode(name: char): Node =
+  new result
+  result.name = name
+  result.kids = createSeq[Node]()
+
+proc use(x: Node) = discard
+
+proc buildComplexGraph: Node =
+  # see https://en.wikipedia.org/wiki/Strongly_connected_component for the
+  # graph:
+  let a = createNode('a')
+  let b = createNode('b')
+  let c = createNode('c')
+  let d = createNode('d')
+  let e = createNode('e')
+
+  a.edge c
+  c.edge b
+  c.edge e
+  b.edge a
+  d.edge c
+  e.edge d
+
+
+  let f = createNode('f')
+  b.edge f
+  e.edge f
+
+  let g = createNode('g')
+  let h = createNode('h')
+  let i = createNode('i')
+
+  f.edge g
+  f.edge i
+  g.edge h
+  h.edge i
+  i.edge g
+
+  let j = createNode('j')
+
+  h.edge j
+  i.edge j
+
+  let k = createNode('k')
+  let l = createNode('l')
+
+  f.edge k
+  k.edge l
+  l.edge k
+  k.edge j
+
+  let m = createNode('m')
+  let n = createNode('n')
+  let p = createNode('p')
+  let q = createNode('q')
+
+  m.edge n
+  n.edge p
+  n.edge q
+  q.edge p
+  p.edge m
+
+  q.edge k
+
+  d.edge m
+  e.edge n
+
+  result = a
+
+proc main2 =
+  let g = buildComplexGraph()
+
+main2()
+GC_fullCollect()
+echo "MEM ", getOccupiedMem()
diff --git a/tests/arc/tdeepcopy.nim b/tests/arc/tdeepcopy.nim
new file mode 100644
index 000000000..91d93aa28
--- /dev/null
+++ b/tests/arc/tdeepcopy.nim
@@ -0,0 +1,67 @@
+discard """
+  cmd: "nim c --gc:arc --deepcopy:on $file"
+  output: '''13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+13 abc
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+called deepCopy for int
+0'''
+"""
+
+type
+  PBinaryTree = ref object of RootObj
+    le, ri: PBinaryTree
+    value: int
+
+proc mainB =
+  var x: PBinaryTree
+  deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13))))
+
+  var y: string
+  deepCopy y, "abc"
+  echo x.ri.le.value, " ", y
+
+for i in 0..10:
+  mainB()
+
+
+type
+  Bar[T] = object
+    x: T
+
+proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] =
+  result.new
+  result.x = b.x
+  when T is int:
+    echo "called deepCopy for int"
+  else:
+    echo "called deepCopy for something else"
+
+proc main =
+  var dummy, c: ref Bar[int]
+  new(dummy)
+  dummy.x = 44
+
+  deepCopy c, dummy
+
+for i in 0..10:
+  main()
+
+echo getOccupiedMem()
diff --git a/tests/arc/tdestroy_in_loopcond.nim b/tests/arc/tdestroy_in_loopcond.nim
new file mode 100644
index 000000000..62532664d
--- /dev/null
+++ b/tests/arc/tdestroy_in_loopcond.nim
@@ -0,0 +1,74 @@
+discard """
+  output: '''400 true'''
+  cmd: "nim c --gc:orc $file"
+"""
+
+type HeapQueue*[T] = object
+  data: seq[T]
+
+
+proc len*[T](heap: HeapQueue[T]): int {.inline.} =
+  heap.data.len
+
+proc `[]`*[T](heap: HeapQueue[T], i: Natural): T {.inline.} =
+  heap.data[i]
+
+proc push*[T](heap: var HeapQueue[T], item: T) =
+  heap.data.add(item)
+
+proc pop*[T](heap: var HeapQueue[T]): T =
+  result = heap.data.pop
+
+proc clear*[T](heap: var HeapQueue[T]) = heap.data.setLen 0
+
+
+type
+  Future = ref object of RootObj
+    s: string
+    callme: proc()
+
+var called = 0
+
+proc consume(f: Future) =
+  inc called
+
+proc newFuture(s: string): Future =
+  var r: Future
+  r = Future(s: s, callme: proc() =
+    consume r)
+  result = r
+
+var q: HeapQueue[tuple[finishAt: int64, fut: Future]]
+
+proc sleep(f: int64): Future =
+  q.push (finishAt: f, fut: newFuture("async-sleep"))
+
+proc processTimers =
+  # Pop the timers in the order in which they will expire (smaller `finishAt`).
+  var count = q.len
+  let t = high(int64)
+  while count > 0 and t >= q[0].finishAt:
+    q.pop().fut.callme()
+    dec count
+
+var futures: seq[Future]
+
+proc main =
+  for i in 1..200:
+    futures.add sleep(56020904056300)
+    futures.add sleep(56020804337500)
+    #futures.add sleep(2.0)
+
+    #futures.add sleep(4.0)
+
+    processTimers()
+    #q.pop()[1].callme()
+    #q.pop()[1].callme()
+
+    futures.setLen 0
+
+  q.clear()
+
+main()
+GC_fullCollect()
+echo called, " ", getOccupiedMem() < 160
diff --git a/tests/arc/tdup.nim b/tests/arc/tdup.nim
new file mode 100644
index 000000000..61f262a68
--- /dev/null
+++ b/tests/arc/tdup.nim
@@ -0,0 +1,71 @@
+discard """
+  cmd: "nim c --mm:arc --expandArc:foo --hints:off $file"
+  nimout: '''
+--expandArc: foo
+
+var
+  x
+  :tmpD
+  s
+  :tmpD_1
+x = Ref(id: 8)
+inc:
+  :tmpD = `=dup`(x)
+  :tmpD
+inc:
+  let blitTmp = x
+  blitTmp
+var id_1 = 777
+s = RefCustom(id_2: addr(id_1))
+inc_1 :
+  :tmpD_1 = `=dup_1`(s)
+  :tmpD_1
+inc_1 :
+  let blitTmp_1 = s
+  blitTmp_1
+-- end of expandArc ------------------------
+'''
+"""
+
+type
+  Ref = ref object
+    id: int
+
+  RefCustom = object
+    id: ptr int
+
+proc `=dup`(x: RefCustom): RefCustom =
+  result.id = x.id
+
+proc inc(x: sink Ref) =
+  inc x.id
+
+proc inc(x: sink RefCustom) =
+  inc x.id[]
+
+
+proc foo =
+  var x = Ref(id: 8)
+  inc(x)
+  inc(x)
+  var id = 777
+  var s = RefCustom(id: addr id)
+  inc s
+  inc s
+
+foo()
+
+proc foo2 =
+  var x = Ref(id: 8)
+  inc(x)
+  doAssert x.id == 9
+  inc(x)
+  doAssert x.id == 10
+  var id = 777
+  var s = RefCustom(id: addr id)
+  inc s
+  doAssert s.id[] == 778
+  inc s
+  doAssert s.id[] == 779
+
+foo2()
diff --git a/tests/arc/testfile.txt b/tests/arc/testfile.txt
new file mode 100644
index 000000000..5169490be
--- /dev/null
+++ b/tests/arc/testfile.txt
@@ -0,0 +1,2 @@
+1 x
+2 y
diff --git a/tests/arc/texceptions.nim b/tests/arc/texceptions.nim
new file mode 100644
index 000000000..c55b463fc
--- /dev/null
+++ b/tests/arc/texceptions.nim
@@ -0,0 +1,16 @@
+discard """
+  cmd: "nim cpp --gc:arc $file"
+"""
+
+block: # issue #13071
+  type MyExcept = object of CatchableError
+  proc gun()=
+    raise newException(MyExcept, "foo:")
+  proc fun()=
+    var a = ""
+    try:
+      gun()
+    except Exception as e:
+      a = e.msg & $e.name # was segfaulting here for `nim cpp --gc:arc`
+    doAssert a == "foo:MyExcept"
+  fun()
diff --git a/tests/arc/texplicit_sink.nim b/tests/arc/texplicit_sink.nim
new file mode 100644
index 000000000..4b021ed62
--- /dev/null
+++ b/tests/arc/texplicit_sink.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''de'''
+  cmd: '''nim c --mm:arc --expandArc:main $file'''
+  nimout: '''--expandArc: main
+
+var
+  a
+  b_cursor
+try:
+  a = f "abc"
+  b_cursor = "de"
+  `=sink`(a, b_cursor)
+  echo [a]
+finally:
+  `=destroy`(a)
+-- end of expandArc ------------------------'''
+"""
+
+# bug #20572
+
+proc f(s: string): string = s
+
+proc main =
+  var a = f "abc"
+  var b = "de"
+  `=sink`(a, b)
+  echo a
+
+main()
diff --git a/tests/arc/tfuncobj.nim b/tests/arc/tfuncobj.nim
new file mode 100644
index 000000000..50cd9425e
--- /dev/null
+++ b/tests/arc/tfuncobj.nim
@@ -0,0 +1,38 @@
+discard """
+  outputsub: '''f1
+f2
+f3'''
+  cmd: "nim c --gc:orc $file"
+  valgrind: true
+"""
+
+type
+  FuncObj = object
+    fn: proc (env: pointer) {.cdecl.}
+    env: pointer
+
+proc `=destroy`(x: var FuncObj) =
+  GC_unref(cast[RootRef](x.env))
+
+proc `=copy`(x: var FuncObj, y: FuncObj) {.error.}
+
+# bug #18433
+
+proc main =
+  var fs: seq[FuncObj]
+
+  proc wrap(p: proc()) =
+    proc closeOver() = p()
+    let env = rawEnv closeOver
+    GC_ref(cast[RootRef](env))
+    fs.add(FuncObj(fn: cast[proc(env: pointer){.cdecl.}](rawProc closeOver), env: env))
+
+  wrap(proc() {.closure.} = echo "f1")
+  wrap(proc() {.closure.} = echo "f2")
+  wrap(proc() {.closure.} = echo "f3")
+
+  for a in fs:
+    a.fn(a.env)
+
+main()
+
diff --git a/tests/arc/thamming_orc.nim b/tests/arc/thamming_orc.nim
new file mode 100644
index 000000000..777efb38e
--- /dev/null
+++ b/tests/arc/thamming_orc.nim
@@ -0,0 +1,155 @@
+discard """
+  output: '''(allocCount: 1114, deallocCount: 1112)
+created 491 destroyed 491'''
+  cmd: "nim c --gc:orc -d:nimAllocStats $file"
+"""
+
+# bug #18421
+
+# test Nim Hamming Number Lazy List algo with reference counts and not...
+# compile with "-d:release -d:danger" and test with various
+# memory managment GC's, allocators, threading, etc.
+# it should be guaranteed to work with zero memory leaks with `--gc:orc`...
+
+# compile with `-d:trace20` to trace creation and destruction of first 20 values.
+
+from math import log2
+
+# implement our own basic BigInt so the bigints library isn't necessary...
+type
+  BigInt = object
+    digits: seq[uint32]
+let zeroBigInt = BigInt(digits: @[ 0'u32 ])
+let oneBigInt = BigInt(digits: @[ 1'u32 ])
+
+proc shladd(bi: var BigInt; n: int; a: BigInt) =
+  # assume that both `bi` and `a` are sized correctly with
+  # msuint32 for both not containing a zero
+  let alen = a.digits.len
+  let mx = max(bi.digits.len, a.digits.len)
+  for i in bi.digits.len ..< mx: bi.digits.add 0'u32
+  var cry = 0'u64
+  for i in 0 ..< alen:
+    cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64
+    bi.digits[i] = cry.uint32; cry = cry shr 32
+  for i in alen ..< mx:
+    cry += bi.digits[i].uint64 shl n
+    bi.digits[i] = cry.uint32; cry = cry shr 32
+  if cry > 0'u64:
+    bi.digits.add cry.uint32
+
+proc `$`(x: BigInt): string =
+  if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32):
+    return "0"
+  result = ""; var n = x; var msd = n.digits.high
+  while msd >= 0:
+    if n.digits[msd] == 0'u32: msd.dec; continue
+    var brw = 0.uint64
+    for i in countdown(msd, 0):
+      let dvdnd = n.digits[i].uint64 + (brw shl 32)
+      let q = dvdnd div 10'u64; brw = dvdnd - q * 10'u64
+      n.digits[i] = q.uint32
+    result &= $brw
+  for i in 0 .. result.high shr 1: # reverse result string in place
+    let tmp = result[^(i + 1)]
+    result[^(i + 1)] = result[i]
+    result[i] = tmp
+
+type TriVal = (uint32, uint32, uint32)
+type LogRep = (float64, TriVal)
+type LogRepf = proc(x: LogRep): LogRep
+const one: LogRep = (0.0'f64, (0'u32, 0'u32, 0'u32))
+proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0]
+
+proc convertTriVal2BigInt(tpl: TriVal): BigInt =
+  result = oneBigInt
+  let (x2, x3, x5) = tpl
+  for _ in 1 .. x2: result.shladd 1, zeroBigInt
+  for _ in 1 .. x3: result.shladd 1, result
+  for _ in 1 .. x5: result.shladd 2, result
+
+const lb2 = 1.0'f64
+const lb3 = 3.0'f64.log2
+const lb5 = 5.0'f64.log2
+
+proc mul2(me: LogRep): LogRep =
+  let (lr, tpl) = me; let (x2, x3, x5) = tpl
+  (lr + lb2, (x2 + 1, x3, x5))
+
+proc mul3(me: LogRep): LogRep =
+  let (lr, tpl) = me; let (x2, x3, x5) = tpl
+  (lr + lb3, (x2, x3 + 1, x5))
+
+proc mul5(me: LogRep): LogRep =
+  let (lr, tpl) = me; let (x2, x3, x5) = tpl
+  (lr + lb5, (x2, x3, x5 + 1))
+
+type
+  LazyListObj = object
+    hd: LogRep
+    tlf: proc(): LazyList {.closure.}
+    tl: LazyList
+  LazyList = ref LazyListObj
+
+var destroyed = 0
+
+proc `=destroy`(ll: var LazyListObj) =
+  destroyed += 1
+  if ll.tlf == nil and ll.tl == nil: return
+
+  when defined(trace20):
+    echo "destroying:  ", (destroyed, ll.hd[1].convertTriVal2BigInt)
+  if ll.tlf != nil: ll.tlf.`=destroy`
+  if ll.tl != nil: ll.tl.`=destroy`
+  #wasMoved(ll)
+
+proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk
+  if ll.tlf != nil: ll.tl = ll.tlf(); ll.tlf = nil
+  ll.tl
+
+var created = 0
+iterator hammings(until: int): TriVal =
+  proc merge(x, y: LazyList): LazyList =
+    let xh = x.hd; let yh = y.hd; created += 1
+    when defined(trace20):
+      echo "merge create:  ", (created - 1, (if xh < yh: xh else: yh)[1].convertTriVal2BigInt)
+    if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y)
+    else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest)
+  proc smult(mltf: LogRepf; s: LazyList): LazyList =
+    proc smults(ss: LazyList): LazyList =
+      when defined(trace20):
+        echo "mult create:  ", (created, ss.hd.mltf[1].convertTriVal2BigInt)
+      created += 1; LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults)
+    s.smults
+  proc unnsm(s: LazyList, mltf: LogRepf): LazyList =
+    var r: LazyList = nil
+    when defined(trace20):
+      echo "first create:  ", (created, one[1].convertTriVal2BigInt)
+    let frst = LazyList(hd: one, tlf: proc(): LazyList = r); created += 1
+    r = if s == nil: smult(mltf, frst) else: s.merge smult(mltf, frst)
+    r
+  yield one[1]
+  var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2
+  for _ in 2 .. until:
+    yield hmpll.hd[1]; hmpll = hmpll.rest # almost forever
+
+proc main =
+  var s = ""
+  for h in hammings(20): s &= $h.convertTrival2BigInt & " "
+  doAssert s == "1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 ",
+           "Algorithmic error finding first 20 Hamming numbers!!!"
+
+  when not defined(trace20):
+    var lsth: TriVal
+    for h in hammings(200): lsth = h
+    doAssert $lsth.convertTriVal2BigInt == "16200",
+             "Algorithmic error finding 200th Hamming number!!!"
+
+let mem = getOccupiedMem()
+main()
+GC_FullCollect()
+let mb = getOccupiedMem() - mem
+doAssert mb == 0, "Found memory leak of " & $mb & " bytes!!!"
+
+echo getAllocStats()
+echo "created ", created, " destroyed ", destroyed
diff --git a/tests/arc/thamming_thinout.nim b/tests/arc/thamming_thinout.nim
new file mode 100644
index 000000000..65c34ef49
--- /dev/null
+++ b/tests/arc/thamming_thinout.nim
@@ -0,0 +1,183 @@
+discard """
+  cmd: "nim c --gc:orc -d:nimThinout -r $file"
+  output: '''The first 20 hammings are:  1 2 3 4 5 MEM IS 0'''
+"""
+
+# test Nim Hamming Number Lazy List algo with reference counts and not...
+# compile with "-d:release -d:danger" and test with various
+# memory managment GC's, allocators, threading, etc.
+
+from times import epochTime
+from math import log2
+
+# implement our own basic BigInt so the bigints library isn't necessary...
+type
+  BigInt = object
+    digits: seq[uint32]
+let zeroBigInt = BigInt(digits: @[ 0'u32 ])
+let oneBigInt = BigInt(digits: @[ 1'u32 ])
+
+proc shladd(bi: var BigInt; n: int; a: BigInt) =
+  var cry = 0'u64
+  for i in 0 ..< min(bi.digits.len, a.digits.len):
+    cry += (bi.digits[i].uint64 shl n) + a.digits[i].uint64
+    bi.digits[i] = cry.uint32
+    cry = cry shr 32
+  if cry > 0'u64:
+    bi.digits.add cry.uint32
+
+proc `$`(x: BigInt): string =
+  if x.digits.len == 0 or (x.digits.len == 1 and x.digits[0] == 0'u32):
+    return "0"
+  var n = x
+  var msd = n.digits.high
+  result = ""
+  while msd >= 0:
+    if n.digits[msd] == 0'u32: msd.dec; continue
+    var brw = 0.uint64
+    for i in countdown(msd, 0):
+      let dvdnd = n.digits[i].uint64 + (brw shl 32)
+      let q = dvdnd div 10'u64; brw = dvdnd - q*10'u64; n.digits[i] = q.uint32
+    result &= $brw
+  for i in 0 .. result.high shr 1:
+    let tmp = result[^(i + 1)]
+    result[^(i + 1)] = result[i]
+    result[i] = tmp
+
+proc convertTrival2BigInt(tpl: (uint32, uint32, uint32)): BigInt =
+  result = oneBigInt
+  let (x2, x3, x5) = tpl
+  for _ in 1 .. x2: result.shladd 1, zeroBigInt
+  for _ in 1 .. x3: result.shladd 1, result
+  for _ in 1 .. x5: result.shladd 2, result
+
+type LogRep = (float64, (uint32, uint32, uint32))
+type LogRepf = proc(x: LogRep): LogRep
+const one: LogRep = (0.0f64, (0u32, 0u32, 0u32))
+proc `<`(me: LogRep, othr: LogRep): bool = me[0] < othr[0]
+
+const lb2 = 1.0'f64
+const lb3 = 3.0'f64.log2
+const lb5 = 5.0'f64.log2
+
+proc mul2(me: LogRep): LogRep =
+  let (lr, tpl) = me; let (x2, x3, x5) = tpl
+  (lr + lb2, (x2 + 1, x3, x5))
+
+proc mul3(me: LogRep): LogRep =
+  let (lr, tpl) = me; let (x2, x3, x5) = tpl
+  (lr + lb3, (x2, x3 + 1, x5))
+
+proc mul5(me: LogRep): LogRep =
+  let (lr, tpl) = me; let (x2, x3, x5) = tpl
+  (lr + lb5, (x2, x3, x5 + 1))
+
+type
+  LazyList = ref object
+    hd: LogRep
+    tlf: proc(): LazyList {.closure.}
+    tl: LazyList
+
+proc rest(ll: LazyList): LazyList = # not thread-safe; needs lock on thunk
+  if ll.tlf != nil:
+    ll.tl = ll.tlf()
+    ll.tlf = nil
+  ll.tl
+
+iterator hamming(until: int): (uint32, uint32, uint32) =
+  proc merge(x, y: LazyList): LazyList =
+    let xh = x.hd
+    let yh = y.hd
+    if xh < yh: LazyList(hd: xh, tlf: proc(): auto = merge x.rest, y)
+    else: LazyList(hd: yh, tlf: proc(): auto = merge x, y.rest)
+  proc smult(mltf: LogRepf; s: LazyList): LazyList =
+    proc smults(ss: LazyList): LazyList =
+      LazyList(hd: ss.hd.mltf, tlf: proc(): auto = ss.rest.smults)
+    s.smults
+  proc unnsm(s: LazyList, mltf: LogRepf): LazyList =
+    var r: LazyList = nil
+    let frst = LazyList(hd: one, tlf: proc(): LazyList = r)
+    r = if s == nil: smult mltf, frst else: s.merge smult(mltf, frst)
+    r
+  var hmpll: LazyList = ((nil.unnsm mul5).unnsm mul3).unnsm mul2
+  #  var hmpll: LazyList = nil; for m in [mul5, mul3, mul2]: echo one.m # ; hmpll = unnsm(hmpll, m)
+  yield one[1]
+  var cnt = 1
+  while hmpll != nil:
+    yield hmpll.hd[1]
+    hmpll = hmpll.rest # almost forever
+    cnt.inc
+    if cnt > until: break
+  #when declared(thinout):
+  thinout(hmpll)
+
+proc main =
+  stdout.write "The first 20 hammings are:  "
+  for h in hamming(4):
+    write stdout, h.convertTrival2BigInt, " "
+
+  for h in hamming(200):
+    discard h.convertTrival2BigInt
+
+let mem = getOccupiedMem()
+main()
+echo "MEM IS ", getOccupiedMem() - mem
+
+#[
+result = (smults, :envP.:up)(rest(:envP.ss2))
+
+proc anon =
+  var
+    :tmpD_284230
+    :tmpD_284233
+    :tmpD_284236
+  try:
+    `=sink_283407`(result_283502,
+      `=sink_283927`(:tmpD_284236, (smults_283495,
+        wasMoved_284234(:tmpD_284233)
+        `=_284014`(:tmpD_284233, :envP_283898.:up_283899)
+        :tmpD_284233))
+      :tmpD_284236(
+      `=sink_283407`(:tmpD_284230, rest_283366(:envP_283898.ss2_-283497))
+      :tmpD_284230))
+  finally:
+    `=destroy_283914`(:tmpD_284236)
+    `=destroy_283388`(:tmpD_284230)
+
+proc smuls(ss: LazyList_283350; :envP_283891): LazyList_283350  =
+  var :env_283913
+  try:
+    `=destroy_283951`(:env_283913)
+    internalNew_43643(:env_283913)
+    `=_283401`(:env_283913.ss2_-283497, ss_283497)
+    :env_283913.:up_283899 = :envP_283891
+    `=sink_283407`(result_283498, LazyList_283350(hd_283353: :envP_283891.mltf1_-283492(
+        :env_283913.ss2_-283497.hd_283353), tlf_283356: (:anonymous_283499,
+      let blitTmp_284227 = :env_283913
+      wasMoved_284228(:env_283913)
+      blitTmp_284227)))
+  finally:
+    `=destroy_283951`(:env_283913)
+
+proc smul =
+  var
+    :env_283969
+    :tmpD_284220
+  try:
+    `=destroy_284008`(:env_283969)
+    internalNew_43643(:env_283969)
+    `=_283976`(:env_283969.mltf1_-283492, mltf_283492)
+    proc smults(ss: LazyList_283350; :envP_283891): LazyList_283350 =
+      result_283498 = LazyList_283350(hd_283353: mltf_283492(ss_283497.hd_283353), tlf_283356: proc (
+          :envP_283898): auto_43100 = result_283502 = smults_283495(rest_283366(ss_283497)))
+
+    `=sink_283407`(result_283494,
+      `=sink_283927`(:tmpD_284220, (smults_283495,
+        let blitTmp_284218 = :env_283969
+        wasMoved_284219(:env_283969)
+        blitTmp_284218))
+      :tmpD_284220(s_283493))
+  finally:
+    `=destroy_283914`(:tmpD_284220)
+    `=destroy_284008`(:env_283969)
+]#
diff --git a/tests/arc/thard_alignment.nim b/tests/arc/thard_alignment.nim
new file mode 100644
index 000000000..30cfddb05
--- /dev/null
+++ b/tests/arc/thard_alignment.nim
@@ -0,0 +1,148 @@
+discard """
+disabled: "arm64"
+cmd: "nim c --mm:arc -u:nimPreviewNonVarDestructor $file"
+output: "y"
+"""
+
+# TODO: fixme: investigate why it failed with non-var destructors
+
+{.passC: "-march=native".}
+
+proc isAlignedCheck(p: pointer, alignment: int) = 
+  doAssert (cast[uint](p) and uint(alignment - 1)) == 0
+
+proc isAlignedCheck[T](p: ref T, alignment: int) = 
+  isAlignedCheck(cast[pointer](p), alignment)
+
+type
+  m256d {.importc: "__m256d", header: "immintrin.h".} = object
+
+proc set1(x: float): m256d {.importc: "_mm256_set1_pd", header: "immintrin.h".}
+func `+`(a,b: m256d): m256d {.importc: "_mm256_add_pd", header: "immintrin.h".}
+proc `$`(a: m256d): string =  
+  result = $(cast[ptr float](a.addr)[])
+
+
+var res: seq[seq[m256d]]
+
+for _ in 1..1000:
+  var x = newSeq[m256d](1)
+  x[0] = set1(1.0) # test if operation causes segfault
+  isAlignedCheck(x[0].addr, alignof(m256d))
+  res.add x
+
+var res2: seq[m256d]
+for i in 1..10000:
+  res2.setLen(res2.len + 1) # check if realloc works
+  isAlignedCheck(res2[0].addr, alignof(m256d))  
+
+proc lambdaGen(a, b: float, z: ref m256d) : auto =
+  var x1 = new(m256d)
+  var x2 = new(m256d)
+  isAlignedCheck(x1, alignof(m256d))
+  isAlignedCheck(x2, alignof(m256d))
+  x1[] = set1(2.0 + a)  
+  x2[] = set1(-23.0 - b)
+  let capturingLambda = proc(x: ref m256d): ref m256d =
+    var cc = new(m256d)
+    var bb = new(m256d)
+    isAlignedCheck(x1, alignof(m256d))
+    isAlignedCheck(x2, alignof(m256d))
+    isAlignedCheck(cc, alignof(m256d))
+    isAlignedCheck(bb, alignof(m256d))
+    isAlignedCheck(z, alignof(m256d))
+        
+    cc[] = x1[] + x1[] + z[]
+    bb[] = x2[] + set1(12.5) + z[]
+    
+    result = new(m256d)
+    isAlignedCheck(result, alignof(m256d))
+    result[] = cc[] + bb[] + x[]
+    
+  return capturingLambda
+
+var xx = new(m256d)
+xx[] = set1(10)
+isAlignedCheck(xx, alignOf(m256d))
+
+let f1 = lambdaGen(2.0 , 2.221, xx)
+let f2 = lambdaGen(-1.226 , 3.5, xx)
+isAlignedCheck(f1(xx), alignOf(m256d))
+isAlignedCheck(f2(xx), alignOf(m256d))
+
+
+#-----------------------------------------------------------------------------
+
+type
+  MyAligned = object of RootObj
+    a{.align: 128.}: float
+
+
+var f: MyAligned
+isAlignedCheck(f.addr, MyAligned.alignOf)
+
+var fref = new(MyAligned)
+isAlignedCheck(fref, MyAligned.alignOf)
+
+var fs: seq[MyAligned]
+var fr: seq[RootRef]
+
+for i in 0..1000:
+  fs.add MyAligned()
+  isAlignedCheck(fs[^1].addr, MyAligned.alignOf)
+  fs[^1].a = i.float
+
+  fr.add new(MyAligned)
+  isAlignedCheck(fr[^1], MyAligned.alignOf)
+  ((ref MyAligned)fr[^1])[].a = i.float
+
+for i in 0..1000:
+  doAssert(fs[i].a == i.float)
+  doAssert(((ref MyAligned)fr[i]).a == i.float)
+
+
+proc lambdaTest2(a: MyAligned, z: ref MyAligned): auto =
+  var x1: MyAligned
+  x1.a = a.a + z.a  
+  var x2: MyAligned
+  x2.a = a.a - z.a
+  let capturingLambda = proc(x: MyAligned): MyAligned =
+    var cc: MyAligned
+    var bb: MyAligned
+    isAlignedCheck(x1.addr, MyAligned.alignOf)
+    isAlignedCheck(x2.addr, MyAligned.alignOf)
+    isAlignedCheck(cc.addr, MyAligned.alignOf)
+    isAlignedCheck(bb.addr, MyAligned.alignOf)
+    isAlignedCheck(z, MyAligned.alignOf)
+        
+    cc.a = x1.a + x1.a + z.a
+    bb.a = x2.a - z.a
+    
+    isAlignedCheck(result.addr, MyAligned.alignOf)
+    result.a = cc.a + bb.a + x2.a
+    
+  return capturingLambda
+
+
+let q1 = lambdaTest2(MyAligned(a: 1.0), (ref MyAligned)(a: 2.0))
+let q2 = lambdaTest2(MyAligned( a: -1.0), (ref MyAligned)(a: -2.0))
+
+isAlignedCheck(rawEnv(q1), MyAligned.alignOf)
+isAlignedCheck(rawEnv(q2), MyAligned.alignOf)
+discard q1(MyAligned(a: 1.0))
+discard q2(MyAligned(a: -1.0))
+
+
+#-----------------------------------------------------------------------------
+
+block:
+  var s: seq[seq[MyAligned]]
+  for len in 0..128:
+    s.add newSeq[MyAligned](len)
+    for i in 0..<len:
+      s[^1][i] = MyAligned(a: 1.0)
+
+    if len > 0:
+      isAlignedCheck(s[^1][0].addr, MyAligned.alignOf)
+  
+echo "y"
diff --git a/tests/arc/thavlak_orc_stress.nim b/tests/arc/thavlak_orc_stress.nim
new file mode 100644
index 000000000..862e1a097
--- /dev/null
+++ b/tests/arc/thavlak_orc_stress.nim
@@ -0,0 +1,414 @@
+discard """
+  cmd: "nim c --gc:orc -d:useMalloc -d:nimStressOrc $file"
+  valgrind: "leaks"
+  output: "done"
+"""
+
+import tables
+import sets
+import net
+
+type
+  BasicBlock = object
+    inEdges: seq[ref BasicBlock]
+    outEdges: seq[ref BasicBlock]
+    name: int
+
+proc newBasicBlock(name: int): ref BasicBlock =
+  new(result)
+  result.inEdges = newSeq[ref BasicBlock]()
+  result.outEdges = newSeq[ref BasicBlock]()
+  result.name = name
+
+proc hash(x: ref BasicBlock): int {.inline.} =
+  result = x.name
+
+type
+  BasicBlockEdge = object
+    fr: ref BasicBlock
+    to: ref BasicBlock
+
+  Cfg = object
+    basicBlockMap: Table[int, ref BasicBlock]
+    edgeList: seq[BasicBlockEdge]
+    startNode: ref BasicBlock
+
+proc newCfg(): Cfg =
+  result.basicBlockMap = initTable[int, ref BasicBlock]()
+  result.edgeList = newSeq[BasicBlockEdge]()
+
+proc createNode(self: var Cfg, name: int): ref BasicBlock =
+  #var node: ref BasicBlock
+  result = self.basicBlockMap.getOrDefault(name)
+  if result == nil:
+    result = newBasicBlock(name)
+    self.basicBlockMap.add name, result
+
+  if self.startNode == nil:
+    self.startNode = result
+
+proc addEdge(self: var Cfg, edge: BasicBlockEdge) =
+  self.edgeList.add(edge)
+
+proc getNumNodes(self: Cfg): int =
+  self.basicBlockMap.len
+
+proc newBasicBlockEdge(cfg: var Cfg, fromName: int, toName: int) =
+  var newEdge = BasicBlockEdge()
+  newEdge.fr = cfg.createNode(fromName)
+  newEdge.to = cfg.createNode(toName)
+  newEdge.fr.outEdges.add(newEdge.to)
+  newEdge.to.inEdges.add(newEdge.fr)
+  cfg.addEdge(newEdge)
+
+type
+  SimpleLoop = object
+    basicBlocks: seq[ref BasicBlock] # TODO: set here
+    children: seq[ref SimpleLoop] # TODO: set here
+    parent: ref SimpleLoop
+    header: ref BasicBlock
+    isRoot: bool
+    isReducible: bool
+    counter: int
+    nestingLevel: int
+    depthLevel: int
+
+proc newSimpleLoop(): ref SimpleLoop =
+  new(result)
+  result.basicBlocks = newSeq[ref BasicBlock]()
+  result.children = newSeq[ref SimpleLoop]()
+  result.parent = nil
+  result.header = nil
+  result.isRoot = false
+  result.isReducible = true
+  result.counter = 0
+  result.nestingLevel = 0
+  result.depthLevel = 0
+
+proc addNode(self: ref SimpleLoop, bb: ref BasicBlock) =
+  self.basicBlocks.add bb
+
+proc addChildLoop(self: ref SimpleLoop, loop: ref SimpleLoop) =
+  self.children.add loop
+
+proc setParent(self: ref SimpleLoop, parent: ref SimpleLoop) =
+  self.parent = parent
+  self.parent.addChildLoop(self)
+
+proc setHeader(self: ref SimpleLoop, bb: ref BasicBlock) =
+  self.basicBlocks.add(bb)
+  self.header = bb
+
+proc setNestingLevel(self: ref SimpleLoop, level: int) =
+  self.nestingLevel = level
+  if level == 0: self.isRoot = true
+
+var loop_counter: int = 0
+
+type
+  Lsg = object
+    loops: seq[ref SimpleLoop]
+    root: ref SimpleLoop
+
+proc createNewLoop(self: var Lsg): ref SimpleLoop =
+  var s = newSimpleLoop()
+  loop_counter += 1
+  s.counter = loop_counter
+  s
+
+proc addLoop(self: var Lsg, l: ref SimpleLoop) =
+  self.loops.add l
+
+proc newLsg(): Lsg =
+  result.loops = newSeq[ref SimpleLoop]()
+  result.root = result.createNewLoop()
+  result.root.setNestingLevel(0)
+  result.addLoop(result.root)
+
+proc getNumLoops(self: Lsg): int =
+  self.loops.len
+
+type
+  UnionFindNode = object
+    parent: ref UnionFindNode
+    bb: ref BasicBlock
+    l: ref SimpleLoop
+    dfsNumber: int
+
+proc newUnionFindNode(): ref UnionFindNode =
+  new(result)
+  result.parent = nil
+  result.bb = nil
+  result.l = nil
+  result.dfsNumber = 0
+
+proc initNode(self: ref UnionFindNode, bb: ref BasicBlock, dfsNumber: int) =
+  self.parent = self
+  self.bb = bb
+  self.dfsNumber = dfsNumber
+
+proc findSet(self: ref UnionFindNode): ref UnionFindNode =
+  var nodeList = newSeq[ref UnionFindNode]()
+  var node = self
+
+  while node != node.parent:
+    var parent = node.parent
+    if parent != parent.parent: nodeList.add node
+    node = parent
+
+  for iter in nodeList: iter.parent = node.parent
+  node
+
+proc union(self: ref UnionFindNode, unionFindNode: ref UnionFindNode) =
+  self.parent = unionFindNode
+
+
+const
+  BB_NONHEADER    = 1 # a regular BB
+  BB_REDUCIBLE    = 2 # reducible loop
+  BB_SELF         = 3 # single BB loop
+  BB_IRREDUCIBLE  = 4 # irreducible loop
+  BB_DEAD         = 5 # a dead BB
+
+  # # Marker for uninitialized nodes.
+  UNVISITED = -1
+
+  # # Safeguard against pathologic algorithm behavior.
+  MAXNONBACKPREDS = (32 * 1024)
+
+type
+  HavlakLoopFinder = object
+    cfg: Cfg
+    lsg: Lsg
+
+proc newHavlakLoopFinder(cfg: sink Cfg, lsg: sink Lsg): HavlakLoopFinder =
+  result.cfg = cfg
+  result.lsg = lsg
+
+proc isAncestor(w: int, v: int, last: seq[int]): bool =
+  w <= v and v <= last[w]
+
+proc dfs(currentNode: ref BasicBlock, nodes: var seq[ref UnionFindNode], number: var Table[ref BasicBlock, int], last: var seq[int], current: int): int =
+  nodes[current].initNode(currentNode, current)
+  number[currentNode] = current
+
+  var lastid = current
+  for target in currentNode.outEdges:
+    if number[target] == UNVISITED:
+      lastid = dfs(target, nodes, number, last, lastid + 1)
+
+  last[number[currentNode]] = lastid
+  return lastid
+
+proc findLoops(self: var HavlakLoopFinder): int =
+  var startNode = self.cfg.startNode
+  if startNode == nil: return 0
+  var size = self.cfg.getNumNodes
+
+  var nonBackPreds = newSeq[HashSet[int]]()
+  var backPreds = newSeq[seq[int]]()
+  var number = initTable[ref BasicBlock, int]()
+  var header = newSeq[int](size)
+  var types = newSeq[int](size)
+  var last = newSeq[int](size)
+  var nodes = newSeq[ref UnionFindNode]()
+
+  for i in 1..size:
+    nonBackPreds.add initHashSet[int](1)
+    backPreds.add newSeq[int]()
+    nodes.add newUnionFindNode()
+
+  # Step a:
+  #   - initialize all nodes as unvisited.
+  #   - depth-first traversal and numbering.
+  #   - unreached BB's are marked as dead.
+  #
+  for v in self.cfg.basicBlockMap.values: number[v] = UNVISITED
+  discard dfs(startNode, nodes, number, last, 0)
+
+  # Step b:
+  #   - iterate over all nodes.
+  #
+  #   A backedge comes from a descendant in the DFS tree, and non-backedges
+  #   from non-descendants (following Tarjan).
+  #
+  #   - check incoming edges 'v' and add them to either
+  #     - the list of backedges (backPreds) or
+  #     - the list of non-backedges (nonBackPreds)
+  #
+  for w in 0 ..< size:
+    header[w] = 0
+    types[w]  = BB_NONHEADER
+
+    var nodeW = nodes[w].bb
+    if nodeW != nil:
+      for nodeV in nodeW.inEdges:
+        var v = number[nodeV]
+        if v != UNVISITED:
+          if isAncestor(w, v, last):
+            backPreds[w].add v
+          else:
+            nonBackPreds[w].incl v
+    else:
+      types[w] = BB_DEAD
+
+  # Start node is root of all other loops.
+  header[0] = 0
+
+  # Step c:
+  #
+  # The outer loop, unchanged from Tarjan. It does nothing except
+  # for those nodes which are the destinations of backedges.
+  # For a header node w, we chase backward from the sources of the
+  # backedges adding nodes to the set P, representing the body of
+  # the loop headed by w.
+  #
+  # By running through the nodes in reverse of the DFST preorder,
+  # we ensure that inner loop headers will be processed before the
+  # headers for surrounding loops.
+
+  for w in countdown(size - 1, 0):
+    # this is 'P' in Havlak's paper
+    var nodePool = newSeq[ref UnionFindNode]()
+
+    var nodeW = nodes[w].bb
+    if nodeW != nil: # dead BB
+      # Step d:
+      for v in backPreds[w]:
+        if v != w:
+          nodePool.add nodes[v].findSet
+        else:
+          types[w] = BB_SELF
+
+      # Copy nodePool to workList.
+      #
+      var workList = newSeq[ref UnionFindNode]()
+      for x in nodePool: workList.add x
+
+      if nodePool.len != 0: types[w] = BB_REDUCIBLE
+
+      # work the list...
+      #
+      while workList.len > 0:
+        var x = workList[0]
+        workList.del(0)
+
+        # Step e:
+        #
+        # Step e represents the main difference from Tarjan's method.
+        # Chasing upwards from the sources of a node w's backedges. If
+        # there is a node y' that is not a descendant of w, w is marked
+        # the header of an irreducible loop, there is another entry
+        # into this loop that avoids w.
+        #
+
+        # The algorithm has degenerated. Break and
+        # return in this case.
+        #
+        var nonBackSize = nonBackPreds[x.dfsNumber].len
+        if nonBackSize > MAXNONBACKPREDS: return 0
+
+        for iter in nonBackPreds[x.dfsNumber]:
+          var y = nodes[iter]
+          var ydash = y.findSet
+
+          if not isAncestor(w, ydash.dfsNumber, last):
+            types[w] = BB_IRREDUCIBLE
+            nonBackPreds[w].incl ydash.dfsNumber
+          else:
+            if ydash.dfsNumber != w and not nodePool.contains(ydash):
+              workList.add ydash
+              nodePool.add ydash
+
+      # Collapse/Unionize nodes in a SCC to a single node
+      # For every SCC found, create a loop descriptor and link it in.
+      #
+      if (nodePool.len > 0) or (types[w] == BB_SELF):
+        var l = self.lsg.createNewLoop
+
+        l.setHeader(nodeW)
+        l.isReducible = types[w] != BB_IRREDUCIBLE
+
+        # At this point, one can set attributes to the loop, such as:
+        #
+        # the bottom node:
+        #    iter  = backPreds(w).begin();
+        #    loop bottom is: nodes(iter).node;
+        #
+        # the number of backedges:
+        #    backPreds(w).size()
+        #
+        # whether this loop is reducible:
+        #    types(w) != BB_IRREDUCIBLE
+        #
+        nodes[w].l = l
+
+        for node in nodePool:
+          # Add nodes to loop descriptor.
+          header[node.dfsNumber] = w
+          node.union(nodes[w])
+
+          # Nested loops are not added, but linked together.
+          var node_l = node.l
+          if node_l != nil:
+            node_l.setParent(l)
+          else:
+            l.addNode(node.bb)
+
+        self.lsg.addLoop(l)
+
+  result = self.lsg.getNumLoops
+
+
+type
+  LoopTesterApp = object
+    cfg: Cfg
+    lsg: Lsg
+
+proc newLoopTesterApp(): LoopTesterApp =
+  result.cfg = newCfg()
+  result.lsg = newLsg()
+
+proc buildDiamond(self: var LoopTesterApp, start: int): int =
+  var bb0 = start
+  newBasicBlockEdge(self.cfg, bb0, bb0 + 1)
+  newBasicBlockEdge(self.cfg, bb0, bb0 + 2)
+  newBasicBlockEdge(self.cfg, bb0 + 1, bb0 + 3)
+  newBasicBlockEdge(self.cfg, bb0 + 2, bb0 + 3)
+  result = bb0 + 3
+
+proc buildConnect(self: var LoopTesterApp, start1: int, end1: int) =
+  newBasicBlockEdge(self.cfg, start1, end1)
+
+proc buildStraight(self: var LoopTesterApp, start: int, n: int): int =
+  for i in 0..n-1:
+    self.buildConnect(start + i, start + i + 1)
+  result = start + n
+
+proc buildBaseLoop(self: var LoopTesterApp, from1: int): int =
+  var header   = self.buildStraight(from1, 1)
+  var diamond1 = self.buildDiamond(header)
+  var d11      = self.buildStraight(diamond1, 1)
+  var diamond2 = self.buildDiamond(d11)
+  var footer   = self.buildStraight(diamond2, 1)
+
+  self.buildConnect(diamond2, d11)
+  self.buildConnect(diamond1, header)
+  self.buildConnect(footer, from1)
+  result = self.buildStraight(footer, 1)
+
+proc run(self: var LoopTesterApp) =
+  discard self.cfg.createNode(0)
+  discard self.buildBaseLoop(0)
+  discard self.cfg.createNode(1)
+  self.buildConnect(0, 2)
+
+  for i in 1..8:
+    # yes, it's 8 and it's correct.
+    var h = newHavlakLoopFinder(self.cfg, newLsg())
+    discard h.findLoops()
+
+  echo "done"
+
+var l = newLoopTesterApp()
+l.run()
diff --git a/tests/arc/theavy_recursion.nim b/tests/arc/theavy_recursion.nim
new file mode 100644
index 000000000..9813331f4
--- /dev/null
+++ b/tests/arc/theavy_recursion.nim
@@ -0,0 +1,43 @@
+discard """
+  output: "yay"
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #15122
+
+import tables
+
+type
+  BENodeKind* = enum
+    tkEof,
+    tkBytes,
+    tkList,
+    tkDict
+
+  BENode* = object
+    case kind: BENodeKind
+    of tkBytes: strVal: string
+    of tkList: listVal: seq[BENode]
+    of tkDict: dictVal*: Table[string, BENode]
+    else:
+      discard
+
+proc unused(s: string): BENode =
+  # bad:
+  result = BENode(kind: tkBytes, strVal: "abc")
+
+proc main =
+  var data = {
+    "examples": {
+      "values": BENode(
+        kind: tkList,
+        listVal: @[BENode(kind: tkBytes, strVal: "test")]
+      )
+    }.toTable()
+  }.toTable()
+
+  # For ARC listVal is empty for some reason
+  doAssert data["examples"]["values"].listVal[0].strVal == "test"
+
+main()
+echo "yay"
diff --git a/tests/arc/timportedobj.nim b/tests/arc/timportedobj.nim
new file mode 100644
index 000000000..9a88a9468
--- /dev/null
+++ b/tests/arc/timportedobj.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  action: "compile"
+"""
+
+# bug #13269
+
+import posix
+proc foo*() =
+  var last = newSeq[Stat]()
+  var next = last
+  for i in 0..3:
+    last = next
+foo()
diff --git a/tests/arc/titeration_doesnt_copy.nim b/tests/arc/titeration_doesnt_copy.nim
new file mode 100644
index 000000000..e510a6eff
--- /dev/null
+++ b/tests/arc/titeration_doesnt_copy.nim
@@ -0,0 +1,67 @@
+discard """
+  output: "true"
+"""
+
+type
+  Idx = object
+    i: int
+  Node = object
+    n: int
+    next: seq[Idx]
+  FooBar = object
+    s: seq[Node]
+
+proc `=copy`(dest: var Idx; source: Idx) {.error.}
+proc `=copy`(dest: var Node; source: Node) {.error.}
+proc `=copy`(dest: var FooBar; source: FooBar) {.error.}
+
+proc doSomething(ss: var seq[int], s: FooBar) =
+  for i in 0 .. s.s.len-1:
+    for elm in items s.s[i].next:
+      ss.add s.s[elm.i].n
+
+when isMainModule:
+  const foo = FooBar(s: @[Node(n: 1, next: @[Idx(i: 0)])])
+  var ss: seq[int]
+  doSomething(ss, foo)
+  echo ss == @[1]
+
+from sequtils import mapIt
+from strutils import join
+
+proc toBinSeq*(b: uint8): seq[uint8] =
+  ## Return binary sequence from each bits of uint8.
+  runnableExamples:
+    from sequtils import repeat
+    doAssert 0'u8.toBinSeq == 0'u8.repeat(8)
+    doAssert 0b1010_1010.toBinSeq == @[1'u8, 0, 1, 0, 1, 0, 1, 0]
+  result = @[]
+  var c = b
+  for i in 1..8:
+    result.add (uint8(c and 0b1000_0000) shr 7)
+    c = c shl 1
+
+proc toBinString*(data: openArray[uint8], col: int): string =
+  ## Return binary string from each bits of uint8.
+  runnableExamples:
+    doAssert @[0b0000_1111'u8, 0b1010_1010].toBinString(8) == "0000111110101010"
+    doAssert @[0b1000_0000'u8, 0b0000_0000].toBinString(1) == "10"
+  result = ""
+  for b in items data.mapIt(it.toBinSeq.mapIt(it.`$`[0].char)):
+    for i, c in b:
+      if i < col:
+        result.add c
+
+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/tkeys_lent.nim b/tests/arc/tkeys_lent.nim
new file mode 100644
index 000000000..2c92350b1
--- /dev/null
+++ b/tests/arc/tkeys_lent.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''{"string": 2}'''
+  cmd: "nim c --gc:orc $file"
+"""
+
+import tables
+
+proc use(x: int) = echo x
+
+proc main =
+  var tab = {"string": 1}.toTable
+  for keyAAA in tab.keys():
+    template alias(): untyped = tab[keyAAA]
+    alias() = 2
+  echo tab
+
+main()
diff --git a/tests/arc/tmalloc.nim b/tests/arc/tmalloc.nim
new file mode 100644
index 000000000..1d72646c8
--- /dev/null
+++ b/tests/arc/tmalloc.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "--mm:arc -d:useMalloc; --mm:arc"
+"""
+
+block: # bug #22058
+  template foo(): auto =
+    {.noSideEffect.}:
+      newSeq[byte](1)
+
+  type V = object
+    v: seq[byte]
+
+  proc bar(): V =
+    V(v: foo())
+
+  doAssert bar().v == @[byte(0)]
diff --git a/tests/arc/tmarshal.nim b/tests/arc/tmarshal.nim
new file mode 100644
index 000000000..f7ec6e2c5
--- /dev/null
+++ b/tests/arc/tmarshal.nim
@@ -0,0 +1,140 @@
+discard """
+  cmd: "nim c --gc:orc $file"
+  output: '''
+{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}
+true
+true
+alpha 100
+omega 200
+0'''
+"""
+
+import marshal
+
+template testit(x) = discard $$to[typeof(x)]($$x)
+
+var x: array[0..4, array[0..4, string]] = [
+  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+  ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+  ["test", "1", "2", "3", "4"]]
+
+proc blockA =
+  testit(x)
+  var test2: tuple[name: string, s: int] = ("tuple test", 56)
+  testit(test2)
+
+blockA()
+
+type
+  TE = enum
+    blah, blah2
+
+  TestObj = object
+    test, asd: int
+    case test2: TE
+    of blah:
+      help: string
+    else:
+      discard
+
+  PNode = ref TNode
+  TNode = object
+    next, prev: PNode
+    data: string
+
+proc buildList(): PNode =
+  new(result)
+  new(result.next)
+  new(result.prev)
+  result.data = "middle"
+  result.next.data = "next"
+  result.prev.data = "prev"
+  result.next.next = result.prev
+  result.next.prev = result
+  result.prev.next = result
+  result.prev.prev = result.next
+
+proc blockB =
+  var test3: TestObj
+  test3.test = 42
+  test3.test2 = blah
+  testit(test3)
+
+  var test4: ref tuple[a, b: string]
+  new(test4)
+  test4.a = "ref string test: A"
+  test4.b = "ref string test: B"
+  testit(test4)
+
+  var test5 = @[(0,1),(2,3),(4,5)]
+  testit(test5)
+
+  var test7 = buildList()
+  testit(test7)
+
+  var test6: set[char] = {'A'..'Z', '_'}
+  testit(test6)
+
+blockB()
+
+# bug #1352
+
+type
+  Entity = object of RootObj
+    name: string
+
+  Person = object of Entity
+    age: int
+    bio: string
+    blob: string
+
+proc blockC =
+  var instance1 = Person(name: "Cletus", age: 12,
+                        bio: "Я Cletus",
+                        blob: "ABC\x80")
+  echo($$instance1)
+  echo(to[Person]($$instance1).bio == instance1.bio) # true
+  echo(to[Person]($$instance1).blob == instance1.blob) # true
+
+blockC()
+
+# bug 5757
+
+type
+  Something = object
+    x: string
+    y: int
+
+proc blockD =
+  var data1 = """{"x": "alpha", "y": 100}"""
+  var data2 = """{"x": "omega", "y": 200}"""
+
+  var r = to[Something](data1)
+
+  echo r.x, " ", r.y
+
+  r = to[Something](data2)
+
+  echo r.x, " ", r.y
+
+blockD()
+
+type
+  Foo = object
+    a1: string
+    a2: string
+    a3: seq[string]
+    a4: seq[int]
+    a5: seq[int]
+    a6: seq[int]
+
+proc blockE =
+  var foo = Foo(a2: "", a4: @[], a6: @[1])
+  foo.a6.setLen 0
+  doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}"""
+  testit(foo)
+
+blockE()
+
+GC_fullCollect()
+echo getOccupiedMem()
diff --git a/tests/arc/tmove_regression.nim b/tests/arc/tmove_regression.nim
new file mode 100644
index 000000000..7d9a867c3
--- /dev/null
+++ b/tests/arc/tmove_regression.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''/1/2
+/1
+/
+'''
+""""
+
+# bug #22001
+
+import std / [os, strutils]
+
+proc finOp2(path, name: string): (string, File) = # Find & open FIRST `name`
+  var current = path
+  while true:
+    if current.isRootDir: break # <- current=="" => current.isRootDir
+    current = current.parentDir
+    let dir = current
+    echo dir.replace('\\', '/')  # Commenting out try/except below hides bug
+    try: result[0] = dir/name; result[1] = open(result[0]); return
+    except CatchableError: discard
+
+discard finOp2("/1/2/3", "4")  # All same if this->inside a proc
diff --git a/tests/arc/tmovebug.nim b/tests/arc/tmovebug.nim
new file mode 100644
index 000000000..8ad7c955c
--- /dev/null
+++ b/tests/arc/tmovebug.nim
@@ -0,0 +1,841 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: '''5
+(w: 5)
+(w: -5)
+c.text = hello
+c.text = hello
+p.text = hello
+p.toks = @["hello"]
+c.text = hello
+c[].text = hello
+pA.text = hello
+pA.toks = @["hello"]
+c.text = hello
+c.text = hello
+pD.text = hello
+pD.toks = @["hello"]
+c.text = hello
+c.text = hello
+pOD.text = hello
+pOD.toks = @["hello"]
+fff
+fff
+2
+fff
+fff
+2
+fff
+fff
+2
+mmm
+fff
+fff
+fff
+3
+mmm
+sink me (sink)
+assign me (not sink)
+sink me (not sink)
+sinked and not optimized to a bitcopy
+sinked and not optimized to a bitcopy
+sinked and not optimized to a bitcopy
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+100
+hey
+hey
+(a: "a", b: 2)
+ho
+(a: "b", b: 3)
+(b: "b", a: 2)
+ho
+(b: "a", a: 3)
+hey
+break
+break
+hey
+ho
+hey
+ho
+ho
+king
+live long; long live
+king
+hi
+try
+bye
+()
+()
+()
+1
+destroy
+1
+destroy
+1
+destroy
+copy (self-assign)
+1
+destroy
+1
+destroy
+1
+destroy
+destroy
+copy
+@[(f: 2), (f: 2), (f: 3)]
+destroy
+destroy
+destroy
+sink
+sink
+destroy
+copy
+(f: 1)
+destroy
+destroy
+part-to-whole assigment:
+sink
+(children: @[])
+destroy
+sink
+(children: @[])
+destroy
+copy
+destroy
+(f: 1)
+destroy
+'''
+"""
+
+# move bug
+type
+  TMyObj = object
+    p: pointer
+    len: int
+
+var destroyCounter = 0
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil:
+    dealloc o.p
+    o.p = nil
+    inc destroyCounter
+
+proc `=`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = alloc(src.len)
+  dst.len = src.len
+
+proc `=sink`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = src.p
+  dst.len = src.len
+
+type
+  TObjKind = enum Z, A, B
+  TCaseObj = object
+    case kind: TObjKind
+    of Z: discard
+    of A:
+      x1: int # this int plays important role
+      x2: TMyObj
+    of B:
+      y: TMyObj
+
+proc use(a: TCaseObj) = discard
+
+proc moveBug(i: var int) =
+  var a: array[2, TCaseObj]
+  a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 1
+  a[i+1] = a[i] # 2
+  inc i
+  use(a[i-1])
+
+var x = 0
+moveBug(x)
+
+proc moveBug2(): (TCaseObj, TCaseObj) =
+  var a: array[2, TCaseObj]
+  a[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
+  a[1] = a[0] # can move 3
+  result[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 4
+  result[1] = result[0] # 5
+
+proc main =
+  discard moveBug2()
+
+main()
+echo destroyCounter
+
+# bug #13314
+
+type
+  O = object
+    v: int
+  R = ref object
+    w: int
+
+proc `$`(r: R): string = $r[]
+
+proc tbug13314 =
+  var t5 = R(w: 5)
+  var execute = proc () =
+    echo t5
+
+  execute()
+  t5.w = -5
+  execute()
+
+tbug13314()
+
+#-------------------------------------------------------------------------
+# bug #13368
+
+import strutils
+proc procStat() =
+  for line in @["a b", "c d", "e f"]:
+    let cols = line.splitWhitespace(maxSplit=1)
+    let x = cols[0]
+    let (nm, rest) = (cols[0], cols[1])
+procStat()
+
+
+# bug #14269
+
+import sugar, strutils
+
+type
+  Cursor = object
+    text: string
+  Parsed = object
+    text: string
+    toks: seq[string]
+
+proc tokenize(c: var Cursor): seq[string] =
+  dump c.text
+  return c.text.splitWhitespace()
+
+proc parse(): Parsed =
+  var c = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c.tokenize) # note: c.tokenized uses c.text
+
+let p = parse()
+dump p.text
+dump p.toks
+
+
+proc tokenizeA(c: ptr Cursor): seq[string] =
+  dump c[].text
+  return c[].text.splitWhitespace()
+
+proc parseA(): Parsed =
+  var c = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c.addr.tokenizeA) # note: c.tokenized uses c.text
+
+let pA = parseA()
+dump pA.text
+dump pA.toks
+
+
+proc tokenizeD(c: Cursor): seq[string] =
+  dump c.text
+  return c.text.splitWhitespace()
+
+proc parseD(): Parsed =
+  var c = cast[ptr Cursor](alloc0(sizeof(Cursor)))
+  c[] = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c[].tokenizeD) # note: c.tokenized uses c.text
+
+let pD = parseD()
+dump pD.text
+dump pD.toks
+
+# Bug would only pop up with owned refs
+proc tokenizeOD(c: Cursor): seq[string] =
+  dump c.text
+  return c.text.splitWhitespace()
+
+proc parseOD(): Parsed =
+  var c = new Cursor
+  c[] = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c[].tokenizeOD) # note: c.tokenized uses c.text
+
+let pOD = parseOD()
+dump pOD.text
+dump pOD.toks
+
+when false:
+  # Bug would only pop up with owned refs and implicit derefs, but since they don't work together..
+  {.experimental: "implicitDeref".}
+  proc tokenizeOHD(c: Cursor): seq[string] =
+    dump c.text
+    return c.text.splitWhitespace()
+
+  proc parseOHD(): Parsed =
+    var c = new Cursor
+    c[] = Cursor(text: "hello")
+    dump c.text
+    return Parsed(text: c.text, toks: c.tokenizeOHD) # note: c.tokenized uses c.text
+
+  let pOHD = parseOHD()
+  dump pOHD.text
+  dump pOHD.toks
+
+# bug #13456
+
+iterator combinations[T](s: openArray[T], k: int): seq[T] =
+  let n = len(s)
+  assert k >= 0 and k <= n
+  var pos = newSeq[int](k)
+  var current = newSeq[T](k)
+  for i in 0..k-1:
+    pos[k-i-1] = i
+  var done = false
+  while not done:
+    for i in 0..k-1:
+      current[i] = s[pos[k-i-1]]
+    yield current
+    var i = 0
+    while i < k:
+      pos[i] += 1
+      if pos[i] < n-i:
+        for j in 0..i-1:
+          pos[j] = pos[i] + i - j
+        break
+      i += 1
+    if i >= k:
+      break
+
+type
+  UndefEx = object of ValueError
+
+proc main2 =
+  var delayedSyms = @[1, 2, 3]
+  var unp: seq[int]
+  block myb:
+    for a in 1 .. 2:
+      if delayedSyms.len > a:
+        unp = delayedSyms
+        for t in unp.combinations(a + 1):
+          try:
+            var h = false
+            for k in t:
+              echo "fff"
+            if h: continue
+            if true:
+              raise newException(UndefEx, "forward declaration")
+            break myb
+          except UndefEx:
+            echo t.len
+        echo "mmm"
+
+main2()
+
+
+
+type ME = object
+  who: string
+
+proc `=`(x: var ME, y: ME) =
+  if y.who.len > 0: echo "assign ",y.who
+
+proc `=sink`(x: var ME, y: ME) =
+  if y.who.len > 0: echo "sink ",y.who
+
+var dump: ME
+template use(x) = dump = x
+template def(x) = x = dump
+
+var c = true
+
+proc shouldSink() =
+  var x = ME(who: "me (sink)")
+  use(x) # we analyse this
+  if c: def(x)
+  else: def(x)
+  use(x) # ok, with the [else] part.
+
+shouldSink()
+
+dump = ME()
+
+proc shouldNotSink() =
+  var x = ME(who: "me (not sink)")
+  use(x) # we analyse this
+  if c: def(x)
+  use(x) # Not ok without the '[else]'
+
+shouldNotSink()
+
+# bug #14568
+import os
+
+type O2 = object
+  s: seq[int]
+
+proc `=sink`(dest: var O2, src: O2) =
+  echo "sinked and not optimized to a bitcopy"
+
+var testSeq: O2
+
+proc update() =
+  # testSeq.add(0) # uncommenting this line fixes the leak
+  testSeq = O2(s: @[])
+  testSeq.s.add(0)
+
+for i in 1..3:
+  update()
+
+
+# bug #14961
+type
+  Foo = object
+    data: seq[int]
+
+proc initFoo(len: int): Foo =
+  result = (let s = newSeq[int](len); Foo(data: s) )
+
+var f = initFoo(2)
+echo initFoo(2)
+
+proc initFoo2(len: int) =
+  echo   if true:
+             let s = newSeq[int](len); Foo(data: s)
+         else:
+             let s = newSeq[int](len); Foo(data: s)
+
+initFoo2(2)
+
+proc initFoo3(len: int) =
+  echo (block:
+         let s = newSeq[int](len); Foo(data: s))
+
+initFoo3(2)
+
+proc initFoo4(len: int) =
+  echo (let s = newSeq[int](len); Foo(data: s))
+
+initFoo4(2)
+
+proc initFoo5(len: int) =
+  echo (case true
+        of true:
+          let s = newSeq[int](len); Foo(data: s)
+        of false:
+          let s = newSeq[int](len); Foo(data: s))
+
+initFoo5(2)
+
+proc initFoo6(len: int) =
+  echo (block:
+          try:
+            let s = newSeq[int](len); Foo(data: s)
+          finally: discard)
+
+initFoo6(2)
+
+proc initFoo7(len: int) =
+  echo (block:
+          try:
+            raise newException(CatchableError, "sup")
+            let s = newSeq[int](len); Foo(data: s)
+          except CatchableError:
+            let s = newSeq[int](len); Foo(data: s) )
+
+initFoo7(2)
+
+
+# bug #14902
+iterator zip[T](s: openArray[T]): (T, T) =
+  var i = 0
+  while i < 10:
+    yield (s[i mod 2], s[i mod 2 + 1])
+    inc i
+
+var lastMem = int.high
+
+proc leak =
+  const len = 10
+  var x = @[newString(len), newString(len), newString(len)]
+
+  var c = 0
+  for (a, b) in zip(x):
+    let newMem = getOccupiedMem()
+    assert newMem <= lastMem
+    lastMem = newMem
+    c += a.len
+  echo c
+
+leak()
+
+
+proc consume(a: sink string) = echo a
+
+proc weirdScopes =
+  if (let a = "hey"; a.len > 0):
+    echo a
+
+  while (let a = "hey"; a.len > 0):
+    echo a
+    break
+
+  var a = block: (a: "a", b: 2)
+  echo a
+  (discard; a) = (echo "ho"; (a: "b", b: 3))
+  echo a
+
+  var b = try: (b: "b", a: 2)
+          except: raise
+  echo b
+  (discard; b) = (echo "ho"; (b: "a", a: 3))
+  echo b
+
+  var s = "break"
+  consume((echo "hey"; s))
+  echo s
+
+  echo (block:
+          var a = "hey"
+          (echo "hey"; "ho"))
+
+  var b2 = "ho"
+  echo (block:
+          var a = "hey"
+          (echo "hey"; b2))
+  echo b2
+
+  type status = enum
+    alive
+
+  var king = "king"
+  echo (block:
+          var a = "a"
+          when true:
+            var b = "b"
+            case alive
+            of alive:
+              try:
+                var c = "c"
+                if true:
+                  king
+                else:
+                  "the abyss"
+              except:
+                echo "he ded"
+                "dead king")
+  echo "live long; long live"
+  echo king
+
+weirdScopes()
+
+
+# bug #14985
+proc getScope(): string =
+  if true:
+    return "hi"
+  else:
+    "else"
+
+echo getScope()
+
+proc getScope3(): string =
+  try:
+    "try"
+  except:
+    return "except"
+
+echo getScope3()
+
+proc getScope2(): string =
+  case true
+  of true:
+    return "bye"
+  else:
+    "else"
+
+echo getScope2()
+
+
+#--------------------------------------------------------------------
+#bug  #15609
+
+type
+  Wrapper = object
+    discard
+
+proc newWrapper(): ref Wrapper =
+  new(result)
+  result
+
+
+proc newWrapper2(a: int): ref Wrapper =
+  new(result)
+  if a > 0:
+    result
+  else:
+    new(Wrapper)
+
+
+let w1 = newWrapper()
+echo $w1[]
+
+let w2 = newWrapper2(1)
+echo $w2[]
+
+let w3 = newWrapper2(-1)
+echo $w3[]
+
+
+#--------------------------------------------------------------------
+#self-assignments
+
+# Self-assignments that are not statically determinable will get
+# turned into `=copy` calls as caseBracketExprCopy demonstrates.
+# (`=copy` handles self-assignments at runtime)
+
+type
+  OO = object
+    f: int
+  W = object
+    o: OO
+
+proc `=destroy`(x: var OO) =
+  if x.f != 0:
+    echo "destroy"
+    x.f = 0
+
+proc `=sink`(x: var OO, y: OO) =
+  `=destroy`(x)
+  echo "sink"
+  x.f = y.f
+
+proc `=copy`(x: var OO, y: OO) =
+  if x.f != y.f:
+    `=destroy`(x)
+    echo "copy"
+    x.f = y.f
+  else:
+    echo "copy (self-assign)"
+
+proc caseSym =
+  var o = OO(f: 1)
+  o = o # NOOP
+  echo o.f # "1"
+  # "destroy"
+
+caseSym()
+
+proc caseDotExpr =
+  var w = W(o: OO(f: 1))
+  w.o = w.o # NOOP
+  echo w.o.f # "1"
+  # "destroy"
+
+caseDotExpr()
+
+proc caseBracketExpr =
+  var w = [0: OO(f: 1)]
+  w[0] = w[0] # NOOP
+  echo w[0].f # "1"
+  # "destroy"
+
+caseBracketExpr()
+
+proc caseBracketExprCopy =
+  var w = [0: OO(f: 1)]
+  let i = 0
+  w[i] = w[0] # "copy (self-assign)"
+  echo w[0].f # "1"
+  # "destroy"
+
+caseBracketExprCopy()
+
+proc caseDotExprAddr =
+  var w = W(o: OO(f: 1))
+  w.o = addr(w.o)[] # NOOP
+  echo w.o.f # "1"
+  # "destroy"
+
+caseDotExprAddr()
+
+proc caseBracketExprAddr =
+  var w = [0: OO(f: 1)]
+  addr(w[0])[] = addr(addr(w[0])[])[] # NOOP
+  echo w[0].f # "1"
+  # "destroy"
+
+caseBracketExprAddr()
+
+proc caseNotAConstant =
+  var i = 0
+  proc rand: int =
+    result = i
+    inc i
+  var s = @[OO(f: 1), OO(f: 2), OO(f: 3)]
+  s[rand()] = s[rand()] # "destroy" "copy"
+  echo s # @[(f: 2), (f: 2), (f: 3)]
+
+caseNotAConstant()
+
+proc potentialSelfAssign(i: var int) =
+  var a: array[2, OO]
+  a[i] = OO(f: 1) # turned into a memcopy
+  a[1] = OO(f: 2)
+  a[i+1] = a[i] # This must not =sink, but =copy
+  inc i
+  echo a[i-1] # (f: 1)
+
+potentialSelfAssign (var xi = 0; xi)
+
+
+#--------------------------------------------------------------------
+echo "part-to-whole assigment:"
+
+type
+  Tree = object
+    children: seq[Tree]
+
+  TreeDefaultHooks = object
+    children: seq[TreeDefaultHooks]
+
+proc `=destroy`(x: var Tree) = echo "destroy"
+proc `=sink`(x: var Tree, y: Tree) = echo "sink"
+proc `=copy`(x: var Tree, y: Tree) = echo "copy"
+
+proc partToWholeSeq =
+  var t = Tree(children: @[Tree()])
+  t = t.children[0] # This should be sunk, but with the special transform (tmp = t.children[0]; wasMoved(0); `=sink`(t, tmp))
+
+  var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()])
+  tc = tc.children[0] # Ditto; if this were sunk with the normal transform (`=sink`(t, t.children[0]); wasMoved(t.children[0]))
+  echo tc             #        then it would crash because t.children[0] does not exist after the call to `=sink`
+
+partToWholeSeq()
+
+proc partToWholeSeqRTIndex =
+  var i = 0
+  var t = Tree(children: @[Tree()])
+  t = t.children[i] # See comment in partToWholeSeq
+
+  var tc = TreeDefaultHooks(children: @[TreeDefaultHooks()])
+  tc = tc.children[i] # See comment in partToWholeSeq
+  echo tc
+
+partToWholeSeqRTIndex()
+
+type List = object
+  next: ref List
+
+proc `=destroy`(x: var List) = echo "destroy"
+proc `=sink`(x: var List, y: List) = echo "sink"
+proc `=copy`(x: var List, y: List) = echo "copy"
+
+proc partToWholeUnownedRef =
+  var t = List(next: new List)
+  t = t.next[] # Copy because t.next is not an owned ref, and thus t.next[] cannot be moved
+
+partToWholeUnownedRef()
+
+
+#--------------------------------------------------------------------
+# test that nodes that get copied during the transformation
+# (like dot exprs) don't loose their firstWrite/lastRead property
+
+type
+  OOO = object
+    initialized: bool
+
+  C = object
+    o: OOO
+
+proc `=destroy`(o: var OOO) =
+  doAssert o.initialized, "OOO was destroyed before initialization!"
+
+proc initO(): OOO =
+  OOO(initialized: true)
+
+proc initC(): C =
+  C(o: initO())
+
+proc pair(): tuple[a: C, b: C] =
+  result = (a: initC(), b: initC())# <- when firstWrite tries to find this node to start its analysis it fails, because injectdestructors uses copyTree/shallowCopy
+
+discard pair()
+
+
+# bug #17450
+proc noConsume(x: OO) {.nosinks.} = echo x
+
+proc main3 =
+  var i = 1
+  noConsume:
+    block:
+      OO(f: i)
+
+main3()
+
+# misc
+proc smoltest(x: bool): bool =
+  while true:
+    if true: return x
+
+discard smoltest(true)
+
+# bug #18002
+type
+  TTypeAttachedOp = enum
+    attachedAsgn
+    attachedSink
+    attachedTrace
+
+  PNode = ref object
+    discard
+
+proc genAddrOf(n: PNode) =
+  assert n != nil, "moved?!"
+
+proc atomicClosureOp =
+  let x = PNode()
+
+  genAddrOf:
+    block:
+      x
+
+  case attachedTrace
+  of attachedSink: discard
+  of attachedAsgn: discard
+  of attachedTrace: genAddrOf(x)
+
+atomicClosureOp()
+
+
+template assertEq(a, b: untyped): untyped =
+  block:
+    let
+      aval = a
+      bval = b
+
+    if aval != bval:
+      quit "bug!"
+
+proc convoluted =
+  let _ = (;
+    var val1: string;
+    if true: val1 = "22"
+    true
+  )
+
+  assertEq val1, "22"
+  assertEq val1, "22"
+
+convoluted()
diff --git a/tests/arc/tmovebugcopy.nim b/tests/arc/tmovebugcopy.nim
new file mode 100644
index 000000000..ec4315777
--- /dev/null
+++ b/tests/arc/tmovebugcopy.nim
@@ -0,0 +1,526 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: '''5
+(w: 5)
+(w: -5)
+c.text = hello
+c.text = hello
+p.text = hello
+p.toks = @["hello"]
+c.text = hello
+c[].text = hello
+pA.text = hello
+pA.toks = @["hello"]
+c.text = hello
+c.text = hello
+pD.text = hello
+pD.toks = @["hello"]
+c.text = hello
+c.text = hello
+pOD.text = hello
+pOD.toks = @["hello"]
+fff
+fff
+2
+fff
+fff
+2
+fff
+fff
+2
+mmm
+fff
+fff
+fff
+3
+mmm
+sink me (sink)
+assign me (not sink)
+sink me (not sink)
+sinked and not optimized to a bitcopy
+sinked and not optimized to a bitcopy
+sinked and not optimized to a bitcopy
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+(data: @[0, 0])
+100
+hey
+hey
+(a: "a", b: 2)
+ho
+(a: "b", b: 3)
+(b: "b", a: 2)
+ho
+(b: "a", a: 3)
+hey
+break
+break
+hey
+ho
+hey
+ho
+ho
+king
+live long; long live
+king
+hi
+try
+bye
+'''
+"""
+
+# move bug
+type
+  TMyObj = object
+    p: pointer
+    len: int
+
+var destroyCounter = 0
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil:
+    dealloc o.p
+    o.p = nil
+    inc destroyCounter
+
+proc `=copy`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = alloc(src.len)
+  dst.len = src.len
+
+proc `=sink`(dst: var TMyObj, src: TMyObj) =
+  `=destroy`(dst)
+  dst.p = src.p
+  dst.len = src.len
+
+type
+  TObjKind = enum Z, A, B
+  TCaseObj = object
+    case kind: TObjKind
+    of Z: discard
+    of A:
+      x1: int # this int plays important role
+      x2: TMyObj
+    of B:
+      y: TMyObj
+
+proc use(a: TCaseObj) = discard
+
+proc moveBug(i: var int) =
+  var a: array[2, TCaseObj]
+  a[i] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 1
+  a[i+1] = a[i] # 2
+  inc i
+  use(a[i-1])
+
+var x = 0
+moveBug(x)
+
+proc moveBug2(): (TCaseObj, TCaseObj) =
+  var a: array[2, TCaseObj]
+  a[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5)))
+  a[1] = a[0] # can move 3
+  result[0] = TCaseObj(kind: A, x1: 5000, x2: TMyObj(len: 5, p: alloc(5))) # 4
+  result[1] = result[0] # 5
+
+proc main =
+  discard moveBug2()
+
+main()
+echo destroyCounter
+
+# bug #13314
+
+type
+  O = object
+    v: int
+  R = ref object
+    w: int
+
+proc `$`(r: R): string = $r[]
+
+proc tbug13314 =
+  var t5 = R(w: 5)
+  var execute = proc () =
+    echo t5
+
+  execute()
+  t5.w = -5
+  execute()
+
+tbug13314()
+
+#-------------------------------------------------------------------------
+# bug #13368
+
+import strutils
+proc procStat() =
+  for line in @["a b", "c d", "e f"]:
+    let cols = line.splitWhitespace(maxSplit=1)
+    let x = cols[0]
+    let (nm, rest) = (cols[0], cols[1])
+procStat()
+
+
+# bug #14269
+
+import sugar, strutils
+
+type
+  Cursor = object
+    text: string
+  Parsed = object
+    text: string
+    toks: seq[string]
+
+proc tokenize(c: var Cursor): seq[string] =
+  dump c.text
+  return c.text.splitWhitespace()
+
+proc parse(): Parsed =
+  var c = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c.tokenize) # note: c.tokenized uses c.text
+
+let p = parse()
+dump p.text
+dump p.toks
+
+
+proc tokenizeA(c: ptr Cursor): seq[string] =
+  dump c[].text
+  return c[].text.splitWhitespace()
+
+proc parseA(): Parsed =
+  var c = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c.addr.tokenizeA) # note: c.tokenized uses c.text
+
+let pA = parseA()
+dump pA.text
+dump pA.toks
+
+
+proc tokenizeD(c: Cursor): seq[string] =
+  dump c.text
+  return c.text.splitWhitespace()
+
+proc parseD(): Parsed =
+  var c = cast[ptr Cursor](alloc0(sizeof(Cursor)))
+  c[] = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c[].tokenizeD) # note: c.tokenized uses c.text
+
+let pD = parseD()
+dump pD.text
+dump pD.toks
+
+# Bug would only pop up with owned refs
+proc tokenizeOD(c: Cursor): seq[string] =
+  dump c.text
+  return c.text.splitWhitespace()
+
+proc parseOD(): Parsed =
+  var c = new Cursor
+  c[] = Cursor(text: "hello")
+  dump c.text
+  return Parsed(text: c.text, toks: c[].tokenizeOD) # note: c.tokenized uses c.text
+
+let pOD = parseOD()
+dump pOD.text
+dump pOD.toks
+
+when false:
+  # Bug would only pop up with owned refs and implicit derefs, but since they don't work together..
+  {.experimental: "implicitDeref".}
+  proc tokenizeOHD(c: Cursor): seq[string] =
+    dump c.text
+    return c.text.splitWhitespace()
+
+  proc parseOHD(): Parsed =
+    var c = new Cursor
+    c[] = Cursor(text: "hello")
+    dump c.text
+    return Parsed(text: c.text, toks: c.tokenizeOHD) # note: c.tokenized uses c.text
+
+  let pOHD = parseOHD()
+  dump pOHD.text
+  dump pOHD.toks
+
+# bug #13456
+
+iterator combinations[T](s: openArray[T], k: int): seq[T] =
+  let n = len(s)
+  assert k >= 0 and k <= n
+  var pos = newSeq[int](k)
+  var current = newSeq[T](k)
+  for i in 0..k-1:
+    pos[k-i-1] = i
+  var done = false
+  while not done:
+    for i in 0..k-1:
+      current[i] = s[pos[k-i-1]]
+    yield current
+    var i = 0
+    while i < k:
+      pos[i] += 1
+      if pos[i] < n-i:
+        for j in 0..i-1:
+          pos[j] = pos[i] + i - j
+        break
+      i += 1
+    if i >= k:
+      break
+
+type
+  UndefEx = object of ValueError
+
+proc main2 =
+  var delayedSyms = @[1, 2, 3]
+  var unp: seq[int]
+  block myb:
+    for a in 1 .. 2:
+      if delayedSyms.len > a:
+        unp = delayedSyms
+        for t in unp.combinations(a + 1):
+          try:
+            var h = false
+            for k in t:
+              echo "fff"
+            if h: continue
+            if true:
+              raise newException(UndefEx, "forward declaration")
+            break myb
+          except UndefEx:
+            echo t.len
+        echo "mmm"
+
+main2()
+
+
+
+type ME = object
+  who: string
+
+proc `=copy`(x: var ME, y: ME) =
+  if y.who.len > 0: echo "assign ",y.who
+
+proc `=sink`(x: var ME, y: ME) =
+  if y.who.len > 0: echo "sink ",y.who
+
+var dump: ME
+template use(x) = dump = x
+template def(x) = x = dump
+
+var c = true
+
+proc shouldSink() =
+  var x = ME(who: "me (sink)")
+  use(x) # we analyse this
+  if c: def(x)
+  else: def(x)
+  use(x) # ok, with the [else] part.
+
+shouldSink()
+
+dump = ME()
+
+proc shouldNotSink() =
+  var x = ME(who: "me (not sink)")
+  use(x) # we analyse this
+  if c: def(x)
+  use(x) # Not ok without the '[else]'
+
+shouldNotSink()
+
+# bug #14568
+import os
+
+type O2 = object
+  s: seq[int]
+
+proc `=sink`(dest: var O2, src: O2) =
+  echo "sinked and not optimized to a bitcopy"
+
+var testSeq: O2
+
+proc update() =
+  # testSeq.add(0) # uncommenting this line fixes the leak
+  testSeq = O2(s: @[])
+  testSeq.s.add(0)
+
+for i in 1..3:
+  update()
+
+
+# bug #14961
+type
+  Foo = object
+    data: seq[int]
+
+proc initFoo(len: int): Foo =
+  result = (let s = newSeq[int](len); Foo(data: s) )
+
+var f = initFoo(2)
+echo initFoo(2)
+
+proc initFoo2(len: int) =
+  echo   if true:
+             let s = newSeq[int](len); Foo(data: s)
+         else:
+             let s = newSeq[int](len); Foo(data: s)
+
+initFoo2(2)
+
+proc initFoo3(len: int) =
+  echo (block:
+         let s = newSeq[int](len); Foo(data: s))
+
+initFoo3(2)
+
+proc initFoo4(len: int) =
+  echo (let s = newSeq[int](len); Foo(data: s))
+
+initFoo4(2)
+
+proc initFoo5(len: int) =
+  echo (case true
+        of true:
+          let s = newSeq[int](len); Foo(data: s)
+        of false:
+          let s = newSeq[int](len); Foo(data: s))
+
+initFoo5(2)
+
+proc initFoo6(len: int) =
+  echo (block:
+          try:
+            let s = newSeq[int](len); Foo(data: s)
+          finally: discard)
+
+initFoo6(2)
+
+proc initFoo7(len: int) =
+  echo (block:
+          try:
+            raise newException(CatchableError, "sup")
+            let s = newSeq[int](len); Foo(data: s)
+          except CatchableError:
+            let s = newSeq[int](len); Foo(data: s) )
+
+initFoo7(2)
+
+
+# bug #14902
+iterator zip[T](s: openArray[T]): (T, T) =
+  var i = 0
+  while i < 10:
+    yield (s[i mod 2], s[i mod 2 + 1])
+    inc i
+
+var lastMem = int.high
+
+proc leak =
+  const len = 10
+  var x = @[newString(len), newString(len), newString(len)]
+
+  var c = 0
+  for (a, b) in zip(x):
+    let newMem = getOccupiedMem()
+    assert newMem <= lastMem
+    lastMem = newMem
+    c += a.len
+  echo c
+
+leak()
+
+
+proc consume(a: sink string) = echo a
+
+proc weirdScopes =
+  if (let a = "hey"; a.len > 0):
+    echo a
+
+  while (let a = "hey"; a.len > 0):
+    echo a
+    break
+
+  var a = block: (a: "a", b: 2)
+  echo a
+  (discard; a) = (echo "ho"; (a: "b", b: 3))
+  echo a
+
+  var b = try: (b: "b", a: 2)
+          except: raise
+  echo b
+  (discard; b) = (echo "ho"; (b: "a", a: 3))
+  echo b
+
+  var s = "break"
+  consume((echo "hey"; s))
+  echo s
+
+  echo (block:
+          var a = "hey"
+          (echo "hey"; "ho"))
+
+  var b2 = "ho"
+  echo (block:
+          var a = "hey"
+          (echo "hey"; b2))
+  echo b2
+
+  type status = enum
+    alive
+
+  var king = "king"
+  echo (block:
+          var a = "a"
+          when true:
+            var b = "b"
+            case alive
+            of alive:
+              try:
+                var c = "c"
+                if true:
+                  king
+                else:
+                  "the abyss"
+              except:
+                echo "he ded"
+                "dead king")
+  echo "live long; long live"
+  echo king
+
+weirdScopes()
+
+
+# bug #14985
+proc getScope(): string =
+  if true:
+    "hi"
+  else:
+    "else"
+
+echo getScope()
+
+proc getScope3(): string =
+  try:
+    "try"
+  except:
+    "except"
+
+echo getScope3()
+
+proc getScope2(): string =
+  case true
+  of true:
+    "bye"
+  else:
+    "else"
+
+echo getScope2()
diff --git a/tests/arc/tnewseq_legacy.nim b/tests/arc/tnewseq_legacy.nim
new file mode 100644
index 000000000..4730d2c2b
--- /dev/null
+++ b/tests/arc/tnewseq_legacy.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "(allocCount: 201, deallocCount: 201)"
+  cmd: "nim c --gc:orc -d:nimAllocStats $file"
+"""
+
+proc main(prefix: string) =
+  var c: seq[string]
+  for i in 0..<100:
+    newSeq(c, 100)
+    c[i] = prefix & $i
+
+main("abc")
+echo getAllocStats()
diff --git a/tests/arc/top_no_cursor2.nim b/tests/arc/top_no_cursor2.nim
new file mode 100644
index 000000000..5dfde57aa
--- /dev/null
+++ b/tests/arc/top_no_cursor2.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''true
+true
+true
+true
+true'''
+  cmd: "nim c --gc:arc $file"
+"""
+# bug #15361
+
+type
+  ErrorNodeKind = enum Branch, Leaf
+  Error = ref object
+    case kind: ErrorNodeKind
+      of Branch:
+        left: Error
+        right: Error
+      of Leaf:
+        leafError: string
+    input: string
+
+proc ret(input: string, lefterr, righterr: Error): Error =
+  result = Error(kind: Branch, left: lefterr, right: righterr, input: input)
+
+proc parser() =
+  var rerrors: Error
+  let lerrors = Error(
+    kind: Leaf,
+    leafError: "first error",
+    input: "123 ;"
+  )
+  # If you remove "block" - everything works
+  block:
+    let rresult = Error(
+      kind: Leaf,
+      leafError: "second error",
+      input: ";"
+    )
+    # this assignment is needed too
+    rerrors = rresult
+
+  # Returns Error(kind: Branch, left: lerrors, right: rerrors, input: "some val")
+  # needs to be a proc call for some reason, can't inline the result
+  var data = ret(input = "some val", lefterr = lerrors, righterr = rerrors)
+
+  echo data.left.leafError == "first error"
+  echo data.left.input == "123 ;"
+  # stacktrace shows this line
+  echo data.right.leafError == "second error"
+  echo data.right.input == ";"
+  echo data.input == "some val"
+
+parser()
diff --git a/tests/arc/topenarray.nim b/tests/arc/topenarray.nim
new file mode 100644
index 000000000..ba91666ba
--- /dev/null
+++ b/tests/arc/topenarray.nim
@@ -0,0 +1,86 @@
+discard """
+  input: "hi"
+  output: '''
+hi
+Nim
+'''
+  matrix: "--gc:arc -d:useMalloc; --gc:arc"
+"""
+{.experimental: "views".}
+
+block: # bug 18627
+  proc setPosition(params: openArray[string]) =
+    for i in params.toOpenArray(0, params.len - 1):
+      echo i
+
+  proc uciLoop() =
+    let params = @[readLine(stdin)]
+    setPosition(params)
+
+  uciLoop()
+
+  proc uciLoop2() =
+    let params = @["Nim"]
+    for i in params.toOpenArray(0, params.len - 1):
+      echo i
+  uciLoop2()
+
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+
+block: # bug #20954
+  block:
+    doAssertRaises(IndexDefect):
+      var v: array[10, int]
+
+      echo len(toOpenArray(v, 20, 30))
+
+  block:
+    doAssertRaises(IndexDefect):
+      var v: seq[int]
+
+      echo len(toOpenArray(v, 20, 30))
+
+# bug #20422
+
+proc f(a: var string) =
+  var v = a.toOpenArray(1, 3)
+  v[0] = 'a'
+
+var a = "Hello"
+f(a)
+doAssert a == "Hallo"
+
+# bug #22132
+block:
+  func foo[T](arr: openArray[T], idx: int = arr.low): string =
+    doAssert idx == 0
+    return $arr
+
+  let bug = ["0", "c", "a"]
+
+  let str = foo(bug)
+
+  const expected = """["0", "c", "a"]"""
+  doAssert str == expected
+
+  const noBugConst = ["0", "c", "a"]
+  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/topt_cursor.nim b/tests/arc/topt_cursor.nim
new file mode 100644
index 000000000..794132921
--- /dev/null
+++ b/tests/arc/topt_cursor.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''("string here", 80)'''
+  cmd: '''nim c --gc:arc --expandArc:main --expandArc:sio --hint:Performance:off $file'''
+  nimout: '''--expandArc: main
+
+var
+  x_cursor
+  :tmpD
+try:
+  x_cursor = ("hi", 5)
+  if cond:
+    x_cursor = ("different", 54) else:
+    x_cursor = ("string here", 80)
+  echo [
+    :tmpD = `$$`(x_cursor)
+    :tmpD]
+finally:
+  `=destroy`(:tmpD)
+-- end of expandArc ------------------------
+--expandArc: sio
+
+block :tmp:
+  var x_cursor
+  var f = open("debug.txt", fmRead, 8000)
+  try:
+    var res
+    try:
+      res = newStringOfCap(80)
+      block :tmp_1:
+        while readLine(f, res):
+          x_cursor = res
+          echo [x_cursor]
+    finally:
+      `=destroy`(res)
+  finally:
+    close(f)
+-- end of expandArc ------------------------'''
+"""
+
+proc main(cond: bool) =
+  var x = ("hi", 5) # goal: computed as cursor
+
+  x = if cond:
+        ("different", 54)
+      else:
+        ("string here", 80)
+
+  echo x
+
+main(false)
+
+proc sio =
+  for x in lines("debug.txt"):
+    echo x
+
+if false:
+  sio()
diff --git a/tests/arc/topt_cursor2.nim b/tests/arc/topt_cursor2.nim
new file mode 100644
index 000000000..4b566ed24
--- /dev/null
+++ b/tests/arc/topt_cursor2.nim
@@ -0,0 +1,76 @@
+discard """  
+  cmd: '''nim c --gc:arc $file'''
+  output: '''emptyemptyempty
+inner destroy
+'''
+"""
+
+# bug #15039
+
+import lists
+
+type
+  Token = ref object of RootObj
+    children: DoublyLinkedList[Token]
+
+  Paragraph = ref object of Token
+
+method `$`(token: Token): string {.base.} =
+  result = "empty"
+
+method `$`(token: Paragraph): string =
+  if token.children.head == nil:
+    result = ""
+  else:
+    for c in token.children:
+      result.add $c
+
+proc parseLeafBlockInlines(token: Token) =
+  token.children.append(Token())
+  token.children.append(Token()) # <-- this one AAA
+
+  var emNode = newDoublyLinkedNode(Token())
+  var i = 0
+
+  var it = token.children.head
+  while it != nil:
+    var nxt = it.next  # this is not a cursor, it takes over ownership.
+    var childNode = it
+    if i == 0:
+      childNode.next = emNode # frees the object allocated in line 29 marked with AAA
+    elif i == 1:
+      emNode.next = childNode  #
+    it = nxt # incref on freed data, 'nxt' is freed
+    inc i
+
+proc parse() =
+  var token = Token()
+  token.children.append Paragraph()
+  parseLeafBlockInlines(token.children.head.value)
+  for children in token.children:
+    echo children
+
+parse()
+
+
+#------------------------------------------------------------------------------
+# issue #15629
+
+type inner = object
+type outer = ref inner
+
+proc `=destroy`(b: var inner) =
+  echo "inner destroy"
+
+proc newOuter(): outer =
+  new(result)
+
+type holder = object
+  contents: outer
+
+proc main() = 
+  var t: holder
+  t.contents = newOuter()
+  
+main()
+
diff --git a/tests/arc/topt_no_cursor.nim b/tests/arc/topt_no_cursor.nim
new file mode 100644
index 000000000..0a4984a69
--- /dev/null
+++ b/tests/arc/topt_no_cursor.nim
@@ -0,0 +1,376 @@
+discard """
+  nimoutFull: true
+  cmd: '''nim c -r --warnings:off --hints:off --mm:arc --expandArc:newTarget --expandArc:delete --expandArc:p1 --expandArc:tt --hint:Performance:off --assertions:off --expandArc:extractConfig --expandArc:mergeShadowScope --expandArc:check $file'''
+  nimout: '''
+--expandArc: newTarget
+
+var
+  splat
+  :tmp
+  :tmp_1
+splat = splitDrive do:
+  let blitTmp = path
+  blitTmp
+:tmp = splat.drive
+`=wasMoved`(splat.drive)
+:tmp_1 = splat.path_1
+`=wasMoved`(splat.path_1)
+result = (
+  let blitTmp_1 = :tmp
+  blitTmp_1,
+  let blitTmp_2 = :tmp_1
+  blitTmp_2)
+`=destroy`(splat)
+-- end of expandArc ------------------------
+--expandArc: delete
+
+var
+  sibling
+  saved
+`=copy`(sibling, target.parent.left)
+`=copy`(saved, sibling.right)
+`=copy`(sibling.right, saved.left)
+`=sink`(sibling.parent, saved)
+`=destroy`(sibling)
+-- end of expandArc ------------------------
+--expandArc: p1
+
+var
+  lresult
+  lvalue
+  lnext
+  tmpTupleAsgn
+lresult = @[123]
+tmpTupleAsgn = (
+  let blitTmp = lresult
+  blitTmp, ";")
+lvalue = tmpTupleAsgn[0]
+lnext = tmpTupleAsgn[1]
+`=sink`(result.value, move lvalue)
+`=destroy`(lnext)
+`=destroy_1`(lvalue)
+-- end of expandArc ------------------------
+--expandArc: tt
+
+var
+  it_cursor
+  a
+  :tmpD
+  :tmpD_1
+  :tmpD_2
+try:
+  it_cursor = x
+  a = (
+    :tmpD = `=dup`(it_cursor.key)
+    :tmpD,
+    :tmpD_1 = `=dup`(it_cursor.val)
+    :tmpD_1)
+  echo [
+    :tmpD_2 = `$$`(a)
+    :tmpD_2]
+finally:
+  `=destroy`(:tmpD_2)
+  `=destroy_1`(a)
+-- end of expandArc ------------------------
+--expandArc: extractConfig
+
+var lan_ip
+try:
+  lan_ip = ""
+  block :tmp:
+    var line
+    var i = 0
+    let L = len(txt)
+    block :tmp_1:
+      while i < L:
+        var splitted
+        try:
+          line = txt[i]
+          splitted = split(line, " ", -1)
+          if splitted[0] == "opt":
+            `=copy`(lan_ip, splitted[1])
+          echo [lan_ip]
+          echo [splitted[1]]
+          {.push, overflowChecks: false.}
+          inc(i, 1)
+          {.pop.}
+        finally:
+          `=destroy`(splitted)
+finally:
+  `=destroy_1`(lan_ip)
+-- end of expandArc ------------------------
+--expandArc: mergeShadowScope
+
+var shadowScope
+`=copy`(shadowScope, c.currentScope)
+rawCloseScope(c)
+block :tmp:
+  var sym
+  var i = 0
+  let L = len(shadowScope.symbols)
+  block :tmp_1:
+    while i < L:
+      var :tmpD
+      sym = shadowScope.symbols[i]
+      addInterfaceDecl(c):
+        :tmpD = `=dup`(sym)
+        :tmpD
+      {.push, overflowChecks: false.}
+      inc(i, 1)
+      {.pop.}
+`=destroy`(shadowScope)
+-- end of expandArc ------------------------
+--expandArc: check
+
+var par
+this.isValid = fileExists(this.value)
+if dirExists(this.value):
+  var :tmpD
+  par = (dir:
+    :tmpD = `=dup`(this.value)
+    :tmpD, front: "") else:
+  var
+    :tmpD_1
+    :tmpD_2
+    :tmpD_3
+  par = (dir_1: parentDir(this.value), front_1:
+    :tmpD_1 = `=dup`(
+      :tmpD_3 = splitDrive do:
+        :tmpD_2 = `=dup`(this.value)
+        :tmpD_2
+      :tmpD_3.path)
+    :tmpD_1)
+  `=destroy`(:tmpD_3)
+if dirExists(par.dir):
+  `=sink`(this.matchDirs, getSubDirs(par.dir, par.front))
+else:
+  `=sink`(this.matchDirs, [])
+`=destroy`(par)
+-- end of expandArc ------------------------
+--expandArc: check
+
+check(this)
+-- end of expandArc ------------------------
+(package: "", ext: "meo")
+doing shady stuff...
+3
+6
+(@[1], @[2])
+192.168.0.1
+192.168.0.1
+192.168.0.1
+192.168.0.1
+'''
+"""
+
+import os, std/private/ntpath
+
+type Target = tuple[package, ext: string]
+
+proc newTarget*(path: string): Target =
+  let splat = path.splitDrive
+  result = (package: splat.drive, ext: splat.path)
+
+echo newTarget("meo")
+
+type
+  Node = ref object
+    left, right, parent: Node
+    value: int
+
+proc delete(target: var Node) =
+  var sibling = target.parent.left # b3
+  var saved = sibling.right # b3.right -> r4
+
+  sibling.right = saved.left # b3.right -> r4.left = nil
+  sibling.parent = saved # b3.parent -> r5 = r4
+
+  #[after this proc:
+        b 5
+      /   \
+    b 3     b 6
+  ]#
+
+
+#[before:
+      r 5
+    /   \
+  b 3    b 6 - to delete
+  /    \
+empty  r 4
+]#
+proc main =
+  var five = Node(value: 5)
+
+  var six = Node(value: 6)
+  six.parent = five
+  five.right = six
+
+  var three = Node(value: 3)
+  three.parent = five
+  five.left = three
+
+  var four = Node(value: 4)
+  four.parent = three
+  three.right = four
+
+  echo "doing shady stuff..."
+  delete(six)
+  # need both of these echos
+  echo five.left.value
+  echo five.right.value
+
+main()
+
+type
+  Maybe = object
+    value: seq[int]
+
+proc p1(): Maybe =
+  let lresult = @[123]
+  var lvalue: seq[int]
+  var lnext: string
+  (lvalue, lnext) = (lresult, ";")
+
+  result.value = move lvalue
+
+proc tissue15130 =
+  doAssert p1().value == @[123]
+
+tissue15130()
+
+type
+  KeyValue = tuple[key, val: seq[int]]
+
+proc tt(x: KeyValue) =
+  var it = x
+  let a = (it.key, it.val)
+  echo a
+
+proc encodedQuery =
+  var query: seq[KeyValue]
+  query.add (key: @[1], val: @[2])
+
+  for elem in query:
+    elem.tt()
+
+encodedQuery()
+
+# bug #15147
+
+proc s(input: string): (string, string) =
+  result = (";", "")
+
+proc charmatch(input: string): (string, string) =
+  result = ("123", input[0 .. input.high])
+
+proc plus(input: string) =
+  var
+    lvalue, rvalue: string # cursors
+    lnext: string # must be cursor!!!
+    rnext: string # cursor
+  let lresult = charmatch(input)
+  (lvalue, lnext) = lresult
+
+  let rresult = s(lnext)
+  (rvalue, rnext) = rresult
+
+plus("123;")
+
+func substrEq(s: string, pos: int, substr: string): bool =
+  var i = 0
+  var length = substr.len
+  while i < length and pos+i < s.len and s[pos+i] == substr[i]:
+    inc i
+  return i == length
+
+template stringHasSep(s: string, index: int, sep: string): bool =
+  s.substrEq(index, sep)
+
+template splitCommon(s, sep, maxsplit, sepLen) =
+  var last = 0
+  var splits = maxsplit
+
+  while last <= len(s):
+    var first = last
+    while last < len(s) and not stringHasSep(s, last, sep):
+      inc(last)
+    if splits == 0: last = len(s)
+    yield substr(s, first, last-1)
+    if splits == 0: break
+    dec(splits)
+    inc(last, sepLen)
+
+iterator split(s: string, sep: string, maxsplit = -1): string =
+  splitCommon(s, sep, maxsplit, sep.len)
+
+template accResult(iter: untyped) =
+  result = @[]
+  for x in iter: add(result, x)
+
+func split*(s: string, sep: string, maxsplit = -1): seq[string] =
+  accResult(split(s, sep, maxsplit))
+
+
+let txt = @["opt 192.168.0.1", "static_lease 192.168.0.1"]
+
+# bug #17033
+
+proc extractConfig() =
+  var lan_ip = ""
+
+  for line in txt:
+    let splitted = line.split(" ")
+    if splitted[0] == "opt":
+      lan_ip = splitted[1] # "borrow" is conditional and inside a loop.
+      # Not good enough...
+      # we need a flag that live-ranges are disjoint
+    echo lan_ip
+    echo splitted[1] # Without this line everything works
+
+extractConfig()
+
+
+type
+  Symbol = ref object
+    name: string
+
+  Scope = ref object
+    parent: Scope
+    symbols: seq[Symbol]
+
+  PContext = ref object
+    currentScope: Scope
+
+proc rawCloseScope(c: PContext) =
+  c.currentScope = c.currentScope.parent
+
+proc addInterfaceDecl(c: PContext; s: Symbol) =
+  c.currentScope.symbols.add s
+
+proc mergeShadowScope*(c: PContext) =
+  let shadowScope = c.currentScope
+  c.rawCloseScope
+  for sym in shadowScope.symbols:
+    c.addInterfaceDecl(sym)
+
+mergeShadowScope(PContext(currentScope: Scope(parent: Scope())))
+
+type
+  Foo = ref object
+    isValid*: bool
+    value*: string
+    matchDirs*: seq[string]
+
+proc getSubDirs(parent, front: string): seq[string] = @[]
+
+method check(this: Foo) {.base.} =
+  this.isValid = fileExists(this.value)
+  let par = if dirExists(this.value): (dir: this.value, front: "")
+            else: (dir: parentDir(this.value), front: splitDrive(this.value).path)
+  if dirExists(par.dir):
+    this.matchDirs = getSubDirs(par.dir, par.front)
+  else:
+    this.matchDirs = @[]
+
+check(Foo())
diff --git a/tests/arc/topt_refcursors.nim b/tests/arc/topt_refcursors.nim
new file mode 100644
index 000000000..8c638a4a1
--- /dev/null
+++ b/tests/arc/topt_refcursors.nim
@@ -0,0 +1,54 @@
+discard """
+  output: ''''''
+  cmd: '''nim c --gc:arc --expandArc:traverse --hint:Performance:off $file'''
+  nimout: '''
+--expandArc: traverse
+
+var
+  it_cursor
+  jt
+try:
+  it_cursor = root
+  block :tmp:
+    while (
+      not (it_cursor == nil)):
+      echo [it_cursor.s]
+      it_cursor = it_cursor.ri
+  `=copy`(jt, root)
+  block :tmp_1:
+    while (
+      not (jt == nil)):
+      var ri_1
+      try:
+        `=copy`(ri_1, jt.ri)
+        echo [jt.s]
+        `=sink`(jt, ri_1)
+        `=wasMoved`(ri_1)
+      finally:
+        `=destroy`(ri_1)
+finally:
+  `=destroy`(jt)
+-- end of expandArc ------------------------
+'''
+"""
+
+type
+  Node = ref object
+    le, ri: Node
+    s: string
+
+proc traverse(root: Node) =
+  var it = root
+  while it != nil:
+    echo it.s
+    it = it.ri
+
+  var jt = root
+  while jt != nil:
+    let ri = jt.ri
+    echo jt.s
+    jt = ri
+
+traverse(nil)
+
+# XXX: This optimization is not sound
diff --git a/tests/arc/topt_wasmoved_destroy_pairs.nim b/tests/arc/topt_wasmoved_destroy_pairs.nim
new file mode 100644
index 000000000..c96340a30
--- /dev/null
+++ b/tests/arc/topt_wasmoved_destroy_pairs.nim
@@ -0,0 +1,94 @@
+discard """
+  output: ''''''
+  cmd: '''nim c --gc:arc --expandArc:main --expandArc:tfor --hint:Performance:off $file'''
+  nimout: '''
+--expandArc: main
+
+var
+  a
+  b
+  x
+x = f()
+if cond:
+  add(a):
+    let blitTmp = x
+    blitTmp
+else:
+  add(b):
+    let blitTmp_1 = x
+    blitTmp_1
+`=destroy`(b)
+`=destroy`(a)
+-- end of expandArc ------------------------
+--expandArc: tfor
+
+var
+  a
+  b
+  x
+try:
+  x = f()
+  block :tmp:
+    var i_cursor
+    mixin inc
+    var i_1 = 0
+    block :tmp_1:
+      while i_1 < 4:
+        var :tmpD
+        i_cursor = i_1
+        if i_cursor == 2:
+          return
+        add(a):
+          :tmpD = `=dup`(x)
+          :tmpD
+        inc i_1, 1
+  if cond:
+    add(a):
+      let blitTmp = x
+      `=wasMoved`(x)
+      blitTmp
+  else:
+    add(b):
+      let blitTmp_1 = x
+      `=wasMoved`(x)
+      blitTmp_1
+finally:
+  `=destroy`(x)
+  `=destroy_1`(b)
+  `=destroy_1`(a)
+-- end of expandArc ------------------------
+'''
+"""
+
+proc f(): seq[int] =
+  @[1, 2, 3]
+
+proc main(cond: bool) =
+  var a, b: seq[seq[int]]
+  var x = f()
+  if cond:
+    a.add x
+  else:
+    b.add x
+
+# all paths move 'x' so no wasMoved(x); destroy(x) pair should be left in the
+# AST.
+
+main(false)
+
+
+proc tfor(cond: bool) =
+  var a, b: seq[seq[int]]
+
+  var x = f()
+
+  for i in 0 ..< 4:
+    if i == 2: return
+    a.add x
+
+  if cond:
+    a.add x
+  else:
+    b.add x
+
+tfor(false)
diff --git a/tests/arc/torc_basic_test.nim b/tests/arc/torc_basic_test.nim
new file mode 100644
index 000000000..73039fad7
--- /dev/null
+++ b/tests/arc/torc_basic_test.nim
@@ -0,0 +1,138 @@
+discard """
+  output: "MEM 0"
+  cmd: "nim c --gc:orc $file"
+"""
+
+type
+  Node = ref object
+    name: char
+    sccId: int
+    #a: array[3, Node]
+    a0, a1, a2: Node
+    rc: int
+
+proc edge(a, b: Node) =
+  inc b.rc
+  if a.a0 == nil: a.a0 = b
+  elif a.a1 == nil: a.a1 = b
+  else: a.a2 = b
+  when false:
+    var i = 0
+    while a.a[i] != nil: inc i
+    a.a[i] = b
+
+proc createNode(name: char): Node =
+  new result
+  result.name = name
+
+#[
+
+     +--------------------------------+
+     v                                |
++---------+      +------+             |
+|         |      |      |             |
+|  A      +----->+      |      +------+------+
++--+------+      |      |      |             |
+   |             |      |      |     C       ------------>  G  <--|
+   |             |  R   |      |             |
++--v------+      |      |      +-------------+
+|         |      |      |        ^
+|   B     <------+      |        |
+|         |      |      +--------+
++---------+      |      |
+                 +------+
+
+]#
+proc use(x: Node) = discard
+
+proc main =
+  let a = createNode('A')
+  let b = createNode('B')
+  let r = createNode('R')
+  let c = createNode('C')
+
+  a.edge b
+  a.edge r
+
+  r.edge b
+  r.edge c
+
+  let g = createNode('G')
+  g.edge g
+  g.edge g
+
+  c.edge g
+  c.edge a
+
+  use g
+  use b
+
+proc buildComplexGraph: Node =
+  # see https://en.wikipedia.org/wiki/Strongly_connected_component for the
+  # graph:
+  let a = createNode('a')
+  let b = createNode('b')
+  let c = createNode('c')
+  let d = createNode('d')
+  let e = createNode('e')
+
+  a.edge c
+  c.edge b
+  c.edge e
+  b.edge a
+  d.edge c
+  e.edge d
+
+
+  let f = createNode('f')
+  b.edge f
+  e.edge f
+
+  let g = createNode('g')
+  let h = createNode('h')
+  let i = createNode('i')
+
+  f.edge g
+  f.edge i
+  g.edge h
+  h.edge i
+  i.edge g
+
+  let j = createNode('j')
+
+  h.edge j
+  i.edge j
+
+  let k = createNode('k')
+  let l = createNode('l')
+
+  f.edge k
+  k.edge l
+  l.edge k
+  k.edge j
+
+  let m = createNode('m')
+  let n = createNode('n')
+  let p = createNode('p')
+  let q = createNode('q')
+
+  m.edge n
+  n.edge p
+  n.edge q
+  q.edge p
+  p.edge m
+
+  q.edge k
+
+  d.edge m
+  e.edge n
+
+  result = a
+
+proc main2 =
+  let g = buildComplexGraph()
+
+main()
+main2()
+GC_fullCollect()
+echo "MEM ", getOccupiedMem()
diff --git a/tests/arc/torc_selfcycles.nim b/tests/arc/torc_selfcycles.nim
new file mode 100644
index 000000000..ac4fa52ce
--- /dev/null
+++ b/tests/arc/torc_selfcycles.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''ok'''
+  cmd: '''nim c --gc:orc -d:useMalloc -d:nimStressOrc $file'''
+  valgrind: "leaks"
+"""
+
+# bug #15753
+
+type
+  NodeKind = enum
+    nkDancing,
+    nkColumn
+
+  DancingNode = ref object
+    right: DancingNode
+    column: DancingNode
+    kind: NodeKind
+
+proc newColumnNode(): DancingNode =
+  result = DancingNode(kind: nkColumn)
+  result.right = result
+  result.column = result
+
+proc createDLXList(): DancingNode =
+  result = newColumnNode()
+
+  for i in 0 .. 15:
+    let n = newColumnNode()
+    n.right = result.right
+    result = n
+  echo "ok"
+
+var dlxlist = createDLXList()
diff --git a/tests/arc/torcbench.nim b/tests/arc/torcbench.nim
new file mode 100644
index 000000000..4c9e65fee
--- /dev/null
+++ b/tests/arc/torcbench.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''true peak memory: true'''
+  cmd: "nim c --gc:orc -d:release $file"
+"""
+
+import lists, strutils, times
+
+type
+  Base = ref object of RootObj
+
+  Node = ref object of Base
+    parent: DoublyLinkedList[string]
+    le, ri: Node
+    self: Node # in order to create a cycle
+
+proc buildTree(parent: DoublyLinkedList[string]; depth: int): Node =
+  if depth == 0:
+    result = nil
+  elif depth == 1:
+    result = Node(parent: parent, le: nil, ri: nil, self: nil)
+    when not defined(gcArc):
+      result.self = result
+  else:
+    result = Node(parent: parent, le: buildTree(parent, depth - 1), ri: buildTree(parent, depth - 2), self: nil)
+    result.self = result
+
+proc main() =
+  for i in countup(1, 100):
+    var leakList = initDoublyLinkedList[string]()
+    for j in countup(1, 5000):
+      leakList.append(newString(200))
+    #GC_fullCollect()
+    for i in 0..400:
+      discard buildTree(leakList, 8)
+
+main()
+GC_fullCollect()
+echo getOccupiedMem() < 10 * 1024 * 1024, " peak memory: ", getMaxMem() < 10 * 1024 * 1024
diff --git a/tests/arc/torcmisc.nim b/tests/arc/torcmisc.nim
new file mode 100644
index 000000000..e41ad7c77
--- /dev/null
+++ b/tests/arc/torcmisc.nim
@@ -0,0 +1,66 @@
+discard """
+  output: '''success'''
+  cmd: "nim c --gc:orc -d:release $file"
+"""
+
+# bug #17170
+
+when true:
+  import asyncdispatch
+
+  type
+    Flags = ref object
+      returnedEof, reading: bool
+
+  proc dummy(): Future[string] {.async.} =
+    result = "foobar"
+
+  proc hello(s: Flags) {.async.} =
+    let buf =
+      try:
+        await dummy()
+      except CatchableError as exc:
+        # When an exception happens here, the Bufferstream is effectively
+        # broken and no more reads will be valid - for now, return EOF if it's
+        # called again, though this is not completely true - EOF represents an
+        # "orderly" shutdown and that's not what happened here..
+        s.returnedEof = true
+        raise exc
+      finally:
+        s.reading = false
+
+  waitFor hello(Flags())
+  echo "success"
+
+# bug #18240
+import tables
+
+type
+  TopicHandler* = proc(topic: string,
+                       data: seq[byte]): Future[void] {.gcsafe, raises: [Defect].}
+
+  PeerID* = object
+    data*: seq[byte]
+
+  PeerInfo* = ref object of RootObj
+    peerId*: PeerID
+
+  Connection* = ref object of RootObj
+    peerInfo*: PeerInfo
+
+  PubSubPeer* = ref object of RootObj
+    codec*: string
+
+  PubSub* = ref object of RootObj
+    topics*: Table[string, seq[TopicHandler]]
+    peers*: Table[PeerID, PubSubPeer]
+
+proc getOrCreatePeer*(myParam: PubSub, peerId: PeerID, protos: seq[string]): PubSubPeer =
+  myParam.peers.withValue(peerId, peer):
+    return peer[]
+
+method handleConn*(myParam: PubSub,
+                  conn: Connection,
+                  proto: string) {.base, async.} =
+  myParam.peers.withValue(conn.peerInfo.peerId, peer):
+    let peerB = peer[]
diff --git a/tests/arc/tref_cast_error.nim b/tests/arc/tref_cast_error.nim
new file mode 100644
index 000000000..20139c1be
--- /dev/null
+++ b/tests/arc/tref_cast_error.nim
@@ -0,0 +1,15 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  errormsg: "expression cannot be cast to 'ref RootObj'"
+  joinable: false
+"""
+
+type Variant* = object
+    refval: ref RootObj
+
+proc newVariant*[T](val: T): Variant =
+    let pt = T.new()
+    pt[] = val
+    result = Variant(refval: cast[ref RootObj](pt))
+
+var v = newVariant(@[1, 2, 3])
diff --git a/tests/arc/trepr.nim b/tests/arc/trepr.nim
new file mode 100644
index 000000000..abf28330a
--- /dev/null
+++ b/tests/arc/trepr.nim
@@ -0,0 +1,97 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  nimout: '''(a: true, n: doAssert)
+Table[system.string, trepr.MyType](data: @[], counter: 0)
+nil
+'''
+  output: '''
+nil
+2
+Obj(member: ref @["hello"])
+ref (member: ref @["hello"])
+ObjUa(v: 0, a: [...])
+'''
+"""
+
+# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage
+
+import tables
+
+type
+  NimSym = distinct NimNode
+  MyType = tuple
+    a: bool
+    n: NimSym
+
+proc myproc(t: MyType) =
+  echo repr(t)
+
+proc myproc2(t: MyType) =
+  var x = Table[string, t]()
+  echo repr(x)
+
+proc myproc3(t: MyType) =
+  var x: TableRef[string, t]
+  echo repr(x)
+
+
+macro dumpSym(a: typed) =
+  myproc((a: true, n: NimSym(a)))
+  myproc2((a: true, n: NimSym(a)))
+  myproc3((a: true, n: NimSym(a)))
+
+dumpSym(doAssert)
+
+# bug 13731
+
+import os
+var a: File
+echo repr a
+
+# bug 13872
+
+echo repr(2'u16)
+
+# bug 14270
+
+type
+  Obj = ref object
+    member: ref seq[string]
+
+var c = Obj(member: new seq[string])
+c.member[] = @["hello"]
+echo c.repr
+
+var c2 = new tuple[member: ref seq[string]]
+c2.member = new seq[string]
+c2.member[] = @["hello"]
+echo c2.repr
+
+proc p2 =
+  echo "hey"
+
+discard repr p2
+
+
+#####################################################################
+# bug #15043
+
+import macros
+
+macro extract(): untyped =
+  result = newStmtList()
+  var x: seq[tuple[node: NimNode]]
+
+  proc test(n: NimNode) {.closure.} =
+    x.add (node: n)
+  
+  test(parseExpr("discard"))
+  
+extract()
+
+type
+  ObjUa = ref object
+    v: int
+    a: UncheckedArray[char]
+
+echo ObjUa().repr
diff --git a/tests/arc/trtree.nim b/tests/arc/trtree.nim
new file mode 100644
index 000000000..683403a62
--- /dev/null
+++ b/tests/arc/trtree.nim
@@ -0,0 +1,640 @@
+discard """
+  output: '''1 [2, 3, 4, 7]
+[0, 0]'''
+  targets: "c"
+  joinable: false
+disabled: 32bit
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #13110: This test failed with --gc:arc.
+
+# this test wasn't written for 32 bit
+# don't join because the code is too messy.
+
+# Nim RTree and R*Tree implementation
+# S. Salewski, 06-JAN-2018
+
+# http://www-db.deis.unibo.it/courses/SI-LS/papers/Gut84.pdf
+# http://dbs.mathematik.uni-marburg.de/publications/myPapers/1990/BKSS90.pdf
+
+# RT: range type like float, int
+# D: Dimension
+# M: Max entries in one node
+# LT: leaf type
+
+type
+  Dim* = static[int]
+  Ext[RT] = tuple[a, b: RT] # extend (range)
+  Box*[D: Dim; RT] = array[D, Ext[RT]] # Rectangle for 2D
+  BoxCenter*[D: Dim; RT] = array[D, RT]
+  L*[D: Dim; RT, LT] = tuple[b: Box[D, RT]; l: LT] # called Index Entry or index record in the Guttman paper
+  H[M, D: Dim; RT, LT] = ref object of RootRef
+    parent: H[M, D, RT, LT]
+    numEntries: int
+    level: int
+  N[M, D: Dim; RT, LT] = tuple[b: Box[D, RT]; n: H[M, D, RT, LT]]
+  LA[M, D: Dim; RT, LT] = array[M, L[D, RT, LT]]
+  NA[M, D: Dim; RT, LT] = array[M, N[M, D, RT, LT]]
+  Leaf[M, D: Dim; RT, LT] = ref object of H[M, D, RT, LT]
+    a: LA[M, D, RT, LT]
+  Node[M, D: Dim; RT, LT] = ref object of H[M, D, RT, LT]
+    a: NA[M, D, RT, LT]
+
+  RTree*[M, D: Dim; RT, LT] = ref object of RootRef
+    root: H[M, D, RT, LT]
+    bigM: int
+    m: int
+
+  RStarTree*[M, D: Dim; RT, LT] = ref object of RTree[M, D, RT, LT]
+    firstOverflow: array[32, bool]
+    p: int
+
+proc newLeaf[M, D: Dim; RT, LT](): Leaf[M, D, RT, LT] =
+  new result
+
+proc newNode[M, D: Dim; RT, LT](): Node[M, D, RT, LT] =
+  new result
+
+proc newRTree*[M, D: Dim; RT, LT](minFill: range[30 .. 50] = 40): RTree[M, D, RT, LT] =
+  assert(M > 1 and M < 101)
+  new result
+  result.bigM = M
+  result.m = M * minFill div 100
+  result.root = newLeaf[M, D, RT, LT]()
+
+proc newRStarTree*[M, D: Dim; RT, LT](minFill: range[30 .. 50] = 40): RStarTree[M, D, RT, LT] =
+  assert(M > 1 and M < 101)
+  new result
+  result.bigM = M
+  result.m = M * minFill div 100
+  result.p = M * 30 div 100
+  result.root = newLeaf[M, D, RT, LT]()
+
+proc center(r: Box): auto =#BoxCenter[r.len, typeof(r[0].a)] =
+  var res: BoxCenter[r.len, typeof(r[0].a)]
+  for i in 0 .. r.high:
+    when r[0].a is SomeInteger:
+      res[i] = (r[i].a + r[i].b) div 2
+    elif r[0].a is SomeFloat:
+      res[i] = (r[i].a + r[i].b) / 2
+    else: assert false
+  return res
+
+proc distance(c1, c2: BoxCenter): auto =
+  var res: typeof(c1[0])
+  for i in 0 .. c1.high:
+    res += (c1[i] - c2[i]) * (c1[i] - c2[i])
+  return res
+
+proc overlap(r1, r2: Box): auto =
+  result = typeof(r1[0].a)(1)
+  for i in 0 .. r1.high:
+    result *= (min(r1[i].b, r2[i].b) - max(r1[i].a, r2[i].a))
+    if result <= 0: return 0
+
+proc union(r1, r2: Box): Box =
+  for i in 0 .. r1.high:
+    result[i].a = min(r1[i].a, r2[i].a)
+    result[i].b = max(r1[i].b, r2[i].b)
+
+proc intersect(r1, r2: Box): bool =
+  for i in 0 .. r1.high:
+    if r1[i].b < r2[i].a or r1[i].a > r2[i].b:
+      return false
+  return true
+
+proc area(r: Box): auto = #typeof(r[0].a) =
+  result = typeof(r[0].a)(1)
+  for i in 0 .. r.high:
+    result *= r[i].b - r[i].a
+
+proc margin(r: Box): auto = #typeof(r[0].a) =
+  result = typeof(r[0].a)(0)
+  for i in 0 .. r.high:
+    result += r[i].b - r[i].a
+
+# how much enlargement does r1 need to include r2
+proc enlargement(r1, r2: Box): auto =
+  area(union(r1, r2)) - area(r1)
+
+proc search*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]): seq[LT] =
+  proc s[M, D: Dim; RT, LT](n: H[M, D, RT, LT]; b: Box[D, RT]; res: var seq[LT]) =
+    if n of Node[M, D, RT, LT]:
+      let h = Node[M, D, RT, LT](n)
+      for i in 0 ..< n.numEntries:
+        if intersect(h.a[i].b, b):
+          s(h.a[i].n, b, res)
+    elif n of Leaf[M, D, RT, LT]:
+      let h = Leaf[M, D, RT, LT](n)
+      for i in 0 ..< n.numEntries:
+        if intersect(h.a[i].b, b):
+          res.add(h.a[i].l)
+    else: assert false
+  result = newSeq[LT]()
+  s(t.root, b, result)
+
+# Insertion
+# a R*TREE proc
+proc chooseSubtree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; b: Box[D, RT]; level: int): H[M, D, RT, LT] =
+  assert level >= 0
+  var it = t.root
+  while it.level > level:
+    let nn = Node[M, D, RT, LT](it)
+    var i0 = 0 # selected index
+    var minLoss = typeof(b[0].a).high
+    if it.level == 1: # childreen are leaves -- determine the minimum overlap costs
+      for i in 0 ..< it.numEntries:
+        let nx = union(nn.a[i].b, b)
+        var loss = 0
+        for j in 0 ..< it.numEntries:
+          if i == j: continue
+          loss += (overlap(nx, nn.a[j].b) - overlap(nn.a[i].b, nn.a[j].b)) # overlap (i, j) == (j, i), so maybe cache that?
+        var rep = loss < minLoss
+        if loss == minLoss:
+          let l2 = enlargement(nn.a[i].b, b) - enlargement(nn.a[i0].b, b)
+          rep = l2 < 0
+          if l2 == 0:
+            let l3 = area(nn.a[i].b) - area(nn.a[i0].b)
+            rep = l3 < 0
+            if l3 == 0:
+              rep = nn.a[i].n.numEntries < nn.a[i0].n.numEntries
+        if rep:
+          i0 = i
+          minLoss = loss
+    else:
+      for i in 0 ..< it.numEntries:
+        let loss = enlargement(nn.a[i].b, b)
+        var rep = loss < minLoss
+        if loss == minLoss:
+          let l3 = area(nn.a[i].b) - area(nn.a[i0].b)
+          rep = l3 < 0
+          if l3 == 0:
+            rep = nn.a[i].n.numEntries < nn.a[i0].n.numEntries
+        if rep:
+          i0 = i
+          minLoss = loss
+    it = nn.a[i0].n
+  return it
+
+proc pickSeeds[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; bx: Box[D, RT]): (int, int) =
+  var i0, j0: int
+  var bi, bj: typeof(bx)
+  var largestWaste = typeof(bx[0].a).low
+  for i in -1 .. n.a.high:
+    for j in 0 .. n.a.high:
+      if unlikely(i == j): continue
+      if unlikely(i < 0):
+        bi = bx
+      else:
+        bi = n.a[i].b
+      bj = n.a[j].b
+      let b = union(bi, bj)
+      let h = area(b) - area(bi) - area(bj)
+      if h > largestWaste:
+        largestWaste = h
+        i0 = i
+        j0 = j
+  return (i0, j0)
+
+proc pickNext[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n0, n1, n2: Node[M, D, RT, LT] | Leaf[M, D, RT, LT]; b1, b2: Box[D, RT]): int =
+  let a1 = area(b1)
+  let a2 = area(b2)
+  var d = typeof(a1).low
+  for i in 0 ..< n0.numEntries:
+    let d1 = area(union(b1, n0.a[i].b)) - a1
+    let d2 = area(union(b2, n0.a[i].b)) - a2
+    if (d1 - d2) * (d1 - d2) > d:
+      result = i
+      d = (d1 - d2) * (d1 - d2)
+
+from algorithm import SortOrder, sort
+proc sortPlus[T](a: var openArray[T], ax: var T, cmp: proc (x, y: T): int {.closure.}, order = algorithm.SortOrder.Ascending) =
+  var j = 0
+  let sign = if order == algorithm.SortOrder.Ascending: 1 else: -1
+  for i in 1 .. a.high:
+    if cmp(a[i], a[j]) * sign < 0:
+      j = i
+  if cmp(a[j], ax) * sign < 0:
+    swap(ax, a[j])
+  a.sort(cmp, order)
+
+# R*TREE procs
+proc rstarSplit[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) =
+  type NL = typeof(lx)
+  var nBest: typeof(n)
+  new nBest
+  var lx = lx
+  when n is Node[M, D, RT, LT]:
+    lx.n.parent = n
+  var lxbest: typeof(lx)
+  var m0 = lx.b[0].a.typeof.high
+  for d2 in 0 ..< 2 * D:
+    let d = d2 div 2
+    if d2 mod 2 == 0:
+      sortPlus(n.a, lx, proc (x, y: NL): int = cmp(x.b[d].a, y.b[d].a))
+    else:
+      sortPlus(n.a, lx, proc (x, y: NL): int = cmp(x.b[d].b, y.b[d].b))
+    for i in t.m - 1 .. n.a.high - t.m + 1:
+      var b = lx.b
+      for j in 0 ..< i: # we can precalculate union() for range 0 .. t.m - 1, but that seems to give no real benefit.Maybe for very large M?
+        #echo "x",j
+        b = union(n.a[j].b, b)
+      var m = margin(b)
+      b = n.a[^1].b
+      for j in i ..< n.a.high: # again, precalculation of tail would be possible
+        #echo "y",j
+        b = union(n.a[j].b, b)
+      m += margin(b)
+      if m < m0:
+        nbest[] = n[]
+        lxbest = lx
+        m0 = m
+  var i0 = -1
+  var o0 = lx.b[0].a.typeof.high
+  for i in t.m - 1 .. n.a.typeof.high - t.m + 1:
+    var b1 = lxbest.b
+    for j in 0 ..< i:
+      b1 = union(nbest.a[j].b, b1)
+    var b2 = nbest.a[^1].b
+    for j in i ..< n.a.high:
+      b2 = union(nbest.a[j].b, b2)
+    let o = overlap(b1, b2)
+    if o < o0:
+      i0 = i
+      o0 = o
+  n.a[0] = lxbest
+  for i in 0 ..< i0:
+    n.a[i + 1] = nbest.a[i]
+  new result
+  result.level = n.level
+  result.parent = n.parent
+  for i in i0 .. n.a.high:
+    result.a[i - i0] = nbest.a[i]
+  n.numEntries = i0 + 1
+  result.numEntries = M - i0
+  when n is Node[M, D, RT, LT]:
+    for i in 0 ..< result.numEntries:
+      result.a[i].n.parent = result
+
+proc quadraticSplit[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) =
+  var n1, n2: typeof(n)
+  var s1, s2: int
+  new n1
+  new n2
+  n1.parent = n.parent
+  n2.parent = n.parent
+  n1.level = n.level
+  n2.level = n.level
+  var lx = lx
+  when n is Node[M, D, RT, LT]:
+    lx.n.parent = n
+  (s1, s2) = pickSeeds(t, n, lx.b)
+  assert s1 >= -1 and s2 >= 0
+  if unlikely(s1 < 0):
+    n1.a[0] = lx
+  else:
+    n1.a[0] = n.a[s1]
+    dec(n.numEntries)
+    if s2 == n.numEntries: # important fix
+      s2 = s1
+    n.a[s1] = n.a[n.numEntries]
+  inc(n1.numEntries)
+  var b1 = n1.a[0].b
+  n2.a[0] = n.a[s2]
+  dec(n.numEntries)
+  n.a[s2] = n.a[n.numEntries]
+  inc(n2.numEntries)
+  var b2 = n2.a[0].b
+  if s1 >= 0:
+    n.a[n.numEntries] = lx
+    inc(n.numEntries)
+  while n.numEntries > 0 and n1.numEntries < (t.bigM + 1 - t.m) and n2.numEntries < (t.bigM + 1 - t.m):
+    let next = pickNext(t, n, n1, n2, b1, b2)
+    let d1 = area(union(b1, n.a[next].b)) - area(b1)
+    let d2 = area(union(b2, n.a[next].b)) - area(b2)
+    if (d1 < d2) or (d1 == d2 and ((area(b1) < area(b2)) or (area(b1) == area(b2) and n1.numEntries < n2.numEntries))):
+      n1.a[n1.numEntries] = n.a[next]
+      b1 = union(b1, n.a[next].b)
+      inc(n1.numEntries)
+    else:
+      n2.a[n2.numEntries] = n.a[next]
+      b2 = union(b2, n.a[next].b)
+      inc(n2.numEntries)
+    dec(n.numEntries)
+    n.a[next] = n.a[n.numEntries]
+  if n.numEntries == 0:
+    discard
+  elif n1.numEntries == (t.bigM + 1 - t.m):
+    while n.numEntries > 0:
+      dec(n.numEntries)
+      n2.a[n2.numEntries] = n.a[n.numEntries]
+      inc(n2.numEntries)
+  elif n2.numEntries == (t.bigM + 1 - t.m):
+    while n.numEntries > 0:
+      dec(n.numEntries)
+      n1.a[n1.numEntries] = n.a[n.numEntries]
+      inc(n1.numEntries)
+  when n is Node[M, D, RT, LT]:
+    for i in 0 ..< n2.numEntries:
+      n2.a[i].n.parent = n2
+  n[] = n1[]
+  return n2
+
+proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n)
+
+proc adjustTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; l, ll: H[M, D, RT, LT]; hb: Box[D, RT]) =
+  var n = l
+  var nn = ll
+  assert n != nil
+  while true:
+    if n == t.root:
+      if nn == nil:
+        break
+      t.root = newNode[M, D, RT, LT]()
+      t.root.level = n.level + 1
+      Node[M, D, RT, LT](t.root).a[0].n = n
+      n.parent = t.root
+      nn.parent = t.root
+      t.root.numEntries = 1
+    let p = Node[M, D, RT, LT](n.parent)
+    var i = 0
+    while p.a[i].n != n:
+      inc(i)
+    var b: typeof(p.a[0].b)
+    if n of Leaf[M, D, RT, LT]:
+      when false:#if likely(nn.isNil): # no performance gain
+        b = union(p.a[i].b, Leaf[M, D, RT, LT](n).a[n.numEntries - 1].b)
+      else:
+        b = Leaf[M, D, RT, LT](n).a[0].b
+        for j in 1 ..< n.numEntries:
+          b = trtree.union(b, Leaf[M, D, RT, LT](n).a[j].b)
+    elif n of Node[M, D, RT, LT]:
+      b = Node[M, D, RT, LT](n).a[0].b
+      for j in 1 ..< n.numEntries:
+        b = union(b, Node[M, D, RT, LT](n).a[j].b)
+    else:
+      assert false
+    #if nn.isNil and p.a[i].b == b: break # no performance gain
+    p.a[i].b = b
+    n = H[M, D, RT, LT](p)
+    if unlikely(nn != nil):
+      if nn of Leaf[M, D, RT, LT]:
+        b = Leaf[M, D, RT, LT](nn).a[0].b
+        for j in 1 ..< nn.numEntries:
+          b = union(b, Leaf[M, D, RT, LT](nn).a[j].b)
+      elif nn of Node[M, D, RT, LT]:
+        b = Node[M, D, RT, LT](nn).a[0].b
+        for j in 1 ..< nn.numEntries:
+          b = union(b, Node[M, D, RT, LT](nn).a[j].b)
+      else:
+        assert false
+      if p.numEntries < p.a.len:
+        p.a[p.numEntries].b = b
+        p.a[p.numEntries].n = nn
+        inc(p.numEntries)
+        assert n != nil
+        nn = nil
+      else:
+        let h: N[M, D, RT, LT] = (b, nn)
+        nn = quadraticSplit(t, p, h)
+    assert n == H[M, D, RT, LT](p)
+    assert n != nil
+    assert t.root != nil
+
+proc insert*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int = 0) =
+  when leaf is N[M, D, RT, LT]:
+    assert level > 0
+    type NodeLeaf = Node[M, D, RT, LT]
+  else:
+    assert level == 0
+    type NodeLeaf = Leaf[M, D, RT, LT]
+  for d in leaf.b:
+    assert d.a <= d.b
+  let l = NodeLeaf(chooseSubtree(t, leaf.b, level))
+  if l.numEntries < l.a.len:
+    l.a[l.numEntries] = leaf
+    inc(l.numEntries)
+    when leaf is N[M, D, RT, LT]:
+      leaf.n.parent = l
+    adjustTree(t, l, nil, leaf.b)
+  else:
+    let l2 = quadraticSplit(t, l, leaf)
+    assert l2.level == l.level
+    adjustTree(t, l, l2, leaf.b)
+
+# R*Tree insert procs
+proc rsinsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int)
+
+proc reInsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]) =
+  type NL = typeof(lx)
+  var lx = lx
+  var buf: typeof(n.a)
+  let p = Node[M, D, RT, LT](n.parent)
+  var i = 0
+  while p.a[i].n != n:
+    inc(i)
+  let c = center(p.a[i].b)
+  sortPlus(n.a, lx, proc (x, y: NL): int = cmp(distance(center(x.b), c), distance(center(y.b), c)))
+  n.numEntries = M - t.p
+  swap(n.a[n.numEntries], lx)
+  inc n.numEntries
+  var b = n.a[0].b
+  for i in 1 ..< n.numEntries:
+    b = union(b, n.a[i].b)
+  p.a[i].b = b
+  for i in M - t.p + 1 .. n.a.high:
+    buf[i] = n.a[i]
+  rsinsert(t, lx, n.level)
+  for i in M - t.p + 1 .. n.a.high:
+    rsinsert(t, buf[i], n.level)
+
+proc overflowTreatment[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; n: var Node[M, D, RT, LT] | var Leaf[M, D, RT, LT]; lx: L[D, RT, LT] | N[M, D, RT, LT]): typeof(n) =
+  if n.level != t.root.level and t.firstOverflow[n.level]:
+    t.firstOverflow[n.level] = false
+    reInsert(t, n, lx)
+    return nil
+  else:
+    let l2 = rstarSplit(t, n, lx)
+    assert l2.level == n.level
+    return l2
+
+proc rsinsert[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: N[M, D, RT, LT] | L[D, RT, LT]; level: int) =
+  when leaf is N[M, D, RT, LT]:
+    assert level > 0
+    type NodeLeaf = Node[M, D, RT, LT]
+  else:
+    assert level == 0
+    type NodeLeaf = Leaf[M, D, RT, LT]
+  let l = NodeLeaf(chooseSubtree(t, leaf.b, level))
+  if l.numEntries < l.a.len:
+    l.a[l.numEntries] = leaf
+    inc(l.numEntries)
+    when leaf is N[M, D, RT, LT]:
+      leaf.n.parent = l
+    adjustTree(t, l, nil, leaf.b)
+  else:
+    when leaf is N[M, D, RT, LT]: # TODO do we need this?
+      leaf.n.parent = l
+    let l2 = overflowTreatment(t, l, leaf)
+    if l2 != nil:
+      assert l2.level == l.level
+      adjustTree(t, l, l2, leaf.b)
+
+proc insert*[M, D: Dim; RT, LT](t: RStarTree[M, D, RT, LT]; leaf: L[D, RT, LT]) =
+  for d in leaf.b:
+    assert d.a <= d.b
+  for i in mitems(t.firstOverflow):
+    i = true
+  rsinsert(t, leaf, 0)
+
+# delete
+proc findLeaf[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): Leaf[M, D, RT, LT] =
+  proc fl[M, D: Dim; RT, LT](h: H[M, D, RT, LT]; leaf: L[D, RT, LT]): Leaf[M, D, RT, LT] =
+    var n = h
+    if n of Node[M, D, RT, LT]:
+      for i in 0 ..< n.numEntries:
+        if intersect(Node[M, D, RT, LT](n).a[i].b, leaf.b):
+          let l = fl(Node[M, D, RT, LT](n).a[i].n, leaf)
+          if l != nil:
+            return l
+    elif n of Leaf[M, D, RT, LT]:
+      for i in 0 ..< n.numEntries:
+        if Leaf[M, D, RT, LT](n).a[i] == leaf:
+          return Leaf[M, D, RT, LT](n)
+    else:
+      assert false
+    return nil
+  fl(t.root, leaf)
+
+proc condenseTree[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: Leaf[M, D, RT, LT]) =
+  var n: H[M, D, RT, LT] = leaf
+  var q = newSeq[H[M, D, RT, LT]]()
+  var b: typeof(leaf.a[0].b)
+  while n != t.root:
+    let p = Node[M, D, RT, LT](n.parent)
+    var i = 0
+    while p.a[i].n != n:
+      inc(i)
+    if n.numEntries < t.m:
+      dec(p.numEntries)
+      p.a[i] = p.a[p.numEntries]
+      q.add(n)
+    else:
+      if n of Leaf[M, D, RT, LT]:
+        b = Leaf[M, D, RT, LT](n).a[0].b
+        for j in 1 ..< n.numEntries:
+          b = union(b, Leaf[M, D, RT, LT](n).a[j].b)
+      elif n of Node[M, D, RT, LT]:
+        b = Node[M, D, RT, LT](n).a[0].b
+        for j in 1 ..< n.numEntries:
+          b = union(b, Node[M, D, RT, LT](n).a[j].b)
+      else:
+        assert false
+      p.a[i].b = b
+    n = n.parent
+  if t of RStarTree[M, D, RT, LT]:
+    for n in q:
+      if n of Leaf[M, D, RT, LT]:
+        for i in 0 ..< n.numEntries:
+          for i in mitems(RStarTree[M, D, RT, LT](t).firstOverflow):
+            i = true
+          rsinsert(RStarTree[M, D, RT, LT](t), Leaf[M, D, RT, LT](n).a[i], 0)
+      elif n of Node[M, D, RT, LT]:
+        for i in 0 ..< n.numEntries:
+          for i in mitems(RStarTree[M, D, RT, LT](t).firstOverflow):
+            i = true
+          rsinsert(RStarTree[M, D, RT, LT](t), Node[M, D, RT, LT](n).a[i], n.level)
+      else:
+        assert false
+  else:
+    for n in q:
+      if n of Leaf[M, D, RT, LT]:
+        for i in 0 ..< n.numEntries:
+          insert(t, Leaf[M, D, RT, LT](n).a[i])
+      elif n of Node[M, D, RT, LT]:
+        for i in 0 ..< n.numEntries:
+          insert(t, Node[M, D, RT, LT](n).a[i], n.level)
+      else:
+        assert false
+
+proc delete*[M, D: Dim; RT, LT](t: RTree[M, D, RT, LT]; leaf: L[D, RT, LT]): bool {.discardable.} =
+  let l = findLeaf(t, leaf)
+  if l.isNil:
+    return false
+  else:
+    var i = 0
+    while l.a[i] != leaf:
+      inc(i)
+    dec(l.numEntries)
+    l.a[i] = l.a[l.numEntries]
+    condenseTree(t, l)
+    if t.root.numEntries == 1:
+      if t.root of Node[M, D, RT, LT]:
+        t.root = Node[M, D, RT, LT](t.root).a[0].n
+      t.root.parent = nil
+    return true
+
+
+var t = [4, 1, 3, 2]
+var xt = 7
+sortPlus(t, xt, system.cmp, SortOrder.Ascending)
+echo xt, " ", t
+
+type
+  RSE = L[2, int, int]
+  RSeq = seq[RSE]
+
+proc rseq_search(rs: RSeq; rse: RSE): seq[int] =
+  result = newSeq[int]()
+  for i in rs:
+    if intersect(i.b, rse.b):
+      result.add(i.l)
+
+proc rseq_delete(rs: var RSeq; rse: RSE): bool =
+  for i in 0 .. rs.high:
+    if rs[i] == rse:
+      #rs.delete(i)
+      rs[i] = rs[rs.high]
+      rs.setLen(rs.len - 1)
+      return true
+
+import random, algorithm
+
+proc test(n: int) =
+  var b: Box[2, int]
+  echo center(b)
+  var x1, x2, y1, y2: int
+  var t = newRStarTree[8, 2, int, int]()
+  #var t = newRTree[8, 2, int, int]()
+  var rs = newSeq[RSE]()
+  for i in 0 .. 5:
+    for i in 0 .. n - 1:
+      x1 = rand(1000)
+      y1 = rand(1000)
+      x2 = x1 + rand(25)
+      y2 = y1 + rand(25)
+      b = [(x1, x2), (y1, y2)]
+      let el: L[2, int, int] = (b, i + 7)
+      t.insert(el)
+      rs.add(el)
+
+    for i in 0 .. (n div 4):
+      let j = rand(rs.high)
+      var el = rs[j]
+      assert t.delete(el)
+      assert rs.rseq_delete(el)
+
+    for i in 0 .. n - 1:
+      x1 = rand(1000)
+      y1 = rand(1000)
+      x2 = x1 + rand(100)
+      y2 = y1 + rand(100)
+      b = [(x1, x2), (y1, y2)]
+      let el: L[2, int, int] = (b, i)
+      let r = search(t, b)
+      let r2 = rseq_search(rs, el)
+      assert r.len == r2.len
+      assert r.sorted(system.cmp) == r2.sorted(system.cmp)
+
+test(500)
diff --git a/tests/arc/tshared_ptr_crash.nim b/tests/arc/tshared_ptr_crash.nim
new file mode 100644
index 000000000..1794834db
--- /dev/null
+++ b/tests/arc/tshared_ptr_crash.nim
@@ -0,0 +1,67 @@
+discard """
+  cmd: "nim c --threads:on --gc:arc $file"
+  action: compile
+"""
+
+# bug #17893
+
+type
+  SharedPtr*[T] = object
+    val: ptr tuple[value: T, atomicCounter: int]
+
+proc `=destroy`*[T](p: var SharedPtr[T]) =
+  mixin `=destroy`
+  if p.val != nil:
+    if atomicLoadN(addr p.val[].atomicCounter, AtomicConsume) == 0:
+      `=destroy`(p.val[])
+      deallocShared(p.val)
+    else:
+      discard atomicDec(p.val[].atomicCounter)
+
+proc `=copy`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) =
+  if src.val != nil:
+    discard atomicInc(src.val[].atomicCounter)
+  if dest.val != nil:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newSharedPtr*[T](val: sink T): SharedPtr[T] {.nodestroy.} =
+  result.val = cast[typeof(result.val)](allocShared(sizeof(result.val[])))
+  result.val.atomicCounter = 0
+  result.val.value = val
+
+proc isNil*[T](p: SharedPtr[T]): bool {.inline.} =
+  p.val == nil
+
+proc `[]`*[T](p: SharedPtr[T]): var T {.inline.} =
+  when compileOption("boundChecks"):
+    doAssert(p.val != nil, "deferencing nil shared pointer")
+  result = p.val.value
+
+type
+  Sender*[T] = object
+    queue: SharedPtr[seq[T]]
+
+proc newSender*[T](queue: sink SharedPtr[seq[T]]): Sender[T] =
+  result = Sender[T](queue: queue)
+
+proc send*[T](self: Sender[T]; t: sink T) =
+  self.queue[].add t
+
+proc newChannel*(): Sender[int] =
+  let queue = newSharedPtr(newSeq[int]())
+  result = newSender(queue)
+
+
+var
+  p: Thread[Sender[int]]
+
+proc threadFn(tx: Sender[int]) =
+  send tx, 0
+
+proc multiThreadedChannel =
+  let tx = newChannel()
+  createThread(p, threadFn, tx)
+  joinThread(p)
+
+multiThreadedChannel()
diff --git a/tests/arc/tstrformat.nim b/tests/arc/tstrformat.nim
new file mode 100644
index 000000000..641f323da
--- /dev/null
+++ b/tests/arc/tstrformat.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''
+verstuff
+'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #13622
+
+import strformat
+
+template necho*(args: string) {.dirty.} =
+  if getCurrentException() != nil:
+    echo args
+  else:
+    stdout.writeLine(args)
+
+proc main(cond: bool; arg: string) =
+  if cond:
+    necho &"ver{arg}\n"
+
+main(true, "stuff")
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/arc/tthread.nim b/tests/arc/tthread.nim
new file mode 100644
index 000000000..8a55a666e
--- /dev/null
+++ b/tests/arc/tthread.nim
@@ -0,0 +1,63 @@
+discard """
+  cmd: "nim cpp --gc:arc --threads:on $file"
+  output: '''ok1
+ok2
+destroyed
+destroyed
+destroyed
+'''
+"""
+import threadpool, os
+
+type
+  MyObj = object
+    p: int
+  MyObjRef = ref MyObj
+
+proc `=destroy`(x: var MyObj) =
+  if x.p != 0:
+    echo "destroyed"
+
+proc thread1(): string =
+  os.sleep(1000)
+  return "ok1"
+
+proc thread2(): ref string =
+  os.sleep(1000)
+  new(result)
+  result[] = "ok2"
+
+proc thread3(): ref MyObj =
+  os.sleep(1000)
+  new(result)
+  result[].p = 2
+
+var fv1 = spawn thread1()
+var fv2 = spawn thread2()
+var fv3 = spawn thread3()
+sync()
+echo ^fv1
+echo (^fv2)[]
+
+
+proc thread4(x: MyObjRef): MyObjRef {.nosinks.} =
+  os.sleep(1000)
+  result = x
+
+proc thread5(x: sink MyObjRef): MyObjRef =
+  os.sleep(1000)
+  result = x
+
+proc ref_forwarding_test =
+  var x = new(MyObj)
+  x[].p = 2
+  var y = spawn thread4(x)
+
+proc ref_sink_forwarding_test =
+  var x = new(MyObj)
+  x[].p = 2
+  var y = spawn thread5(x)
+
+ref_forwarding_test()
+ref_sink_forwarding_test()
+sync()
diff --git a/tests/arc/tunref_cycle.nim b/tests/arc/tunref_cycle.nim
new file mode 100644
index 000000000..82551b7f7
--- /dev/null
+++ b/tests/arc/tunref_cycle.nim
@@ -0,0 +1,26 @@
+discard """
+  outputsub: '''inside closure
+hello world'''
+  cmd: "nim c --gc:orc -d:useMalloc $file"
+  valgrind: true
+"""
+
+# bug #18579
+
+var fp: proc (env: pointer) {.cdecl.}
+var env: pointer
+
+proc store(f: proc (){.closure.}) =
+  proc closeOver() =
+    echo "inside closure"
+    f()
+  (fp,env) = (cast[proc(env: pointer){.cdecl.}](rawProc closeOver), rawEnv closeOver)
+  GC_ref(cast[RootRef](env))
+
+proc run() =
+  fp(env)
+  GC_unref(cast[RootRef](env))
+
+store(proc() = echo "hello world")
+run()
+GC_fullCollect()
diff --git a/tests/arc/tweave.nim b/tests/arc/tweave.nim
new file mode 100644
index 000000000..1c60ac403
--- /dev/null
+++ b/tests/arc/tweave.nim
@@ -0,0 +1,157 @@
+discard """
+  outputsub: '''Success'''
+  cmd: '''nim c --gc:arc --threads:on $file'''
+  disabled: "bsd"
+"""
+
+# bug #13936
+
+import std/atomics
+
+when defined(nimPreviewSlimSystem):
+  import std/[assertions, typedthreads]
+
+const MemBlockSize = 256
+
+type
+  ChannelSPSCSingle* = object
+    full{.align: 128.}: Atomic[bool]
+    itemSize*: uint8
+    buffer*{.align: 8.}: UncheckedArray[byte]
+
+proc `=`(
+    dest: var ChannelSPSCSingle,
+    source: ChannelSPSCSingle
+  ) {.error: "A channel cannot be copied".}
+
+proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} =
+  ## If ChannelSPSCSingle is used intrusive another data structure
+  ## be aware that it should be the last part due to ending by UncheckedArray
+  ## Also due to 128 bytes padding, it automatically takes half
+  ## of the default MemBlockSize
+  assert itemsize.int in 0 .. int high(uint8)
+  assert itemSize.int +
+          sizeof(chan.itemsize) +
+          sizeof(chan.full) < MemBlockSize
+
+  chan.itemSize = uint8 itemsize
+  chan.full.store(false, moRelaxed)
+
+func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} =
+  not chan.full.load(moAcquire)
+
+func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} =
+  ## Try receiving the item buffered in the channel
+  ## Returns true if successful (channel was not empty)
+  ##
+  ## âš  Use only in the consumer thread that reads from the channel.
+  assert (sizeof(T) == chan.itemsize.int) or
+          # Support dummy object
+          (sizeof(T) == 0 and chan.itemsize == 1)
+
+  let full = chan.full.load(moAcquire)
+  if not full:
+    return false
+  dst = cast[ptr T](chan.buffer.addr)[]
+  chan.full.store(false, moRelease)
+  return true
+
+func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} =
+  ## Try sending an item into the channel
+  ## Reurns true if successful (channel was empty)
+  ##
+  ## âš  Use only in the producer thread that writes from the channel.
+  assert (sizeof(T) == chan.itemsize.int) or
+          # Support dummy object
+          (sizeof(T) == 0 and chan.itemsize == 1)
+
+  let full = chan.full.load(moAcquire)
+  if full:
+    return false
+  cast[ptr T](chan.buffer.addr)[] = src
+  chan.full.store(true, moRelease)
+  return true
+
+# Sanity checks
+# ------------------------------------------------------------------------------
+when isMainModule:
+
+  when not compileOption("threads"):
+    {.error: "This requires --threads:on compilation flag".}
+
+  template sendLoop[T](chan: var ChannelSPSCSingle,
+                       data: sink T,
+                       body: untyped): untyped =
+    while not chan.trySend(data):
+      body
+
+  template recvLoop[T](chan: var ChannelSPSCSingle,
+                       data: var T,
+                       body: untyped): untyped =
+    while not chan.tryRecv(data):
+      body
+
+  type
+    ThreadArgs = object
+      ID: WorkerKind
+      chan: ptr ChannelSPSCSingle
+
+    WorkerKind = enum
+      Sender
+      Receiver
+
+  template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} =
+    if args.ID == id:
+      body
+
+  proc thread_func(args: ThreadArgs) =
+
+    # Worker RECEIVER:
+    # ---------
+    # <- chan
+    # <- chan
+    # <- chan
+    #
+    # Worker SENDER:
+    # ---------
+    # chan <- 42
+    # chan <- 53
+    # chan <- 64
+    Worker(Receiver):
+      var val: int
+      for j in 0 ..< 10:
+        args.chan[].recvLoop(val):
+          # Busy loop, in prod we might want to yield the core/thread timeslice
+          discard
+        echo "                  Receiver got: ", val
+        doAssert val == 42 + j*11
+
+    Worker(Sender):
+      doAssert args.chan.full.load(moRelaxed) == false
+      for j in 0 ..< 10:
+        let val = 42 + j*11
+        args.chan[].sendLoop(val):
+          # Busy loop, in prod we might want to yield the core/thread timeslice
+          discard
+        echo "Sender sent: ", val
+
+  proc main() =
+    echo "Testing if 2 threads can send data"
+    echo "-----------------------------------"
+    var threads: array[2, Thread[ThreadArgs]]
+
+    var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize))
+    chan[].initialize(itemSize = sizeof(int))
+
+    createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan))
+    createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan))
+
+    joinThread(threads[0])
+    joinThread(threads[1])
+
+    freeShared(chan)
+
+    echo "-----------------------------------"
+    echo "Success"
+
+  main()
diff --git a/tests/arc/tweavecopy.nim b/tests/arc/tweavecopy.nim
new file mode 100644
index 000000000..fc796b352
--- /dev/null
+++ b/tests/arc/tweavecopy.nim
@@ -0,0 +1,154 @@
+discard """
+  outputsub: '''Success'''
+  cmd: '''nim c --gc:arc --threads:on $file'''
+  disabled: "bsd"
+"""
+
+# bug #13936
+
+import std/atomics
+
+const MemBlockSize = 256
+
+type
+  ChannelSPSCSingle* = object
+    full{.align: 128.}: Atomic[bool]
+    itemSize*: uint8
+    buffer*{.align: 8.}: UncheckedArray[byte]
+
+proc `=copy`(
+    dest: var ChannelSPSCSingle,
+    source: ChannelSPSCSingle
+  ) {.error: "A channel cannot be copied".}
+
+proc initialize*(chan: var ChannelSPSCSingle, itemsize: SomeInteger) {.inline.} =
+  ## If ChannelSPSCSingle is used intrusive another data structure
+  ## be aware that it should be the last part due to ending by UncheckedArray
+  ## Also due to 128 bytes padding, it automatically takes half
+  ## of the default MemBlockSize
+  assert itemsize.int in 0 .. int high(uint8)
+  assert itemSize.int +
+          sizeof(chan.itemsize) +
+          sizeof(chan.full) < MemBlockSize
+
+  chan.itemSize = uint8 itemsize
+  chan.full.store(false, moRelaxed)
+
+func isEmpty*(chan: var ChannelSPSCSingle): bool {.inline.} =
+  not chan.full.load(moAcquire)
+
+func tryRecv*[T](chan: var ChannelSPSCSingle, dst: var T): bool {.inline.} =
+  ## Try receiving the item buffered in the channel
+  ## Returns true if successful (channel was not empty)
+  ##
+  ## âš  Use only in the consumer thread that reads from the channel.
+  assert (sizeof(T) == chan.itemsize.int) or
+          # Support dummy object
+          (sizeof(T) == 0 and chan.itemsize == 1)
+
+  let full = chan.full.load(moAcquire)
+  if not full:
+    return false
+  dst = cast[ptr T](chan.buffer.addr)[]
+  chan.full.store(false, moRelease)
+  return true
+
+func trySend*[T](chan: var ChannelSPSCSingle, src: sink T): bool {.inline.} =
+  ## Try sending an item into the channel
+  ## Reurns true if successful (channel was empty)
+  ##
+  ## âš  Use only in the producer thread that writes from the channel.
+  assert (sizeof(T) == chan.itemsize.int) or
+          # Support dummy object
+          (sizeof(T) == 0 and chan.itemsize == 1)
+
+  let full = chan.full.load(moAcquire)
+  if full:
+    return false
+  cast[ptr T](chan.buffer.addr)[] = src
+  chan.full.store(true, moRelease)
+  return true
+
+# Sanity checks
+# ------------------------------------------------------------------------------
+when isMainModule:
+
+  when not compileOption("threads"):
+    {.error: "This requires --threads:on compilation flag".}
+
+  template sendLoop[T](chan: var ChannelSPSCSingle,
+                       data: sink T,
+                       body: untyped): untyped =
+    while not chan.trySend(data):
+      body
+
+  template recvLoop[T](chan: var ChannelSPSCSingle,
+                       data: var T,
+                       body: untyped): untyped =
+    while not chan.tryRecv(data):
+      body
+
+  type
+    ThreadArgs = object
+      ID: WorkerKind
+      chan: ptr ChannelSPSCSingle
+
+    WorkerKind = enum
+      Sender
+      Receiver
+
+  template Worker(id: WorkerKind, body: untyped): untyped {.dirty.} =
+    if args.ID == id:
+      body
+
+  proc thread_func(args: ThreadArgs) =
+
+    # Worker RECEIVER:
+    # ---------
+    # <- chan
+    # <- chan
+    # <- chan
+    #
+    # Worker SENDER:
+    # ---------
+    # chan <- 42
+    # chan <- 53
+    # chan <- 64
+    Worker(Receiver):
+      var val: int
+      for j in 0 ..< 10:
+        args.chan[].recvLoop(val):
+          # Busy loop, in prod we might want to yield the core/thread timeslice
+          discard
+        echo "                  Receiver got: ", val
+        doAssert val == 42 + j*11
+
+    Worker(Sender):
+      doAssert args.chan.full.load(moRelaxed) == false
+      for j in 0 ..< 10:
+        let val = 42 + j*11
+        args.chan[].sendLoop(val):
+          # Busy loop, in prod we might want to yield the core/thread timeslice
+          discard
+        echo "Sender sent: ", val
+
+  proc main() =
+    echo "Testing if 2 threads can send data"
+    echo "-----------------------------------"
+    var threads: array[2, Thread[ThreadArgs]]
+
+    var chan = cast[ptr ChannelSPSCSingle](allocShared(MemBlockSize))
+    chan[].initialize(itemSize = sizeof(int))
+
+    createThread(threads[0], thread_func, ThreadArgs(ID: Receiver, chan: chan))
+    createThread(threads[1], thread_func, ThreadArgs(ID: Sender, chan: chan))
+
+    joinThread(threads[0])
+    joinThread(threads[1])
+
+    freeShared(chan)
+
+    echo "-----------------------------------"
+    echo "Success"
+
+  main()
diff --git a/tests/arc/twrong_sinkinference.nim b/tests/arc/twrong_sinkinference.nim
new file mode 100644
index 000000000..ecf09d28a
--- /dev/null
+++ b/tests/arc/twrong_sinkinference.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  errormsg: "type mismatch: got <proc (a: string, b: sink string){.noSideEffect, gcsafe.}>"
+  line: 18
+"""
+
+type
+  Foo = proc (a, b: string)
+
+proc take(x: Foo) =
+  x("a", "b")
+
+proc willSink(a, b: string) = # {.nosinks.} =
+  var arr: array[3, string]
+  var x = a
+  arr[0] = b
+
+take willSink
diff --git a/tests/array/t15117.nim b/tests/array/t15117.nim
new file mode 100644
index 000000000..157b04bee
--- /dev/null
+++ b/tests/array/t15117.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--cc:vcc"
+  disabled: "linux"
+  disabled: "bsd"
+  disabled: "osx"
+  disabled: "unix"
+  disabled: "posix"
+"""
+{.experimental: "views".}
+
+let a: array[0, byte] = []
+discard a
+
+type B = object
+  a:int
+let b: array[0, B] = []
+let c: array[0, ptr B] = []
+let d: array[0, ref B] = []
+discard b
+discard c
+discard d
+
+discard default(array[0, B])
+
+type
+  View1 = openArray[byte]
+discard default(View1)
diff --git a/tests/array/t20248.nim b/tests/array/t20248.nim
new file mode 100644
index 000000000..66142548b
--- /dev/null
+++ b/tests/array/t20248.nim
@@ -0,0 +1,14 @@
+discard """
+cmd: "nim check --hints:off $file"
+errormsg: "ordinal type expected; given: Error Type"
+nimout: '''
+t20248.nim(10, 36) Error: ordinal type expected; given: Error Type
+t20248.nim(14, 20) Error: ordinal type expected; given: Error Type
+'''
+"""
+
+type Vec[N: static[int]] = array[0 ..< N, float]
+
+var v: Vec[32]
+
+var stuff: array[0 ..< 16, int]
diff --git a/tests/array/t9932.nim b/tests/array/t9932.nim
new file mode 100644
index 000000000..e3c8abba3
--- /dev/null
+++ b/tests/array/t9932.nim
@@ -0,0 +1,11 @@
+discard """
+cmd: "nim check $file"
+errormsg: "invalid type: 'typedesc[int]' in this context: 'array[0..0, typedesc[int]]' for var"
+nimout: '''
+t9932.nim(10, 5) Error: invalid type: 'type' in this context: 'array[0..0, type]' for var
+t9932.nim(11, 5) Error: invalid type: 'typedesc[int]' in this context: 'array[0..0, typedesc[int]]' for var
+'''
+"""
+
+var y: array[1,type]
+var x = [int]
diff --git a/tests/array/tarray.nim b/tests/array/tarray.nim
new file mode 100644
index 000000000..e9f330e3b
--- /dev/null
+++ b/tests/array/tarray.nim
@@ -0,0 +1,607 @@
+discard """
+output: '''
+[4, 5, 6]
+[16, 25, 36]
+[16, 25, 36]
+apple
+banana
+Fruit
+2
+4
+3
+none
+skin
+paper
+@[2, 3, 4]321
+9.0 4.0
+3
+@[(1, 2), (3, 5)]
+2
+@["a", "new one", "c"]
+@[1, 2, 3]
+3
+dflfdjkl__abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajs
+dflfdjkl__abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajsdf
+kgdchlfniambejop
+fjpmholcibdgeakn
+2.0
+a:1
+a:2
+a:3
+ret:
+ret:1
+ret:12
+123
+'''
+joinable: false
+"""
+
+block tarray:
+  type
+    TMyArray = array[0..2, int]
+    TMyRecord = tuple[x, y: int]
+    TObj = object
+      arr: TMyarray
+
+
+  proc sum(a: openArray[int]): int =
+    result = 0
+    var i = 0
+    while i < len(a):
+      inc(result, a[i])
+      inc(i)
+
+  proc getPos(r: TMyRecord): int =
+    result = r.x + r.y
+
+  doAssert sum([1, 2, 3, 4]) == 10
+  doAssert sum([]) == 0
+  doAssert getPos( (x: 5, y: 7) ) == 12
+
+  # bug #1669
+  let filesToCreate = ["tempdir/fl1.a", "tempdir/fl2.b",
+              "tempdir/tempdir2/fl3.e", "tempdir/tempdir2/tempdir3/fl4.f"]
+
+  var found: array[0..filesToCreate.high, bool]
+
+  doAssert found.len == 4
+
+  # make sure empty arrays are assignable (bug #6853)
+  const arr1: array[0, int] = []
+  const arr2 = []
+  let arr3: array[0, string] = []
+
+  doAssert(arr1.len == 0)
+  doAssert(arr2.len == 0)
+  doAssert(arr3.len == 0)
+
+  # Negative array length is not allowed (#6852)
+  doAssert(not compiles(block:
+    var arr: array[-1, int]))
+
+
+  proc mul(a, b: TMyarray): TMyArray =
+    result = a
+    for i in 0..len(a)-1:
+      result[i] = a[i] * b[i]
+
+  var
+    x, y: TMyArray
+    o: TObj
+
+  proc varArr1(x: var TMyArray): var TMyArray = x
+  proc varArr2(x: var TObj): var TMyArray = x.arr
+
+  x = [4, 5, 6]
+  echo repr(varArr1(x))
+
+  y = x
+  echo repr(mul(x, y))
+
+  o.arr = mul(x, y)
+  echo repr(varArr2(o))
+
+
+  const
+    myData = [[1,2,3], [4, 5, 6]]
+
+  doAssert myData[0][2] == 3
+
+
+
+block tarraycons:
+  type
+    TEnum = enum
+      eA, eB, eC, eD, eE, eF
+
+  const
+    myMapping: array[TEnum, array[0..1, int]] = [
+      eA: [1, 2],
+      eB: [3, 4],
+      [5, 6],
+      eD: [0: 8, 1: 9],
+      eE: [0: 8, 9],
+      eF: [2, 1: 9]
+    ]
+
+  doAssert myMapping[eC][1] == 6
+
+
+
+block tarraycons_ptr_generic:
+  type
+    Fruit = object of RootObj
+      name: string
+    Apple = object of Fruit
+    Banana = object of Fruit
+
+  var
+    ir = Fruit(name: "Fruit")
+    ia = Apple(name: "apple")
+    ib = Banana(name: "banana")
+
+  let x = [ia.addr, ib.addr, ir.addr]
+  for c in x: echo c.name
+
+  type
+    Vehicle[T] = object of RootObj
+      tire: T
+    Car[T] = object of Vehicle[T]
+    Bike[T] = object of Vehicle[T]
+
+  var v = Vehicle[int](tire: 3)
+  var c = Car[int](tire: 4)
+  var b = Bike[int](tire: 2)
+
+  let y = [b.addr, c.addr, v.addr]
+  for c in y: echo c.tire
+
+  type
+    Book[T] = ref object of RootObj
+      cover: T
+    Hard[T] = ref object of Book[T]
+    Soft[T] = ref object of Book[T]
+
+  var bn = Book[string](cover: "none")
+  var hs = Hard[string](cover: "skin")
+  var bp = Soft[string](cover: "paper")
+
+  let z = [bn, hs, bp]
+  for c in z: echo c.cover
+
+
+
+block tarraylen:
+  var a: array[0, int]
+  doAssert a.len == 0
+  doAssert array[0..0, int].len == 1
+  doAssert array[0..0, int]([1]).len == 1
+  doAssert array[1..1, int].len == 1
+  doAssert array[1..1, int]([1]).len == 1
+  doAssert array[2, int].len == 2
+  doAssert array[2, int]([1, 2]).len == 2
+  doAssert array[1..3, int].len == 3
+  doAssert array[1..3, int]([1, 2, 3]).len == 3
+  doAssert array[0..2, int].len == 3
+  doAssert array[0..2, int]([1, 2, 3]).len == 3
+  doAssert array[-2 .. -2, int].len == 1
+  doAssert([1, 2, 3].len == 3)
+  doAssert([42].len == 1)
+
+
+
+
+type ustring = distinct string
+converter toUString(s: string): ustring = ustring(s)
+
+block tarrayindx:
+  proc putEnv(key, val: string) =
+    # XXX: we have to leak memory here, as we cannot
+    # free it before the program ends (says Borland's
+    # documentation)
+    var
+      env: ptr array[0..500000, char]
+    env = cast[ptr array[0..500000, char]](alloc(len(key) + len(val) + 2))
+    for i in 0..len(key)-1: env[i] = key[i]
+    env[len(key)] = '='
+    for i in 0..len(val)-1:
+      env[len(key)+1+i] = val[i]
+
+  # bug #7153
+  const
+    UnsignedConst = 1024'u
+  type
+    SomeObject = object
+      s1: array[UnsignedConst, uint32]
+
+  var
+    obj: SomeObject
+
+  doAssert obj.s1[0] == 0
+  doAssert obj.s1[0u] == 0
+
+  # bug #8049
+  proc `[]`(s: ustring, i: int): ustring = s
+  doAssert "abcdefgh"[1..2] == "bc"
+  doAssert "abcdefgh"[1..^2] == "bcdefg"
+
+
+
+block troof:
+  proc foo[T](x, y: T): T = x
+
+  var a = @[1, 2, 3, 4]
+  var b: array[3, array[2, float]] = [[1.0,2], [3.0,4], [8.0,9]]
+  echo a[1.. ^1], a[^2], a[^3], a[^4]
+  echo b[^1][^1], " ", (b[^2]).foo(b[^1])[^1]
+
+  b[^1] = [8.8, 8.9]
+
+  var c: seq[(int, int)] = @[(1,2), (3,4)]
+
+  proc takeA(x: ptr int) = echo x[]
+
+  takeA(addr c[^1][0])
+  c[^1][1] = 5
+  echo c
+
+  proc useOpenarray(x: openArray[int]) =
+    echo x[^2]
+
+  proc mutOpenarray(x: var openArray[string]) =
+    x[^2] = "new one"
+
+  useOpenarray([1, 2, 3])
+
+  var z = @["a", "b", "c"]
+  mutOpenarray(z)
+  echo z
+
+  # bug #6675
+  var y: array[1..5, int] = [1,2,3,4,5]
+  y[3..5] = [1, 2, 3]
+  echo y[3..5]
+
+
+  var d: array['a'..'c', string] = ["a", "b", "c"]
+  doAssert d[^1] == "c"
+
+
+
+
+import strutils, sequtils, typetraits, os
+
+type
+  MetadataArray* = object
+    data*: array[8, int]
+    len*: int
+
+# Commenting the converter removes the error "lib/system.nim(3536, 3) Error: for a 'var' type a variable needs to be passed"
+converter toMetadataArray*(se: varargs[int]): MetadataArray {.inline.} =
+  result.len = se.len
+  for i in 0..<se.len:
+    result.data[i] = se[i]
+
+
+block troofregression:
+  when NimVersion >= "0.17.3":
+    type Index = int or BackwardsIndex
+    template `^^`(s, i: untyped): untyped =
+      when i is BackwardsIndex:
+        s.len - int(i)
+      else: i
+  else:
+    type Index = int
+    template `^^`(s, i: untyped): untyped =
+      i
+
+  ## With Nim devel from the start of the week (~Oct30) I managed to trigger "lib/system.nim(3536, 4) Error: expression has no address"
+  ## but I can't anymore after updating Nim (Nov5)
+  ## Now commenting this plain compiles and removes the error "lib/system.nim(3536, 3) Error: for a 'var' type a variable needs to be passed"
+  proc `[]`(a: var MetadataArray, idx: Index): var int {.inline.} =
+    a.data[a ^^ idx]
+
+
+  ##############################
+  ### Completely unrelated lib that triggers the issue
+
+  type
+    MySeq[T] = ref object
+      data: seq[T]
+
+  proc test[T](sx: MySeq[T]) =
+    # Removing the backward index removes the error "lib/system.nim(3536, 3) Error: for a 'var' type a variable needs to be passed"
+    echo sx.data[^1] # error here
+
+  let s = MySeq[int](data: @[1, 2, 3])
+  s.test()
+
+
+  # bug #6989
+
+  type Dist = distinct int
+
+  proc mypred[T: Ordinal](x: T): T = T(int(x)-1)
+  proc cons(x: int): Dist = Dist(x)
+
+  var d: Dist
+
+  template `^+`(s, i: untyped): untyped =
+    (when i is BackwardsIndex: s.len - int(i) else: int(i))
+
+  proc `...`[T, U](a: T, b: U): HSlice[T, U] =
+    result.a = a
+    result.b = b
+
+  proc `...`[T](b: T): HSlice[int, T] =
+    result.b = b
+
+  template `...<`(a, b: untyped): untyped =
+    ## a shortcut for 'a..pred(b)'.
+    a ... pred(b)
+
+  template check(a, b) =
+    if $a != b:
+      echo "Failure ", a, " != ", b
+
+  check typeof(4 ...< 1), "HSlice[system.int, system.int]"
+  check typeof(4 ...< ^1), "HSlice[system.int, system.BackwardsIndex]"
+  check typeof(4 ... pred(^1)), "HSlice[system.int, system.BackwardsIndex]"
+  check typeof(4 ... mypred(8)), "HSlice[system.int, system.int]"
+  check typeof(4 ... mypred(^1)), "HSlice[system.int, system.BackwardsIndex]"
+
+  var rot = 8
+
+  proc bug(s: string): string =
+    result = s
+    result = result[result.len - rot .. ^1] & "__" & result[0 ..< ^rot]
+
+  const testStr = "abcdefgasfsgdfgsgdfggsdfasdfsafewfkljdsfajsdflfdjkl"
+
+  echo bug(testStr)
+  echo testStr[testStr.len - 8 .. testStr.len - 1] & "__" & testStr[0 .. testStr.len - pred(rot)]
+
+  var
+    instructions = readFile(parentDir(currentSourcePath) / "troofregression2.txt").split(',')
+    programs = "abcdefghijklmnop"
+
+  proc dance(dancers: string): string =
+    result = dancers
+    for instr in instructions:
+      let rem = instr[1 .. instr.high]
+      case instr[0]
+      of 's':
+        let rot = rem.parseInt
+        result = result[result.len - rot .. ^1] & result[0 ..< ^rot]
+      of 'x':
+        let
+          x = rem.split('/')
+          a = x[0].parseInt
+          b = x[1].parseInt
+        swap(result[a], result[b])
+      of 'p':
+        let
+          a = result.find(rem[0])
+          b = result.find(rem[^1])
+        result[a] = rem[^1]
+        result[b] = rem[0]
+      else: discard
+
+  proc longDance(dancers: string, iterations = 1_000_000_000): string =
+    var
+      dancers = dancers
+      seen = @[dancers]
+    for i in 1 .. iterations:
+      dancers = dancers.dance()
+      if dancers in seen:
+        return seen[iterations mod i]
+      seen.add(dancers)
+
+  echo dance(programs)
+  echo longDance(programs)
+
+
+
+block tunchecked:
+  {.boundchecks: on.}
+  type Unchecked = UncheckedArray[char]
+
+  var x = cast[ptr Unchecked](alloc(100))
+  x[5] = 'x'
+
+
+
+import macros
+block t7818:
+  # bug #7818
+  # this is not a macro bug, but array construction bug
+  # I use macro to avoid object slicing
+  # see #7712 and #7637
+
+  type
+    Vehicle[T] = object of RootObj
+      tire: T
+    Car[T] = object of Vehicle[T]
+    Bike[T] = object of Vehicle[T]
+
+  macro peek(n: typed): untyped =
+    let val = getTypeImpl(n).treeRepr
+    newLit(val)
+
+  block test_t7818:
+    var v = Vehicle[int](tire: 3)
+    var c = Car[int](tire: 4)
+    var b = Bike[int](tire: 2)
+
+    let y = peek([c, b, v])
+    let z = peek([v, c, b])
+    doAssert(y == z)
+
+  block test_t7906_1:
+    proc init(x: typedesc, y: int): ref x =
+      result = new(ref x)
+      result.tire = y
+
+    var v = init(Vehicle[int], 3)
+    var c = init(Car[int], 4)
+    var b = init(Bike[int], 2)
+
+    let y = peek([c, b, v])
+    let z = peek([v, c, b])
+    doAssert(y == z)
+
+  block test_t7906_2:
+    var v = Vehicle[int](tire: 3)
+    var c = Car[int](tire: 4)
+    var b = Bike[int](tire: 2)
+
+    let y = peek([c.addr, b.addr, v.addr])
+    let z = peek([v.addr, c.addr, b.addr])
+    doAssert(y == z)
+
+  block test_t7906_3:
+    type
+      Animal[T] = object of RootObj
+        hair: T
+      Mammal[T] = object of Animal[T]
+      Monkey[T] = object of Mammal[T]
+
+    var v = Animal[int](hair: 3)
+    var c = Mammal[int](hair: 4)
+    var b = Monkey[int](hair: 2)
+
+    let z = peek([c.addr, b.addr, v.addr])
+    let y = peek([v.addr, c.addr, b.addr])
+    doAssert(y == z)
+
+  type
+    Fruit[T] = ref object of RootObj
+      color: T
+    Apple[T] = ref object of Fruit[T]
+    Banana[T] = ref object of Fruit[T]
+
+  proc testArray[T](x: array[3, Fruit[T]]): string =
+    result = ""
+    for c in x:
+      result.add $c.color
+
+  proc testOpenArray[T](x: openArray[Fruit[T]]): string =
+    result = ""
+    for c in x:
+      result.add $c.color
+
+  block test_t7906_4:
+    var v = Fruit[int](color: 3)
+    var c = Apple[int](color: 4)
+    var b = Banana[int](color: 2)
+
+    let y = peek([c, b, v])
+    let z = peek([v, c, b])
+    doAssert(y == z)
+
+  block test_t7906_5:
+    var a = Fruit[int](color: 1)
+    var b = Apple[int](color: 2)
+    var c = Banana[int](color: 3)
+
+    doAssert(testArray([a, b, c]) == "123")
+    doAssert(testArray([b, c, a]) == "231")
+
+    doAssert(testOpenArray([a, b, c]) == "123")
+    doAssert(testOpenArray([b, c, a]) == "231")
+
+    doAssert(testOpenArray(@[a, b, c]) == "123")
+    doAssert(testOpenArray(@[b, c, a]) == "231")
+
+  proc testArray[T](x: array[3, ptr Vehicle[T]]): string =
+    result = ""
+    for c in x:
+      result.add $c.tire
+
+  proc testOpenArray[T](x: openArray[ptr Vehicle[T]]): string =
+    result = ""
+    for c in x:
+      result.add $c.tire
+
+  block test_t7906_6:
+    var u = Vehicle[int](tire: 1)
+    var v = Bike[int](tire: 2)
+    var w = Car[int](tire: 3)
+
+    doAssert(testArray([u.addr, v.addr, w.addr]) == "123")
+    doAssert(testArray([w.addr, u.addr, v.addr]) == "312")
+
+    doAssert(testOpenArray([u.addr, v.addr, w.addr]) == "123")
+    doAssert(testOpenArray([w.addr, u.addr, v.addr]) == "312")
+
+    doAssert(testOpenArray(@[u.addr, v.addr, w.addr]) == "123")
+    doAssert(testOpenArray(@[w.addr, u.addr, v.addr]) == "312")
+
+block trelaxedindextyp:
+  # any integral type is allowed as index
+  proc foo(x: ptr UncheckedArray[int]; idx: uint64) = echo x[idx]
+  proc foo(x: seq[int]; idx: uint64) = echo x[idx]
+  proc foo(x: string|cstring; idx: uint64) = echo x[idx]
+  proc foo(x: openArray[int]; idx: uint64) = echo x[idx]
+
+block t3899:
+  # https://github.com/nim-lang/Nim/issues/3899
+  type O = object
+    a: array[1..2,float]
+  template `[]`(x: O, i: int): float =
+    x.a[i]
+  const c = O(a: [1.0,2.0])
+  echo c[2]
+
+block arrayLiterals:
+  type ABC = enum A, B, C
+  template Idx[IdxT, ElemT](arr: array[IdxT, ElemT]): untyped = IdxT
+  doAssert [A: 0, B: 1].Idx is range[A..B]
+  doAssert [A: 0, 1, 3].Idx is ABC
+  doAssert [1: 2][1] == 2
+  doAssert [-1'i8: 2][-1] == 2
+  doAssert [-1'i8: 2, 3, 4, 5].Idx is range[-1'i8..2'i8]
+
+
+
+# bug #8316
+
+proc myAppend[T](a:T):string=
+  echo "a:", a
+  return $a
+
+template append2*(args: varargs[string, myAppend]): string =
+  var ret:string
+  for a in args:
+    echo "ret:", ret
+    ret.add(a)
+  ret
+
+let foo = append2("1", "2", "3")
+echo foo
+
+block t12466:
+  # https://github.com/nim-lang/Nim/issues/12466
+  var a: array[288, uint16]
+  for i in 0'u16 ..< 144'u16:
+    a[0'u16 + i] = i
+  for i in 0'u16 ..< 8'u16:
+    a[0'u16 + i] = i
+
+block t17705:
+  # https://github.com/nim-lang/Nim/pull/17705
+  var a = array[0, int].low
+  a = int(a)
+  var b = array[0, int].high
+  b = int(b)
+
+block t18643:
+  # https://github.com/nim-lang/Nim/issues/18643
+  let a: array[0, int] = []
+  var caught = false
+  let b = 9999999
+  try:
+    echo a[b]
+  except IndexDefect:
+    caught = true
+  doAssert caught, "IndexDefect not caught!"
diff --git a/tests/array/tarraycons.nim b/tests/array/tarraycons.nim
new file mode 100644
index 000000000..b6ebe55c8
--- /dev/null
+++ b/tests/array/tarraycons.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "invalid order in array constructor"
+  file: "tarraycons.nim"
+  line: 14
+"""
+
+type
+  TEnum = enum
+    eA, eB, eC, eD, eE, eF
+
+const
+  myMapping: array[TEnum, array[0..1, int]] = [
+    eA: [1, 2],
+    eC: [3, 4],
+    eB: [5, 6],
+    eD: [0: 8, 1: 9],
+    eE: [0: 8, 9],
+    eF: [2, 1: 9]
+  ]
+
+echo myMapping[eC][1]
diff --git a/tests/array/tarraycons_ptr_generic2.nim b/tests/array/tarraycons_ptr_generic2.nim
new file mode 100644
index 000000000..f6ed32b58
--- /dev/null
+++ b/tests/array/tarraycons_ptr_generic2.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "type mismatch: got <ptr Hard[system.string]> but expected 'Book[system.string]'"
+  file: "tarraycons_ptr_generic2.nim"
+  line: 17
+"""
+
+type
+  Book[T] = ref object of RootObj
+    cover: T
+  Hard[T] = ref object of Book[T]
+  Soft[T] = ref object of Book[T]
+
+var bn = Book[string](cover: "none")
+var hs = Hard[string](cover: "skin")
+var bp = Soft[string](cover: "paper")
+
+let z = [bn, hs.addr, bp]
diff --git a/tests/array/tarrayplus.nim b/tests/array/tarrayplus.nim
new file mode 100644
index 000000000..09bae77fd
--- /dev/null
+++ b/tests/array/tarrayplus.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "type mismatch: got <array[0..2, float], array[0..1, float]>"
+"""
+
+proc `+`*[R, T] (v1, v2: array[R, T]): array[R, T] =
+  for i in low(v1)..high(v1):
+    result[i] = v1[i] + v2[i]
+
+var
+  v1: array[0..2, float] = [3.0, 1.2, 3.0]
+  v2: array[0..1, float] = [2.0, 1.0]
+  v3 = v1 + v2
+
diff --git a/tests/array/tidx_lit_err1.nim b/tests/array/tidx_lit_err1.nim
new file mode 100644
index 000000000..b1823e5a3
--- /dev/null
+++ b/tests/array/tidx_lit_err1.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "size of array exceeds range of index type 'range 1..2(Color)' by 3 elements"
+  line: 6
+"""
+type Color = enum Red, Green, Blue
+let y = [Green: 0, 1, 2, 3, 4]
diff --git a/tests/array/tidx_lit_err2.nim b/tests/array/tidx_lit_err2.nim
new file mode 100644
index 000000000..75f5f227b
--- /dev/null
+++ b/tests/array/tidx_lit_err2.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "expected ordinal value for array index, got '\"string\"'"
+  line: 5
+"""
+let x = ["string": 0, "index": 1]
diff --git a/tests/array/tidx_lit_err3.nim b/tests/array/tidx_lit_err3.nim
new file mode 100644
index 000000000..95922bc50
--- /dev/null
+++ b/tests/array/tidx_lit_err3.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "size of array exceeds range of index type 'range 2147483646..2147483647(int32)' by 1 elements"
+  line: 5
+"""
+echo [high(int32)-1: 1, 2, 3]
diff --git a/tests/array/tinvalidarrayaccess.nim b/tests/array/tinvalidarrayaccess.nim
new file mode 100644
index 000000000..f8bce45ef
--- /dev/null
+++ b/tests/array/tinvalidarrayaccess.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "index 2 not in 0 .. 1"
+  line: 18
+"""
+block:
+  try:
+    let a = @[1,2]
+    echo a[3]
+  except Exception as e:
+    doAssert e.msg == "index 3 not in 0 .. 1"
+      # note: this is not being tested, because the CT error happens before
+
+block:
+  type TTestArr = array[0..1, int16]
+  var f: TTestArr
+  f[0] = 30
+  f[1] = 40
+  f[2] = 50
+  f[3] = 60
+
+  echo(repr(f))
diff --git a/tests/array/tinvalidarrayaccess2.nim b/tests/array/tinvalidarrayaccess2.nim
new file mode 100644
index 000000000..0a0703834
--- /dev/null
+++ b/tests/array/tinvalidarrayaccess2.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "index 3 not in 0 .. 1"
+  line: 9
+"""
+
+# Note: merge in tinvalidarrayaccess.nim pending https://github.com/nim-lang/Nim/issues/9906
+
+let a = [1,2]
+echo a[3]
+
diff --git a/tests/array/tlargeindex.nim b/tests/array/tlargeindex.nim
new file mode 100644
index 000000000..61bcbd61d
--- /dev/null
+++ b/tests/array/tlargeindex.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim check --hints:off $file"
+"""
+
+# issue #17163
+var e: array[int32, byte] #[tt.Error
+             ^ index type 'int32' for array is too large]#
+var f: array[uint32, byte] #[tt.Error
+             ^ index type 'uint32' for array is too large]#
+var g: array[int64, byte] #[tt.Error
+             ^ index type 'int64' for array is too large]#
+var h: array[uint64, byte] #[tt.Error
+             ^ index type 'uint64' for array is too large]#
+
+# crash in issue #23204
+proc y[N](): array[N, int] = default(array[N, int]) #[tt.Error
+                                           ^ index type 'int' for array is too large]#
+discard y[int]()
diff --git a/tests/array/troofregression2.txt b/tests/array/troofregression2.txt
new file mode 100644
index 000000000..793c1744d
--- /dev/null
+++ b/tests/array/troofregression2.txt
@@ -0,0 +1 @@
+x10/0,s2,x6/11,s3,x12/1,s15,pb/m,x4/8,pn/c,x13/9,pj/e,x15/2,s15,x4/9,pp/h,x8/11,s10,x6/15,s15,pd/k,x11/8,s14,x0/6,s14,x1/7,s14,x2/9,pg/l,x0/15,pc/f,x9/12,s12,pi/d,x4/0,s15,x15/13,s10,x1/8,s10,x3/12,s12,pl/n,x6/8,s5,x3/13,s12,x4/6,s14,x1/13,s3,x12/2,s11,x9/1,ph/f,x2/15,s8,x14/4,pl/d,s7,x10/13,pi/h,x9/12,s7,x13/8,pb/d,x6/14,s15,x7/15,s1,pn/p,x4/11,pe/l,x7/12,s6,x6/14,pp/m,x11/10,s15,x13/12,pc/o,x14/10,pl/k,x1/6,s15,x4/14,s13,x6/2,pp/i,x1/10,s1,x12/2,s12,x1/10,pl/m,x0/15,s1,x9/10,s12,x11/3,ph/a,x4/12,s3,x8/2,s9,x10/3,s10,x12/6,s8,x13/4,s10,x1/11,s11,x9/4,s14,x11/13,s8,x1/2,s9,x14/3,pb/m,x15/5,s13,x13/8,pp/i,x2/3,s6,x10/15,s4,pc/h,x7/0,pb/l,x13/8,s2,x5/14,s5,x8/4,s11,pa/h,x2/13,s11,x5/14,s11,x3/4,pm/b,s9,x2/15,s9,x4/0,s6,x9/7,s3,x1/15,s5,x11/5,s10,x9/7,s2,x8/5,po/l,s13,pd/h,x0/2,s11,x14/12,s15,x3/13,pb/i,x0/10,s11,x14/9,s9,pp/c,x1/3,s15,pf/a,x10/6,s8,x9/14,pj/p,x8/3,s12,x10/15,pl/h,x4/14,s14,pa/d,x2/8,s13,x12/10,s2,x13/3,pi/g,s8,x7/8,s2,x15/10,s8,x3/1,s11,x9/4,pk/o,x13/6,s12,x10/0,s6,x5/9,s15,x0/11,s10,x12/13,s4,x11/3,s4,x8/13,pf/n,s4,x7/0,pi/b,x12/8,pg/d,x1/5,s13,x8/10,pk/i,x11/3,s10,x2/4,s13,x6/11,s1,x2/5,pe/n,x13/0,s7,x11/2,s4,x8/14,s8,x4/5,pf/g,x2/13,pe/i,s7,pn/m,x7/6,pj/o,x15/2,s4,x6/12,s14,x10/11,s8,pe/l,x9/12,s3,x11/15,s4,x14/10,pd/m,x11/13,pk/h,s4,x1/8,pc/m,x12/4,s3,x11/3,s2,x15/4,s14,x1/5,ph/o,x8/6,pb/c,x10/13,pg/f,x1/5,pp/a,x2/15,s7,x13/3,s12,x10/1,s11,x0/3,s8,x14/4,s12,x5/15,pe/f,s14,x13/12,s6,x4/11,s13,x3/5,s13,x2/13,pb/p,s10,x11/0,s3,x4/6,s10,x14/2,s15,x10/9,po/e,x4/11,pl/a,s10,x5/12,s15,x2/9,pg/d,x8/11,pb/f,x10/4,s7,x7/2,pp/o,x8/3,s4,x4/12,s5,x11/3,s1,x14/9,pl/e,x11/12,s15,pi/k,s1,x6/1,pe/b,x10/4,pl/a,x7/0,s13,x2/15,pf/k,x4/7,s14,x8/0,s6,x3/7,pm/i,x1/5,pb/l,x9/15,pp/k,x2/1,s5,x6/10,s3,x12/14,s10,x7/0,pi/h,x8/2,s2,pf/g,s2,x7/3,s3,ph/d,x14/13,s2,x1/15,po/m,x11/5,s15,x2/7,s4,x1/10,pj/a,s7,x15/14,po/k,x11/8,s10,pc/a,x6/15,s14,x12/1,s2,x7/9,pf/i,x5/4,pd/e,x11/13,s11,x9/6,pa/g,x13/8,s8,x2/14,s11,x13/9,s10,x7/11,s5,x2/14,s5,x10/7,s13,x0/13,s14,x5/3,s8,x14/15,s9,x4/0,ph/m,x14/1,po/k,x0/4,pf/b,x13/6,s10,x9/12,s1,x13/3,s1,x7/15,s12,pj/o,s12,x9/5,pm/p,x12/6,pk/j,x14/15,pc/n,x13/5,pk/a,x14/12,pn/f,x1/11,pa/p,x7/2,s8,x9/8,s8,pk/d,x2/12,s8,x15/3,pb/c,x14/9,s7,x10/7,s2,x12/11,s9,x2/3,pa/j,s15,x1/0,s9,x14/8,pc/f,x3/1,s4,x14/6,s1,x13/7,pd/o,x10/0,ph/c,x8/7,s3,x11/4,pj/g,x9/2,pp/n,x6/8,pc/k,x3/11,pa/i,x2/0,s6,x15/5,s12,x2/7,pn/b,x3/0,ph/m,s11,x7/1,s4,x5/10,s13,x11/0,pj/g,x13/3,s11,x7/15,s14,x6/0,s13,pk/a,s7,x4/15,pc/m,x13/6,pl/k,x14/1,s4,x15/11,s1,pg/p,x3/5,s13,x2/14,pa/c,x12/15,pi/k,x6/8,s10,x14/15,s5,x12/8,s15,x5/3,s9,x2/4,s14,x8/7,pb/f,x10/4,s10,x5/9,s3,x4/14,s4,x7/2,pd/j,x0/12,po/l,x3/11,pc/h,x9/0,s11,pp/b,x6/12,s3,x14/4,s9,x5/3,s9,x0/12,s1,x10/7,pd/h,x11/6,s8,pp/f,x14/12,s6,pj/i,s11,x11/0,s13,x7/6,pf/b,x15/1,pa/l,s5,x2/5,po/n,x0/3,ph/b,x8/7,s15,x4/12,s4,x14/11,s6,x15/7,pj/p,s7,x12/6,s5,x5/7,s5,x0/3,s15,x6/11,s4,x13/14,s12,x2/1,pf/g,x11/0,s12,x7/3,s12,x10/4,s10,x5/13,s14,x1/6,pp/h,x7/13,pe/i,x4/15,s6,x3/1,s7,x7/5,s13,x1/0,pj/h,x15/5,pc/i,x9/2,s7,x11/0,s2,x4/13,s8,pg/j,x2/11,s15,x8/14,s11,x6/9,pe/h,x2/12,s6,x14/0,s11,pd/b,x11/3,s10,x1/8,s12,x12/0,s13,x8/13,s7,x2/9,pg/c,x10/6,s5,x4/7,s6,x13/12,pm/o,x4/10,pc/n,x7/15,po/i,x11/3,pl/n,x15/5,pb/a,x13/0,pg/e,x1/5,pa/o,x13/0,pj/m,x14/5,s11,x7/8,s6,x15/9,s5,x14/12,s4,x4/3,ph/c,x12/6,pl/j,s11,x10/0,s9,pd/c,x14/15,s5,x11/3,s3,x8/0,s12,x13/9,s8,x5/7,pl/k,s2,x2/11,s7,x14/10,s14,x11/15,pd/a,x14/4,pj/i,x1/6,s10,x0/14,pl/g,x4/6,s9,x15/13,s9,x12/1,s13,x10/8,pi/c,x5/4,po/f,x0/8,pm/l,x5/11,s9,x8/7,pp/n,x15/10,pi/e,x7/9,pa/f,s13,x3/5,s3,x13/1,pb/d,x7/2,s12,x6/12,pc/g,x9/10,s7,x12/1,s7,x6/11,s5,x1/15,s11,x2/12,s3,x14/0,po/b,x5/7,s10,x13/9,pc/f,x7/15,po/a,x14/5,pl/b,x4/2,ph/j,x14/11,s4,x13/5,s15,pi/n,x3/10,s8,x1/13,s11,x10/9,s2,x3/6,s3,x2/15,s6,x10/12,pf/o,x1/13,s13,x11/7,s11,x9/15,pm/n,x2/14,s12,pp/i,x8/3,pm/n,x6/12,pd/o,x9/11,s4,x12/14,pc/g,x10/5,s6,x12/3,s8,pe/h,x8/1,s13,x0/15,pn/c,x7/10,s12,x15/3,s1,x11/9,pb/j,x5/15,pg/d,x13/7,s9,x1/8,pk/j,x9/7,pc/p,s3,x12/5,s6,x10/3,po/e,x1/12,s15,x8/9,s6,pa/n,x4/3,s9,x1/8,s12,x15/5,s2,x3/14,pe/h,x13/1,pf/l,x8/7,s1,x1/14,pd/a,x7/2,pp/m,x8/5,s7,x0/12,pi/b,s11,x11/2,s3,x8/0,s5,x11/3,s2,x15/9,pj/o,x1/5,s9,x8/4,s12,x3/6,pk/a,x11/7,s1,x14/2,pl/f,s3,x12/6,s9,x3/2,s15,x15/6,pk/i,x12/1,pe/d,x6/10,s12,x15/0,pn/a,x9/10,s4,x13/3,s2,x9/6,s4,pm/b,x4/5,s2,x1/3,s2,x13/10,s1,x1/2,s4,x11/0,po/f,x9/4,s4,x1/0,pp/m,x15/4,s7,x5/2,s4,x8/9,s14,x5/13,pb/c,x8/3,pe/d,s11,x14/13,s3,x6/9,s6,x14/1,s10,x4/0,pk/n,x3/2,pb/f,x15/13,s4,x12/4,pj/o,x11/0,s9,x4/5,s8,x3/11,pn/h,x1/6,pd/a,x14/7,s4,x0/3,s4,x5/15,ph/c,s14,x2/14,pk/p,x11/12,s1,x15/14,pg/n,x10/2,s10,x14/6,s15,x3/4,s12,x14/1,pk/f,x6/10,pn/h,x3/4,pc/a,x10/7,pk/j,x13/6,pi/d,x10/12,pl/c,x4/5,s6,x0/3,s5,x8/14,s12,x7/3,pk/n,x11/5,s7,x9/7,s1,x6/4,pg/f,x5/7,s12,x0/12,s11,pi/b,x14/2,s3,x13/7,s14,x0/3,s8,pk/o,s1,x12/5,pi/e,x2/8,s13,x3/12,s5,x10/14,s8,pd/f,s10,x0/5,s3,x2/3,s2,x14/15,s14,pj/n,s4,x0/6,s12,x13/1,pp/c,x5/12,po/j,x10/13,pb/c,x5/11,pd/o,x8/9,pn/b,x11/2,s12,x15/8,pd/p,x14/0,ph/l,x4/2,pi/f,x5/6,s1,x4/0,s10,x12/2,s4,x15/13,pe/m,x4/6,s10,x12/1,pb/c,s10,x6/3,s6,x9/10,s11,x5/12,pj/f,x7/2,pa/d,s7,pl/k,x12/4,s7,x7/2,s10,x3/9,s13,x12/8,s13,x4/1,pf/o,x9/2,s12,x3/15,pa/e,x1/5,s10,x10/6,s1,x3/9,pc/d,x6/0,pf/j,s12,x3/2,s11,x1/14,s5,x7/0,s11,x1/15,ph/k,x8/7,s15,pa/p,x14/2,s4,x0/15,s9,x3/11,s5,x8/15,pn/l,x3/4,s15,x5/13,s5,x4/14,s8,pj/e,s4,x10/8,s7,x2/11,s1,x12/1,s11,x5/15,s3,x6/10,pf/i,s12,x1/13,pe/n,x0/15,s7,x2/14,s2,x15/9,pl/b,x1/7,pj/o,x0/12,s15,x1/9,pk/i,x4/11,pb/d,s7,x8/6,pa/j,x0/3,pi/m,s7,x13/9,pe/d,x10/11,s8,x0/5,s10,x8/13,pk/b,x15/7,pf/c,x2/1,s2,x3/4,pj/h,x10/8,s10,x3/5,s14,x15/1,pc/i,x8/5,pp/e,x6/15,s2,pj/l,x12/9,po/m,x3/8,s9,x4/9,s6,x13/15,s10,x3/10,s3,x5/11,pd/e,x4/15,s6,x1/2,s1,x14/10,pl/c,x2/4,pj/d,x3/9,pi/b,x13/12,s6,x15/2,s6,x4/5,pd/m,x7/15,s12,x2/10,pl/o,x7/15,pi/f,x14/3,s11,x5/7,pk/b,x2/8,pj/e,x9/14,pk/n,s6,x0/5,pl/a,x15/14,s5,x2/4,s9,x12/0,s14,x10/15,pd/h,x3/5,s1,x6/13,s14,x15/9,s11,x4/7,pg/e,x1/0,pi/a,s4,x12/13,s13,x11/1,s4,x10/9,s15,x3/2,pg/e,s1,pl/f,x15/6,s1,x4/13,pa/o,x9/14,pk/e,x7/10,s14,x5/15,s4,x8/0,pc/o,x3/6,s8,x0/13,s4,x10/5,pn/h,x14/6,pc/g,s12,x11/12,s11,x10/5,pk/o,x0/3,s13,x8/14,s13,x7/15,pe/j,x0/12,pc/o,x15/13,s4,pl/i,x14/3,s5,pm/j,x6/15,s15,x10/1,ph/d,x5/2,pl/f,x9/6,s8,x15/3,pa/m,x0/11,s4,x14/2,s8,x10/0,s11,x1/13,s5,x15/2,pd/c,x11/1,s10,x0/5,s12,x1/11,s3,ph/p,x5/15,pb/k,x2/1,pn/m,s9,pj/i,x6/15,pe/o,x1/14,s12,x0/11,s11,x8/1,s7,x6/11,s8,pj/b,x7/15,pl/o,x12/5,pf/i,x13/2,s14,x10/5,s7,x15/7,pj/k,x12/8,pg/l,s1,x13/10,s9,x6/1,s2,x15/2,s11,x9/12,pn/m,x5/0,pa/i,x2/7,s15,pb/m,s12,pi/e,x12/8,s9,x2/1,s2,x0/12,pc/d,x2/11,s8,x8/10,s5,x2/7,pe/g,x10/3,s5,x8/15,s13,pl/a,x13/11,pe/b,x0/10,s13,x14/11,s14,x12/4,pi/h,s9,x14/2,s6,pe/m,x15/5,s4,x1/6,s12,x14/13,s2,x0/11,pp/l,x3/7,po/g,x15/11,s12,x12/14,pp/a,x5/13,s6,x10/1,s6,x9/7,s13,x5/8,s3,x10/1,s11,pb/m,x7/11,s3,x12/8,po/l,x1/2,pp/a,x8/9,s14,pe/b,x2/3,s15,x14/11,s5,pc/j,x12/3,s15,pe/b,x13/10,s9,x1/11,s10,x7/13,s13,x14/9,s2,x2/6,s12,x15/7,s3,x13/0,pa/m,x11/15,s10,x12/9,s9,x13/10,s5,x1/2,s7,x10/6,s15,x9/1,pg/f,s1,pb/k,x8/7,pg/m,x14/1,s13,x4/8,pi/h,x12/14,pa/c,x15/9,s5,x7/0,pp/m,x11/12,pb/n,x8/1,s1,x12/3,s4,x8/0,s15,x13/4,pk/a,x7/2,pg/n,x11/14,pk/e,x9/1,s3,pl/b,x14/3,s10,x10/13,s10,x8/1,pn/o,x14/9,pe/c,x1/12,pb/m,x14/11,po/n,x9/0,s10,x8/2,pb/j,x12/3,ph/l,x8/7,pi/c,x10/6,ph/p,x9/11,s7,x2/14,s14,x8/3,s13,x1/14,s5,x4/0,pf/b,x1/13,pp/j,x8/12,s1,x1/11,s15,x6/5,s6,x13/7,s13,x0/10,pb/k,x4/9,pd/a,x13/5,s5,x11/2,s8,x13/9,s1,x11/0,s3,x3/2,pi/n,x1/15,s14,x6/14,s5,x12/0,pg/h,x10/8,pa/l,x12/7,s8,x3/14,pm/n,x9/7,s13,x15/13,pp/a,x12/10,s4,x5/9,s2,x2/10,s14,x3/5,pg/h,x10/4,s12,x6/9,s10,x11/4,pf/l,x10/13,pi/o,x6/8,s5,pl/d,x3/2,s5,x10/4,s9,x2/1,s10,x8/15,s3,x0/5,s9,x2/7,pb/e,s9,x15/4,pp/j,x8/10,pk/i,s7,x15/4,s7,x6/8,pp/a,x10/3,pd/g,x15/14,s7,x4/0,pb/j,x12/8,s9,x4/0,s6,x11/10,s9,x9/4,s8,x13/3,pc/d,x7/12,s11,x10/8,s11,x13/1,s4,x5/11,s8,x12/0,s6,x11/13,s8,x2/0,s7,x9/12,pl/a,s14,x2/13,ph/f,x6/12,pm/g,x4/8,pi/l,s1,x5/10,pa/d,x1/13,pp/h,x15/5,s9,x14/0,s8,x12/4,pa/c,x3/5,s11,x2/11,s4,x3/0,s2,pi/g,x14/2,pa/d,s15,x3/4,s8,pj/p,x15/10,s14,x4/13,pm/i,s15,x11/8,pj/b,x6/0,s9,x12/13,s14,x3/10,pi/m,x4/6,po/f,x9/14,s2,pd/i,x12/0,s15,pk/g,x11/14,s1,x9/0,pj/f,x8/2,pk/m,x4/14,pb/o,x11/2,pc/d,x8/0,s14,x15/5,s13,pl/e,x6/11,pb/c,x2/0,pj/h,x15/3,s15,x7/2,s5,x10/3,pf/m,x5/11,pi/l,x14/7,pd/j,x13/5,pp/n,x1/12,s13,x6/4,pb/m,x7/12,s8,pk/l,x15/2,pf/p,x5/8,pi/m,x14/13,s10,x3/8,s1,x9/6,s15,x13/3,pe/b,x5/10,s3,x6/4,s9,x8/7,s13,x3/15,pp/j,x11/6,s7,x9/2,pm/b,x0/3,pd/j,x2/14,s4,x15/3,pm/o,x1/5,s15,x4/8,pa/i,x2/9,pn/h,x1/14,pc/i,x5/15,pk/p,x4/7,pg/n,x2/6,s3,x11/4,pb/h,x8/3,s10,x12/13,s5,x14/11,s9,x2/4,s1,x11/1,pg/l,x4/14,s4,x3/12,pn/j,x2/15,pl/p,x7/5,s6,x3/4,s2,x7/5,pf/j,x12/10,pm/c,x2/14,pi/o,x13/1,pd/m,x11/3,s5,x8/15,s7,x1/0,pi/a,x4/6,s13,x15/13,s9,x1/12,s11,x9/15,ph/k,x2/6,pf/e,x5/11,s4,x13/9,s2,pn/b,x4/7,s5,x9/6,s5,x13/1,s4,x7/8,s6,x11/10,s13,x13/1,pp/d,x9/6,pc/g,x13/7,s7,x9/2,s7,x4/11,po/f,x2/7,pd/i,x8/13,s11,x2/10,pp/h,x3/1,pe/n,x0/5,s3,x14/13,s8,x15/11,s14,x7/10,s15,x3/12,pp/j,x1/14,s12,x10/11,po/i,x5/13,pl/n,x4/0,s14,x1/3,s14,x4/14,s6,x2/6,pg/e,x10/3,pc/h,x2/0,s7,x11/4,s8,po/f,x9/1,pa/e,x4/11,s14,x1/3,s13,pn/d,x13/12,s4,x11/7,s7,x12/13,s11,x6/2,s4,x4/0,s7,pm/k,x6/8,s8,x14/13,pn/d,x8/15,s8,x13/9,s13,x12/10,s3,x3/7,s15,x9/1,pf/o,x0/14,pa/p,s9,x4/12,pl/n,x11/9,pg/i,x8/7,pe/n,x4/9,pp/d,x15/3,s5,x10/7,po/m,x12/3,s10,x4/10,pb/f,x15/6,s5,x12/13,po/l,x15/11,s8,x4/7,pj/d,x13/12,pn/g,x11/2,s5,x12/14,pl/h,x9/2,pd/g,x15/8,ph/l,x1/3,s7,x9/2,pp/d,s1,x5/1,s6,x12/7,s1,x9/8,pk/b,x12/11,s13,x8/1,s11,pl/h,x7/9,pe/n,x0/2,s2,x14/5,s4,x2/15,s4,x4/5,pa/b,x3/15,s14,x5/0,s13,x4/15,pg/o,s2,x3/13,s9,x2/15,s10,x10/12,pk/f,s12,x2/8,pl/h,x12/10,pa/o,x7/8,pi/b,x14/4,pa/c,x7/5,s3,x15/2,s6,pd/k,x11/3,s10,pj/m,x4/9,pp/e,s4,x5/15,s10,x11/1,pn/d,x4/15,s13,x1/9,s15,x15/6,s8,x1/11,s4,x0/5,s15,x11/12,s7,x7/10,s9,x13/1,s13,x5/12,s3,pm/h,s15,x10/14,s10,x11/12,pp/c,s14,x0/1,s8,x3/2,s8,x12/13,pe/g,x2/14,s15,x13/8,pd/a,x1/0,s11,x8/13,pm/g,x12/9,pe/j,s15,x4/7,s8,x6/10,pd/f,x2/1,s13,x5/15,s4,x3/12,pb/e,s7,pm/d,x5/7,pi/k,x13/14,pp/o,x12/8,s3,x4/1,pc/b,s12,x12/8,s2,x3/5,pg/h,x6/9,s15,pa/i,x10/1,s8,x13/0,pf/n,x14/1,s14,pk/a,x3/4,s7,x5/0,s13,x1/13,s6,x2/0,pd/g,x7/1,pn/m,x12/6,s6,x5/15,pc/a,x10/0,s4,x6/13,s15,x12/3,s13,x0/5,pl/f,x6/8,s15,x1/0,s15,x11/15,s8,x14/1,pk/o,x0/13,s1,x2/10,pi/d,x15/11,s2,x0/7,s5,x13/6,s8,x8/0,s13,x11/15,s14,x4/8,s2,x0/1,s7,x6/5,pk/j,x13/1,s1,x14/0,s10,x10/12,s5,x6/3,ph/n,x11/2,s2,x7/14,s3,pi/c,x2/0,s9,x12/5,s14,x9/11,pb/e,s4,x15/7,s7,x10/9,ph/g,s3,x0/11,pf/e,x12/8,s5,x1/5,s11,x2/7,s11,x10/6,s14,x7/2,s3,x6/11,s7,x9/5,s9,x6/12,s9,x15/5,pj/b,x0/7,s8,x9/3,s6,x4/15,pi/k,x7/5,pl/f,x9/14,s9,x0/3,s9,x8/4,s15,pd/g,x2/12,pb/p,x13/11,s14,x3/10,s7,x12/8,s6,x1/5,pc/k,x3/12,s3,x8/13,po/l,x6/3,s4,x9/1,pn/f,s11,x5/13,s2,x4/15,pj/k,x12/9,pl/o,x11/14,s11,x15/1,s6,x12/14,s12,pb/h,x2/4,po/g,x6/3,s4,x14/15,pa/b,x1/0,s14,x6/11,s3,x13/0,s7,pp/l,x6/7,s2,x10/5,s9,x12/2,po/k,x9/15,ph/a,x4/8,s6,x1/9,pf/m,x4/12,s5,x5/2,pj/n,x3/15,s3,x1/7,pm/g,x11/12,s3,x10/2,pf/c,x9/6,pa/n,x7/15,s14,x3/4,s8,x15/10,s10,x9/8,pm/l,x3/6,s10,x8/4,s5,x14/15,s14,x1/4,s4,x9/5,s10,x6/13,s7,po/p,x9/12,s2,x13/6,pf/j,x10/1,s3,x11/0,s2,x14/3,pk/a,s10,x5/8,pb/g,s11,pk/a,x6/7,pm/c,x9/14,s8,x12/6,pf/d,x11/8,pm/i,x4/13,pc/a,x8/10,pn/b,x3/12,s7,pg/f,x5/2,pl/b,s5,x8/0,s4,x14/11,pg/p,x3/12,s4,x10/5,pj/o,x13/7,pp/m,x3/10,s8,x9/4,pl/e,x14/10,pi/o,x13/4,s12,x11/8,s7,x0/2,s10,x4/15,s1,x0/10,pe/j,x15/13,pl/c,x6/12,s6,x4/10,ph/i,x12/11,s9,pc/l,s3,x10/2,s12,x6/0,po/f,x2/13,s5,pg/j,x5/6,s8,x3/8,s6,x9/11,pd/i,x5/13,po/p,x2/0,s11,x13/3,pf/j,x1/9,s11,x13/8,s5,x4/12,pl/i,x3/5,pe/h,x4/14,pn/d,x13/15,s13,x4/10,pb/l,x9/7,s10,x14/0,s9,x4/13,pd/n,x14/7,s13,x5/2,pf/g,x4/9,pb/c,s6,x15/12,s7,x5/10,s15,x4/14,po/l,s7,x15/0,ph/a,x14/5,pb/l,x0/10,pc/j,x14/7,s3,x8/12,s11,x15/0,s14,x10/13,s2,x9/1,pb/m,x14/3,s12,x10/8,pg/n,x15/0,s9,x9/10,pi/m,x0/12,s13,x7/6,s11,x15/8,pf/g,x12/2,s7,x6/1,s4,x2/9,pp/i,x14/8,s6,x6/11,pd/g,x2/13,s8,x0/10,pl/e,x3/14,s5,x15/13,s10,x10/11,s6,x12/9,s6,x8/1,pj/i,x2/14,pd/b,x4/3,s9,x6/1,s12,pj/f,x7/15,s12,x13/8,s8,x4/12,s4,x6/2,pb/p,x5/4,pn/f,x10/1,pb/a,s10,x7/13,s7,x0/4,pk/m,x9/3,s9,x14/5,s10,x13/15,s2,x8/2,s7,x1/3,pg/b,x2/0,s11,x3/1,s15,x10/14,s12,x0/6,s11,x8/14,pa/o,x3/7,s11,x5/14,pi/f,x10/6,s13,x14/8,pk/c,x4/3,s12,x9/2,s2,x3/1,s1,x5/15,s8,x3/8,s10,x10/11,s10,x14/3,s3,x15/7,pb/j,x8/11,s9,x5/6,s13,x12/13,s13,x1/10,pd/k,x11/14,s5,x13/10,ph/n,x5/6,s7,x14/11,pa/k,x12/6,s15,x4/15,po/d,x8/12,s7,x2/11,pa/b,x6/12,s9,x3/11,s8,x12/1,pl/e,x10/7,s10,x8/4,s10,x6/12,s13,x8/7,pk/m,x10/12,s9,x8/2,pa/i,x14/9,s12,x6/11,pn/m,x13/1,s12,x14/6,pi/g,x0/11,s2,x6/15,s1,x4/12,s7,x1/11,s2,x7/12,s12,x15/14,pp/h,x8/1,pi/o,x7/13,pc/a,x14/0,s5,x2/7,s8,x5/8,pg/k,x12/10,pj/o,x11/8,pl/d,x6/4,s15,x14/12,pj/k,x15/9,s15,x0/1,pf/o,x8/4,s14,x13/14,s12,x3/15,s1,x0/6,s8,x9/3,pk/n,x2/11,s11,x1/4,pf/c,x6/7,pb/n,x11/14,s9,x7/2,s11,x3/12,pi/d,x9/2,s6,x12/7,s15,x3/11,pc/g,x6/10,pi/e,x0/11,s6,x9/13,s1,x11/1,ph/g,x15/10,pj/a,x14/6,s10,x8/13,s8,x9/0,s5,x13/1,pb/i,x15/2,s6,pp/a,s4,x4/13,pj/h,x7/5,s6,x15/14,pm/o,x4/7,s1,x3/12,pp/a,x11/4,pg/d,s14,x10/13,s15,x1/12,s11,x5/7,pp/k,x12/1,s15,x11/5,s12,x3/6,pl/c,x14/2,s3,x15/4,pb/m,x3/1,pa/h,x5/6,pf/j,s13,x15/10,ph/e,s3,x5/11,pi/f,x15/10,s11,x7/14,pj/a,s12,x6/13,ph/c,x1/12,pg/i,x6/8,pp/f,x10/4,pg/d,x14/6,pp/b,x5/3,s6,x8/11,s10,x9/1,pe/m,x2/14,s3,x7/9,pl/b,x10/2,pf/p,s1,x15/0,pb/j,x9/8,s10,x5/10,s14,x4/2,s8,x12/1,s12,pi/d,x11/13,po/c,x4/10,pi/d,x15/7,s11,x10/8,pj/m,x7/9,pb/d,x8/5,po/f,x7/2,pe/h,x10/13,pb/i,x9/4,pm/l,x6/3,s3,x4/12,s2,pd/o,x8/5,pa/p,s14,x1/14,s1,pi/d,x2/12,pl/o,x1/13,s3,pp/f,x7/9,ph/j,x0/2,pm/e,x11/4,s13,x12/6,pj/b,x3/8,pk/a,x5/6,s10,x10/11,pe/o,x12/9,pj/p,x0/5,s11,x14/9,pe/f,x3/4,pa/p,s14,x6/0,s11,x8/3,pd/f,x11/5,s14,x9/2,s7,pg/n,x0/14,pj/c,x4/3,s11,x14/2,s1,x0/7,s11,x8/2,s13,x12/3,s11,x9/7,s14,x10/2,s9,x1/12,pi/o,x14/3,pc/b,x7/8,s7,x11/14,s4,pp/l,s5,x2/8,s11,x11/9,pk/e,x5/1,s15,x2/14,pb/d,x11/7,s15,x13/15,pk/o,x5/4,s4,x6/2,pc/p,x8/9,pj/f,x5/10,pb/i,x9/8,s10,x6/10,pj/a,s7,x5/8,s2,x13/14,s12,x11/10,s6,x5/4,pb/p,x1/10,pc/d,x6/12,pm/o,x9/15,s4,x14/2,s7,x12/8,s14,x3/1,pp/b,s2,x8/2,s4,x15/0,s14,x7/11,s4,x5/13,s11,x10/7,s8,x2/9,pe/d,x0/1,s13,pm/f,s10,x3/15,ph/l,x9/11,po/e,x15/1,pg/p,x4/0,pn/b,s12,x13/12,pm/l,x6/4,s11,x3/2,s6,x0/4,pe/p,s4,x8/7,s12,x4/3,s11,x12/10,s1,x9/6,s14,x15/13,s14,x0/4,pc/m,x9/7,s9,x11/13,ph/j,x14/1,pc/m,x11/0,ph/o,x4/15,s14,pp/f,s7,pi/b,s10,x11/12,s4,x4/9,s14,x10/13,pg/l,x1/12,pn/f,x5/8,s15,x15/12,ph/m,x14/3,pl/e,x9/5,ph/i,x4/8,s6,x9/11,s10,x13/1,s9,x0/12,pc/k,x13/4,s9,x1/7,s9,x0/15,pb/l,x12/5,pm/p,x0/8,ph/c,x5/7,s8,x11/14,s6,x0/5,pm/g,x1/12,s4,x5/8,pf/c,x6/15,s10,pb/a,x14/5,s1,pj/e,x3/4,s4,x12/15,s8,x13/3,pa/d,s14,x6/9,po/e,x5/13,s10,x12/10,s2,x0/3,pp/b,x5/15,s15,x12/14,s7,x2/7,pj/d,x0/11,pb/l,x14/8,s14,x13/2,s2,x4/7,pp/g,x11/8,s8,x3/9,pb/l,x1/10,s9,x7/0,po/g,x12/15,pd/h,s4,x10/13,s14,pm/g,x5/9,ph/e,x7/4,po/j,x5/9,s13,pg/d,x2/13,pi/n,x7/14,s14,ph/c,s2,x4/3,pl/o,x10/0,pa/k,x12/2,pd/i,x15/1,pl/n,x4/2,pe/j,x14/3,s14,x12/13,pf/n,x5/2,pa/e,s5,x11/14,s2,pc/h,x9/7,pa/d,x14/8,pc/b,x9/3,s1,pe/h,x1/11,s15,x13/2,s10,x14/1,s1,x15/2,s3,x14/7,s14,x15/1,s5,x10/2,s3,x13/15,s9,x1/4,s5,x10/8,s6,x5/14,s7,x7/6,pj/m,x8/14,s6,x10/6,pa/h,x11/13,s7,x12/9,s5,x5/2,pi/d,x6/0,pg/a,s14,x2/14,s13,pd/n,s4,x15/9,s2,x2/12,pa/f,x4/8,pi/d,x6/15,pa/g,x9/13,pc/b,x3/4,s6,x0/10,s10,x13/12,s1,x6/14,s11,x5/11,s5,x8/1,ph/i,s12,x13/11,s6,x9/1,pe/c,x12/10,pl/g,x9/5,s3,x8/3,pe/d,x6/11,s12,x12/10,s4,x8/5,s6,x0/4,s10,x9/13,pg/n,x5/14,s5,x1/6,pc/j,x11/2,s2,x3/8,s11,x5/6,s12,x0/10,pf/a,x3/11,s2,x4/8,pp/e,s7,x5/1,s4,x6/0,s6,x4/1,s6,x15/6,pi/j,x13/10,s14,x8/7,pp/f,x10/2,s12,x0/6,pk/d,x5/13,s1,x2/9,s3,x15/8,pi/b,s14,x10/0,s2,x7/5,s14,x12/15,s3,x13/11,pe/m,x14/0,s11,x4/3,s3,x15/1,po/b,x0/9,pn/f,x5/1,s12,x12/2,s5,x1/5,pg/i,s5,x11/13,pd/m,x9/6,s11,pp/i,x2/3,s15,x5/14,ph/k,x12/2,pg/m,s6,x10/14,pj/n,x12/3,s12,x14/10,s12,x15/9,pg/p,s5,x6/4,s10,x7/10,s9,x3/0,pa/h,x4/12,s13,po/f,x1/8,s9,x13/11,pi/n,x7/14,pp/o,s15,x10/4,pl/d,x1/6,s12,x5/0,s1,x2/9,pa/c,x11/15,s10,x7/1,ph/b,x4/14,s1,x11/8,pn/a,x10/5,pl/j,x11/3,s9,pi/p,x4/0,s7,x15/12,pk/d,x2/7,s5,x10/6,pa/h,x7/12,pe/c,x3/9,pa/d,x11/0,s7,x4/13,s10,x12/15,s14,ph/n,x4/8,pg/d,x5/10,s15,x0/13,pp/c,x5/9,s11,x0/11,s13,x4/15,s11,x13/7,s1,x4/8,s12,x5/7,s6,pj/d,x13/14,pm/e,x2/11,s8,x3/0,pl/i,s11,po/f,x11/12,pe/g,x14/15,pb/f,x4/8,pi/p,s11,x9/2,pn/b,x1/6,s3,x10/15,pa/p,x1/14,pi/h,x0/8,s4,x9/1,pe/d,x5/6,s5,x15/8,pa/n,x4/0,pc/b,s6,x13/12,s10,x4/2,pd/f,x9/5,s1,x3/10,pm/n,s6,x14/4,pk/l,x2/10,pe/n,x1/12,pd/i,x5/6,s7,pn/l,x15/7,s9,x8/11,pi/a,s4,x9/5,s13,x6/8,s6,x4/13,s2,x11/12,pk/l,s7,x10/5,ph/e,x4/2,s3,x14/15,s11,x0/1,pp/l,x7/10,s7,x3/12,s1,x7/6,pc/f,x5/13,pn/e,x10/8,s11,x6/2,pm/f,x8/3,pk/g,x1/9,po/p,x3/5,s2,x2/1,pd/i,x0/5,s3,x7/6,pc/b,x3/0,s11,pf/m,x12/8,s1,x1/3,pe/g,x0/12,s1,x15/5,s13,x6/4,s7,x0/7,s5,x14/9,s3,x10/12,s14,x4/7,s6,x9/15,s3,x10/11,pk/c,x7/4,s6,x8/13,s6,x5/6,s2,x12/14,pn/d,x1/10,pj/b,s14,pd/l,x5/14,s12,po/m,x9/11,pl/f,x15/3,ph/j,s8,x6/11,s8,x1/9,s3,x0/13,pf/o,x2/6,s1,pl/k,x12/4,pp/o,x8/0,pj/n,x4/15,s2,pe/c,x6/13,s3,x0/10,s5,x8/6,s10,x5/12,pf/p,s5,ph/b,x4/15,pl/i,x10/0,pa/g,s14,x3/12,pe/o,s6,x5/6,pl/g,x8/1,s7,x6/12,pp/h,x4/14,s8,x8/11,s6,x12/4,pj/e,x3/8,s15,x9/14,ph/k,x0/3,s9,x14/6,pi/f,x5/15,s13,pd/j,x11/14,s8,x6/5,s11,x3/1,s1,x2/13,s11,x7/1,pa/p,x8/11,s4,x15/6,s14,pg/e,x13/5,s8,x1/10,s8,x8/6,s3,x13/4,s8,x6/8,pj/h,s14,x10/3,pn/b,s12,x4/5,s7,x0/1,s3,x15/4,s5,x5/8,s3,x7/3,pf/c,x5/11,s15,x14/4,s5,pk/d,x0/15,pj/l,s11,x10/7,s8,ph/p,x2/5,s9,x6/9,pi/n,x3/0,pj/p,x11/1,s15,x8/3,pm/g,x9/1,pd/j,x15/3,s14,x0/9,s9,pc/h,x1/6,pl/k,x11/7,s13,x4/13,pe/b,x15/5,pk/d,s13,x8/12,pe/b,x9/1,po/i,x15/2,s11,x11/4,pj/g,x5/12,s10,x10/2,s9,x0/8,s5,x5/6,pn/p,x0/10,s2,x13/14,s2,x7/2,s4,x6/9,s6,x1/14,pj/g,s11,x3/9,s8,x14/13,pi/b,s15,x3/10,pe/f,x13/12,s14,pj/d,x3/2,pm/f,x13/10,pk/j,x5/11,pc/d,x13/8,pp/i,x11/6,s8,x7/0,s14,x3/1,s13,x2/13,s7,x6/8,s2,x7/15,s4,x10/14,s13,pb/n,x2/6,pj/h,x15/10,s14,x13/1,pb/d,x0/5,s10,x14/3,s9,x12/5,s1,x7/4,pn/e,x9/2,pf/k,s2,x12/1,s11,x5/2,s15,x8/7,s4,x12/1,pj/n,x0/7,pf/k,x11/2,s11,x15/3,pe/m,x0/4,s11,x5/8,s4,x10/15,s7,x2/14,s2,x11/5,s9,x7/6,pj/n,x11/13,s5,x2/10,s11,x15/8,s11,x11/13,pi/b,x3/8,pm/e,x9/5,s14,x4/3,s7,po/j,x12/10,s4,x14/0,s15,pi/a,x7/4,pg/n,x3/1,s3,x11/14,ph/m,x13/12,s11,x2/14,s13,x0/10,s11,x9/12,s13,x3/7,s4,x9/12,s15,x5/3,s5,x10/15,s2,x4/13,s14,x9/10,pj/p,x11/2,s14,x5/10,pn/m,x9/7,s3,x8/10,s7,x15/4,ph/f,x9/5,s15,x8/10,pi/g,x9/12,s14,x14/10,po/h,s13,x9/15,pc/n,x12/10,s7,x6/3,s13,x5/13,s8,x8/2,pd/b,s11,x7/12,s12,x10/13,pp/g,x12/9,s1,x11/13,s15,x1/14,pd/c,x0/10,pp/f,x4/15,s2,x12/8,pl/e,x0/6,s10,x4/2,s12,x5/10,s11,x8/7,pm/p,x6/14,s9,x0/11,s4,pc/d,x5/1,pe/k,x4/9,s9,x7/0,pb/j,x8/15,s10,ph/c,s11,x14/5,pe/d,x0/3,pm/g,x6/15,s15,x9/4,pj/e,x0/12,pn/h,x6/1,s4,x7/10,s14,x6/4,s4,x11/9,s9,x4/3,pg/a,x1/11,pc/e,x9/14,s5,x7/4,pg/d,x5/11,pm/n,x9/4,s14,x7/6,pe/l,x8/3,s5,x0/15,pp/g,x7/6,po/c,x14/12,s1,x2/11,s11,x9/0,s10,x5/1,s10,x10/6,s4,x3/13,s15,x10/8,s15,x13/1,s10,x10/5,s3,x9/15,s7,x8/5,pa/i,s14,x4/10,s10,x14/7,ph/p,s3,x2/13,s10,x1/14,s4,x11/0,s13,pb/j,s9,x7/8,pd/e,x1/14,pa/m,x6/2,s15,x15/13,s14,x10/0,s5,x2/4,pp/f,x8/9,pg/h,s3,x11/1,pa/l,x10/0,s3,x15/12,pp/e,x3/4,s8,x5/15,pi/m,x6/2,s8,pk/e,x13/11,pm/n,x2/0,s3,x15/3,s10,pf/i,x7/9,s1,x3/8,s9,x12/2,pn/d,x6/7,pe/j,x9/15,s8,x7/4,s3,x0/14,po/k,x12/7,s7,x13/6,pd/b,x9/8,s15,x7/5,s13,x9/15,pl/a,x5/6,s13,x13/3,s7,pm/c,x14/0,s9,x10/13,pj/b,s8,x4/14,s7,x15/5,s6,x2/4,pd/i,s4,x6/11,pk/h,x3/12,s12,x14/5,s1,x15/6,s3,x3/12,pb/e,x5/8,pm/n,x0/15,pe/b,x1/13,pn/p,x4/12,s11,x15/8,s8,x9/3,pa/b,x13/12,s5,x2/5,s14,x0/14,s3,x3/6,s9,x12/5,pp/e,x15/13,s7,x1/9,pd/o,x7/14,s11,x15/2,s1,x1/4,s13,x0/13,pg/f,x11/6,pl/m,x10/5,ph/k,x14/8,pn/c,x15/6,s12,x11/9,s10,x7/8,pb/d,x2/5,s11,x14/3,pp/g,x6/0,s12,x12/11,s6,x15/6,s7,x11/12,pd/o,x8/3,s9,x5/6,s3,pl/f,x1/2,s7,pp/i,x7/8,s10,x9/2,s13,x5/15,s4,x6/0,s11,x5/10,ph/k,x15/0,s10,x13/8,pd/n,x11/7,pa/f,s12,x2/3,s14,x5/12,pp/m,x3/10,s14,pn/o,x8/13,s1,x4/6,pi/a,x9/1,s7,x2/5,s8,x11/14,s5,x7/6,s7,x12/1,s12,x9/13,pp/k,x0/3,s13,pm/h,x2/9,pn/f,s10,x3/14,s5,x10/6,s7,pc/b,x3/2,pm/p,x12/10,s6,x4/14,s8,x8/9,s7,x13/2,s11,x14/11,pc/g,x6/9,pj/m,x2/3,pl/e,x14/15,po/j,x12/1,s9,x10/3,pc/p,x2/0,s9,x6/5,s13,pi/e,x10/12,s9,x3/6,pk/g,x14/5,s1,x3/2,pf/j,x14/13,s12,x6/9,s6,x13/10,s2,x15/4,s8,x14/1,s11,x3/11,s3,x6/8,s12,x0/14,s2,x1/12,s13,x3/14,pa/n,x12/8,s12,x15/3,s11,x4/8,s3,x10/9,pe/b,x1/14,s9,x3/8,s11,x12/15,s5,pd/i,x7/2,s8,x11/6,s11,x10/9,s3,x15/3,ph/o,x10/2,s7,x0/6,pa/m,s13,x2/9,s10,x11/0,s6,x15/5,s2,x10/14,s12,x6/2,s2,x4/5,s5,pd/c,x0/8,pk/b,x6/3,pi/a,s8,x10/13,pb/g,x8/5,s14,x10/2,pm/n,x7/9,s14,x6/13,s12,x4/5,pi/o,x12/1,pd/b,s12,x13/11,s12,x14/12,pl/h,x4/6,pd/o,x7/3,s3,x2/10,s15,x3/14,pm/n,x10/7,pj/f,x8/14,s5,x2/15,pl/e,x11/8,s12,x2/15,s8,pp/k,x14/13,s15,x9/11,s3,pa/m,x8/13,pj/c,x6/7,pe/p,x1/11,s1,x3/10,s8,x7/12,s5,x0/11,pj/d,x13/2,s12,x6/8,s11,x7/9,s7,x11/15,s6,x2/0,s1,x3/9,s12,x15/7,pn/h,x0/11,s7,pf/a,x12/4,s7,pj/i,x9/3,s2,x1/4,s9,x11/13,s13,x4/12,s7,x3/15,pn/d,x11/10,po/e,x13/5,s8,pd/a,x7/10,s1,x13/3,s15,x9/12,s1,pk/m,x15/13,s13,x12/0,pa/h,x1/8,s5,x9/14,pb/e,x0/8,s12,x2/5,s7,x8/7,pj/c,x4/3,s15,x14/15,pp/b,x7/4,ph/j,x12/15,pd/b,x2/3,pg/p,s11,x11/12,s12,x1/13,s1,x6/7,po/k,x14/10,s12,pj/e,x8/15,pk/g,x9/3,pn/m,x4/10,s15,x2/14,pa/f,x3/9,s7,x4/0,s11,x11/13,s15,pm/i,x7/9,s15,x3/2,s7,x12/0,pa/c,x15/10,pf/n,x6/8,s12,x3/10,pa/m,x5/1,s2,pe/c,x4/7,s4,x6/8,s8,pl/i,x10/11,s3,x3/14,s4,x2/15,ph/k,x1/5,s8,x3/6,pe/p,x11/1,s9,x6/10,s2,x14/8,s6,x5/15,s6,x11/4,pm/i,x7/10,pd/l,x2/11,s9,x8/10,s13,x11/12,pn/a,x14/6,s8,x3/0,pm/o,x13/2,s6,x4/8,s1,x7/2,pd/i,x12/0,pm/c,x11/5,s7,x9/6,pa/o,x0/15,s10,pg/l,s1,x11/13,pk/m,x1/7,s4,po/a,x0/3,s4,x2/1,pk/l,x6/8,s5,x2/9,pc/h,s13,pl/i,x7/5,s4,x3/6,s13,x10/1,pk/o,x11/4,pi/n,x0/6,ph/m,x12/13,s15,x5/3,s3,x15/2,s13,x3/0,pc/k,x1/9,pp/e,x12/4,s10,x3/13,pm/d,x8/10,s2,x0/3,s7,x6/12,pg/h,x8/14,pi/e,s13,x6/1,s2,x14/0,s9,x8/1,pl/o,x5/11,pc/m,x15/9,s10,x4/8,s8,x0/7,s6,x4/2,s9,x12/5,pl/j,x15/7,s11,x1/2,pa/k,x3/9,s11,x12/5,pn/i,x14/9,s13,x1/15,s6,pe/p,x9/12,pb/a,s11,x11/0,s6,x14/6,ph/g,s7,x3/2,pe/c,x6/10,s11,x12/9,pi/p,x1/14,pf/g,x12/2,s11,x5/1,pj/a,x8/7,s6,x2/4,s3,x11/15,s13,x3/2,s5,x9/0,s7,x6/5,s7,x8/10,s5,x0/13,pm/h,x2/5,s11,x9/1,s1,x10/14,s4,x15/6,pn/o,s7,x11/13,ph/k,x6/1,s5,x0/4,pc/p,s15,x6/7,pm/n,x2/9,pb/a,x0/5,s13,x15/2,pm/c,x12/4,pn/b,x13/6,s6,x0/15,s5,x10/7,s6,x1/9,s4,x11/4,s3,pa/k,x7/6,pe/i,s11,x9/12,pl/p,x13/1,pg/n,s6,x12/10,s9,x11/3,s14,x6/5,pl/m,x0/9,pe/h,x11/10,s11,pf/l,s7,pk/h,x14/5,s12,x15/13,s11,x12/4,s4,x8/6,pb/g,x0/10,s12,x2/15,s3,x7/3,s9,po/e,x11/12,pp/i,x14/0,s3,x10/1,pc/n,x15/3,s9,po/h,x7/10,s15,x15/13,s11,x7/2,pb/f,x11/9,s12,x8/14,pc/p,x11/0,s7,x7/1,pf/b,x3/2,s2,x9/7,ph/a,x2/0,s11,x4/14,s1,x13/15,s9,x6/12,s8,x11/13,s3,x7/10,s6,x0/1,pf/c,x8/5,pn/k,x2/7,pf/d,x5/15,s14,x4/10,s13,x2/0,s14,x13/9,s14,x6/2,s13,x12/4,pa/b,x5/13,s5,pg/m,s3,x1/11,s11,x6/4,pn/d,x11/1,pb/c,s15,x5/14,s2,pf/k,x3/7,pa/i,x10/8,s13,x15/1,s6,x10/9,s14,pd/o,x12/14,pi/h,x6/7,s8,x2/8,s9,x7/14,s5,x13/1,s5,x8/9,s10,x10/2,s3,x1/3,s10,x0/10,s2,x12/13,s11,x3/15,s4,x1/14,s14,x6/11,s11,x12/7,s2,x3/6,s2,x9/8,pn/c,x2/1,pf/e,x12/13,s9,x15/7,pd/n,x0/12,po/f,s1,x15/6,s12,x1/4,s8,x11/15,s5,x9/8,s12,x6/0,pm/a,x15/14,pl/o,x10/0,s5,x15/6,s11,x1/11,pe/c,x0/6,pk/l,x15/4,s2,x5/14,s5,x15/13,s9,x1/3,s15,x2/11,s6,x5/3,s5,x4/2,s6,x14/12,pm/o,x8/9,s3,x6/3,pf/n,x2/9,ph/l,x12/0,pj/e,x15/7,s11,pk/b,x2/4,pd/e,s13,x11/7,s6,x12/0,pc/p,x15/6,s13,x3/7,s7,pa/f,x9/12,pi/d,x4/2,s9,x13/15,pa/k,x5/1,pe/n,x11/0,s1,x14/3,pl/j,x4/12,s6,pg/n,s3,pd/b,x5/10,pc/e,x14/3,s6,ph/p,x1/0,s5,x11/4,pk/d,x6/12,s5,x7/3,s7,x14/6,pa/c,x15/5,s14,x13/14,s2,x15/6,s11,x13/11,pg/i,x12/1,s15,x0/13,pa/e,x12/4,po/p,x1/15,pi/c,x7/3,pd/e,x8/12,s13,x6/0,s1,x5/7,pc/k,x2/1,pp/j,x5/3,s13,ph/i,x4/7,pa/m,x8/15,s15,x11/13,s14,x9/2,s1,x6/13,s14,x5/0,pe/c,x1/13,s15,x5/6,s3,x4/9,s12,x0/1,s10,x12/6,s5,x9/3,s6,x5/8,s12,x15/4,s3,x10/3,s2,x5/8,pd/b,x3/13,s10,x6/10,pa/g,x14/1,pe/k,x5/8,s1,x1/11,s13,x10/15,pa/o,x0/1,s13,x5/12,s10,x14/4,pf/j,x5/12,pi/k,x0/3,s12,x10/9,s4,x2/6,pl/f,s7,x11/5,s6,x8/7,pc/k,x0/2,pi/g,x3/9,pd/l,x2/7,pg/c,x6/8,s14,x13/9,pb/o,x4/8,s12,x1/10,s13,x4/13,ph/d,x11/1,pk/m,x9/3,pe/p,x12/4,s13,x13/6,s14,x12/14,s10,x2/1,pb/c,s6,x12/4,s3,x1/2,s8,x3/9,s3,x8/2,s13,x12/1,pa/e,x9/15,pi/j,x11/8,s2,x6/1,s10,x12/5,s15,x8/2,pf/e,x12/4,pb/c,x15/6,s11,x13/11,pl/p,x1/14,s15,x8/3,s9,x10/1,s13,x11/7,s4,x9/2,s6,x8/10,s4,x4/15,pa/n,s15,x1/3,s1,x7/13,s9,x4/9,s10,x11/14,s8,x2/3,ph/k,x13/7,s4,x4/14,s1,x15/13,pj/o,x10/7,s14,x8/6,s13,x14/1,pe/d,x11/12,s14,x9/8,pj/h,x6/13,pm/d,x3/4,s14,pi/o,x1/5,pg/e,x14/3,s6,x2/15,s10,x14/13,s14,pi/a,x11/12,s6,x13/6,pl/j,x15/8,s2,pe/h,x0/10,s15,x14/2,pb/d,x4/6,s2,x5/14,s6,pg/o,s12,x10/13,pe/d,x14/15,s3,x9/1,pg/l,x2/4,s15,x3/10,pp/h,x5/2,s9,x14/0,pg/d,x15/5,s5,x9/11,s15,x1/13,pc/i,x5/15,s6,ph/g,x7/11,s9,x5/13,s15,x2/15,s2,x3/14,pk/o,x4/5,pj/l,x2/1,s15,x11/14,pp/f,x15/13,s4,x8/11,s4,pa/j,s15,x13/10,s15,x7/1,s1,x15/6,pb/c,x5/3,pi/h,x13/12,pg/e,s2,x5/15,pc/b,x4/13,pe/f,x15/2,pd/l,x6/14,s15,x1/13,ph/b,x15/10,s11,pp/a,x5/8,ph/d,x11/9,s15,x5/13,pn/j,s1,x3/7,s9,x9/12,s2,pk/m,x8/2,s6,x12/4,s2,x5/14,pf/b,x15/7,s9,x3/6,pj/e,s4,x1/13,pg/m,x7/12,s12,x8/15,pp/l,x10/13,s6,x12/5,s12,x4/0,pm/n,x10/8,pa/k,x14/9,pp/j,x15/7,ph/d,x11/6,s13,x13/12,s13,x14/15,s8,x4/8,s12,x13/3,s8,x10/9,s2,x7/8,s8,x14/2,s11,x10/11,pc/n,x4/13,pl/j,x5/15,pn/a,x12/0,s10,x8/11,pd/h,x1/15,s9,x0/8,pe/n,x14/12,s15,pa/h,x2/13,s7,x7/9,pg/m,x1/8,s13,x0/5,s8,x15/8,pd/n,x3/12,pm/o,x13/10,s11,x7/3,s12,x12/4,s14,x3/7,s13,x9/1,pk/b,x11/0,s11,pp/e,x4/8,pm/f,x14/5,s14,x4/10,s11,x11/12,s6,x13/2,s4,x10/0,s5,x7/4,s14,x15/1,s12,x2/12,s3,x9/13,s10,x12/3,pb/e,x8/7,pa/m,x10/6,pk/f,x14/7,pg/b,x0/12,s6,x7/3,s14,x8/2,s9,x7/3,s10,x2/6,pp/h,s4,x8/4,pi/f,x3/6,s5,x7/8,pk/l,x12/1,pi/g,s4,x3/7,s13,x2/13,pd/e,s2,x1/0,s8,x6/3,s3,x4/7,s2,x12/13,s4,x7/11,s3,x12/2,s1,x8/13,pk/m,x2/15,s12,x8/0,s4,x14/12,pb/p,x5/8,s11,x14/12,ph/f,x0/2,pe/n,x8/4,s3,x5/2,s10,x8/9,s5,x13/7,po/l,x8/11,pm/h,x1/9,s8,x14/4,s3,x2/6,s5,pk/f,x15/0,ph/g,s12,x12/1,s7,x14/11,pb/a,x12/8,s11,x4/6,s6,x8/9,s3,x2/1,pn/j,x0/9,s6,x15/5,pc/o,x12/4,pi/a,x13/8,pn/p,x7/9,s4,x6/15,pd/f,s2,x5/9,s4,x3/15,s10,ph/o,x0/12,pn/e,x13/14,s15,x4/12,pf/g,x11/0,s14,x15/9,s1,x1/12,pl/k,s13,x14/8,pp/j,x12/5,pl/f,x7/1,s11,x11/9,s9,x8/6,pb/m,s12,x9/2,s13,x7/1,pf/i,x13/11,pg/j,x10/1,s1,x0/14,pi/p,x5/12,s3,x15/3,s8,x13/8,pf/n,x3/4,s12,x10/8,pp/g,x2/11,s6,pa/c,s10,x1/8,pd/m,x6/12,ph/l,x1/11,pd/p,x12/15,s9,x3/2,s14,x7/6,s13,x10/12,s5,x3/6,s9,pb/n,x5/9,s3,x12/13,s8,x11/0,pc/f,x7/14,pa/m,x11/13,s10,x5/14,s4,x2/11,s4,x14/1,s7,x13/8,s5,x12/5,s13,x0/10,s1,x13/4,s9,x11/14,pj/c,x0/10,s3,x1/5,po/b,x13/11,s4,x5/3,s1,x1/6,pk/m,x13/3,s14,x0/5,pj/h,x14/13,s8,x11/5,s11,x8/12,pp/g,x3/2,pl/m,x5/11,s12,x9/10,s1,x1/13,s11,x3/7,pa/p,x2/4,pn/e,x10/9,s4,x1/6,s11,x3/8,s11,x10/5,s1,x8/11,s14,x4/0,s11,x5/8,pf/c,x4/2,pd/m,x12/6,s3,x8/2,s13,pf/l,x6/13,s11,x5/15,pi/e,x6/10,pb/l,x9/5,s14,pe/o,x10/6,pg/d,x11/8,pn/m,x1/2,pf/c,x4/9,pk/m,x5/15,s1,x12/11,pn/i,x14/6,s13,x0/5,s14,x6/8,s4,x12/0,pe/m,x10/15,pc/p,x3/8,pn/e,x11/0,s14,x7/13,s5,x10/14,pa/o,x3/13,s5,x11/10,pf/m,s11,x5/3,s9,x4/8,s9,x3/1,pp/l,x0/4,pc/j,x13/7,s5,x4/2,pa/d,x1/6,pc/l,s13,x7/4,s12,x3/10,pk/a,x14/7,s7,x11/5,s12,pe/j,x13/14,s2,x7/11,s4,x6/10,s10,x5/8,pn/h,x0/2,pb/j,x12/4,po/a,x5/7,pd/l,x0/15,s10,x1/6,s9,pj/h,x2/12,pf/o,x7/13,s11,x14/11,pi/m,x1/15,pf/j,x13/3,pl/k,x2/8,s3,x5/3,s11,pg/f,x13/4,s15,x3/1,pl/h,x12/15,pj/b,s13,x9/2,pl/o,x5/4,pi/f,s9,x2/3,s3,x0/13,s12,x4/12,ph/o,x3/11,pa/p,x7/14,s6,pd/b,s8,x6/0,pp/g,x15/10,pm/l,x6/8,pd/o,x7/12,s7,x8/10,s6,x2/5,s1,x0/10,s8,x5/2,s2,pl/k,x12/14,s14,x15/11,s13,x3/7,ph/n,x9/15,s13,x7/13,pl/m,x9/10,s9,x1/0,s4,x8/2,pk/b,x10/15,s15,x6/14,s8,x13/11,s9,x6/9,pl/m,x1/8,ph/a,x9/2,s6,x5/12,pm/i,x10/6,pd/n,x5/14,s4,x4/15,pa/p,x3/9,s6,x12/5,po/m,x13/0,pf/g,x15/5,s13,pa/c,x8/10,pd/f,x2/14,s13,x11/3,pa/c,x7/0,s15,x4/5,s5,x3/12,s13,x10/8,s14,x5/11,s12,x1/9,s12,x3/2,pe/b,x6/5,s5,x2/8,s11,x7/10,po/k,x4/8,pc/a,s4,x12/11,pj/b,x4/3,s13,x5/0,pk/e,x15/11,pp/f,x10/6,pe/c,x11/8,s3,x9/5,pn/i,s14,x6/10,pp/g,s9,x5/8,po/h,x13/10,s1,x11/2,s6,x9/7,s4,x6/11,s8,x0/15,s12,x14/4,s1,x6/8,pp/m,x9/10,s10,x3/5,s1,x1/13,s8,x0/14,pa/g,s9,x8/1,s1,x4/13,s5,x9/7,pd/f,x6/12,pp/c,x11/5,pb/k,x0/14,ph/m,x4/5,s7,x0/7,pe/p,x10/5,s4,x9/11,s7,pf/m,x13/14,ph/d,x15/7,s2,pc/b,x14/13,pk/g,x3/5,pa/o,x11/2,pg/k,x3/0,pf/a,x1/13,pm/l,x11/4,s13,x13/3,pn/k,x1/5,pc/o,x4/15,s10,pd/h,x1/14,s9,x6/7,pl/f,x13/8,s3,x4/0,pc/m,x3/1,pk/f,s2,x15/14,s9,x5/6,s1,x12/0,pl/c,x7/10,s5,x4/15,pb/m,x8/11,pg/k,x13/3,s5,x12/9,pe/n,s5,x5/2,pl/m,x4/15,pb/i,x1/13,pl/d,x15/12,po/m,x10/14,s10,x0/15,pk/p,x4/8,s12,x10/13,ph/g,x0/1,s11,x4/2,s15,x1/8,pf/b,x6/13,s1,x2/15,po/l,x12/9,s15,x13/6,s5,x14/8,s10,x0/11,pc/g,x12/4,ph/i,x9/5,pk/o,x13/15,pb/m,x11/5,s6,x0/7,pe/c,x6/3,s13,x14/4,ph/b,x9/6,pa/d,x3/4,po/i,x13/14,pl/m,x2/0,s7,x7/12,s5,x4/14,s5,ph/p,x11/7,s13,x9/1,s15,x3/15,s1,x8/6,pa/e,x1/11,s3,pb/c,x5/13,pn/o,x0/12,pb/g,x13/6,po/f,s9,x5/3,s12,x11/10,pb/j,x8/2,pd/g,x5/15,po/f,x8/12,pl/i,x1/9,pb/c,x5/11,s6,x4/2,s14,x0/3,s10,x4/1,s5,x11/13,pi/k,x3/8,s12,x12/5,s5,x13/6,ph/f,x4/7,s15,x2/6,pa/p,x1/12,s15,x7/0,pl/o,x5/4,ph/g,x10/9,s3,x1/8,s15,x10/11,pk/i,x9/14,s9,x0/6,s11,x14/4,s12,pl/a,x5/8,pi/b,x11/3,s10,x6/4,pf/o,x13/7,pb/m,x10/0,pg/k,x7/13,s1,x11/5,s4,x0/13,s5,x4/5,s5,x6/13,pn/h,x9/4,pd/e,x2/11,ph/o,x14/13,pn/d,x4/5,s7,x12/7,pa/p,x15/5,s3,x14/9,s10,x5/6,pj/o,x11/4,pi/a,s1,x2/12,pj/c,x4/14,s11,x8/13,pf/i,x2/9,s1,pn/o,x0/15,pp/i,x5/6,s5,x7/4,s13,pd/k,x15/12,s13,x0/14,ph/j,x15/12,s15,x6/11,s7,x10/1,s1,x4/3,s15,x0/9,s7,x2/15,pb/p,x14/7,s7,x4/12,pa/g,x6/7,s15,x14/11,s15,x7/13,s9,x9/2,pf/p,x6/10,s3,x0/7,ph/l,x1/8,s15,x0/6,s7,x14/15,s15,x7/9,pe/n,x5/15,s10,x10/11,s7,x7/5,s6,x0/4,pm/g,x7/1,s5,x5/9,s10,x10/15,s10,pj/o,x4/6,pg/b,x9/13,s11,x6/5,s4,pn/o,x15/10,s13,pb/f,s15,x14/3,s9,x4/5,s15,x11/8,s6,x1/4,s1,x3/12,s12,x14/0,pc/d,x11/4,s3,x6/12,s2,x8/9,s1,x12/4,s9,pb/m,x7/5,pf/c,x0/3,s11,x9/10,pm/o,x14/4,pe/c,s1,x15/10,pf/j,x13/5,s9,x1/12,pg/p,x0/15,ph/b,x11/1,pd/e,s8,x14/7,pb/p,s3,x11/9,s8,x8/6,po/a,x13/11,s1,x6/0,s7,x3/13,s15,x12/15,s7,x11/0,pm/b,x1/12,s11,x6/8,pg/l,x13/9,ph/c,x11/10,s9,x8/0,s15,x13/14,pp/f,x3/1,s14,x5/2,s9,x9/15,s9,x11/14,pg/k,x7/4,s4,x8/14,s3,x7/13,pe/n,x11/6,s15,x7/10,pa/m,x9/5,pj/e,x4/12,s13,x10/11,pa/m,s14,pf/k,x1/2,s9,x4/9,pg/j,x0/3,s2,x15/4,s6,pf/a,x9/7,s15,x14/5,pd/p,x4/7,pn/i,x1/10,s15,x7/13,s15,x15/10,ph/e,s1,x3/5,s10,x4/15,s7,x14/1,s8,x12/10,s15,x0/4,pi/n,x6/9,s2,x1/0,pd/o,x8/3,s2,x12/15,pk/h,s13,x10/6,pm/n,x15/2,pc/b,x6/9,s8,x7/13,s12,x2/4,pi/o,s2,x7/12,s13,x9/2,pd/p,x4/8,pk/l,s12,pj/o,x5/1,s12,x4/6,s11,ph/d,x14/9,s8,pb/e,x13/7,pi/f,x12/1,s7,x6/14,pe/j,x15/10,s11,x0/2,pg/d,x12/11,pp/b,x14/15,s5,x2/11,s4,x15/8,pm/e,x10/11,pa/d,x4/9,s11,x14/15,pj/b,x8/2,s3,x5/1,pc/f,x11/3,s8,pg/l,x2/9,po/h,x12/14,s4,x2/0,pe/l,x14/8,s9,x3/1,pn/i,x10/12,s6,x15/2,pm/p,x0/4,pa/c,x9/15,s10,ph/j,x14/1,pn/o,x10/13,s13,x7/11,s14,x15/10,s13,x0/6,s14,x7/2,pa/i,x13/3,s15,x8/1,s13,x11/12,s14,x8/10,s7,pk/p,x4/6,s2,pi/b,x8/10,s6,x5/6,s9,x4/7,pc/k,x13/1,s6,x5/12,s12,x1/0,s8,x3/2,s4,x9/5,s1,x1/8,s9,x0/5,po/i,x11/10,pp/f,x7/3,pe/j,x2/12,s1,x9/4,s7,x1/5,s6,x9/8,s12,x14/10,s10,x7/5,s10,x3/10,pm/k,x1/2,pn/i,x14/7,s9,x2/4,pf/g,x7/8,pb/h,x14/12,pk/m,x6/8,pc/f,x13/5,s8,x14/6,s3,x4/13,s3,x5/7,s1,x11/14,s3,x15/7,pa/p,s11,x11/1,s12,x9/14,s2,x10/12,po/l,x13/9,pp/m,x0/8,pi/d,x5/10,s9,x13/11,pe/k,x5/15,s10,x12/6,s15,x8/15,s4,x12/6,po/i,x13/2,pg/a,x10/5,s2,x0/6,pi/p,x3/9,pg/k,x14/5,s12,x10/7,s14,x3/9,s4,x15/4,ph/n,x13/0,s8,x10/7,pl/j,x14/11,pm/k,x12/5,ph/f,x15/13,s1,x0/5,pk/g,x3/8,ph/l,x1/2,s1,x15/5,pk/c,x8/14,s10,x2/15,s12,x10/9,s3,x3/7,s3,pl/a,s11,x8/11,s15,x1/6,s10,x7/13,po/m,s12,x11/3,ph/j,x4/2,pf/m,x14/1,pg/h,x6/12,s6,x5/7,pl/c,x1/13,s5,x5/3,s2,x8/13,pm/o,x0/2,pd/n,x5/4,pp/g,s9,x9/8,s4,x7/4,s11,x15/6,po/m,x1/10,pc/i,s15,x4/6,s3,x9/7,pa/m,s9,x0/13,s11,x2/1,s14,x15/0,s8,x11/6,s4,x9/10,pn/k,s6,x4/14,po/p,x10/15,s9,x4/12,pm/b,x9/7,s13,x1/0,s8,x2/8,s1,x7/5,s8,x8/10,s12,x5/1,s14,x13/2,pd/n,x4/8,pe/j,x3/15,pc/l,x12/6,pi/n,x13/2,pj/d,x8/3,s15,pa/m,x11/10,s11,x8/15,pf/g,x4/0,pd/h,x8/3,pg/j,x6/10,po/h,x3/11,s10,x4/15,s9,x11/1,s6,x8/9,pp/e,x4/11,pd/b,x5/3,s7,x8/14,s14,x5/2,s9,x1/13,po/k,x11/3,pg/a,x12/8,pi/d,x6/11,pn/b,x5/3,s11,x0/6,s9,pc/a,x4/1,pb/p,x9/8,s10,x2/3,s9,pk/a,x4/7,s9,x2/13,s8,x1/11,s7,x3/13,s13,x1/0,s13,x9/15,s5,x8/0,pm/i,s9,x6/12,pb/n,x7/4,pc/d,x6/9,pn/p,s3,x4/14,s4,x10/1,pa/o,s12,x2/14,s4,x6/12,s4,x4/2,pn/d,x15/8,s10,pk/i,x10/7,s4,pb/a,x14/9,s3,x13/11,s12,x12/0,s10,x11/7,s4,x0/4,pl/g,x2/5,s7,x8/10,s1,pn/k,s9,x9/2,s2,x4/6,s9,x8/10,pc/a,s9,x11/7,po/k,x6/4,pj/f,x3/12,s12,x2/10,pp/c,x5/14,s3,pk/e,x3/8,s9,x4/6,s10,x5/10,pg/o,x0/1,pa/l,s11,x3/7,s6,x13/14,s10,x8/12,pk/j,x0/1,pl/d,x3/12,s10,x10/11,s9,x7/15,s9,x3/4,pi/b,x15/0,pm/g,x4/1,s4,x0/15,po/p,s5,x2/6,s9,x13/12,pa/m,x10/14,pb/j,s14,x12/8,pk/n,x3/5,pj/p,x13/14,pi/n,x1/8,pg/l,s13,x5/9,po/j,x3/14,s12,x2/1,pc/l,x9/4,s5,x13/6,ph/f,x5/15,s9,pj/b,x12/10,pg/f,x1/15,pb/a,x5/12,ph/m,x13/3,s15,x11/8,s5,pb/e,x9/7,pa/j,s14,x13/15,s13,x8/10,s2,x14/4,pe/o,x9/12,s13,x8/1,s8,x15/11,s5,x8/5,s13,x14/12,s8,x7/5,s6,x15/9,ph/p,x14/8,s1,x10/13,s10,x8/2,s2,x15/7,pg/f,x0/11,s2,x8/14,s8,x1/13,pd/k,x14/6,s8,x11/10,s6,x0/4,pg/a,x6/14,s4,x5/10,s15,x7/2,pp/m,x9/3,pk/i,x12/15,s15,x6/11,s5,x10/3,s5,x13/6,s10,x0/10,s14,x9/1,pe/c,x11/3,pn/p,s3,x7/13,s8,x6/14,s14,x3/2,ph/a,x13/0,s14,x12/5,s7,x10/13,s11,pg/k,x8/6,s14,pd/c,x4/9,pp/o,x7/13,s12,x12/15,s10,x5/3,pa/j,x7/9,s15,x3/4,s10,x0/7,pn/g,x9/10,pe/b,x15/3,s6,x5/7,s8,x9/1,s7,x3/15,pp/l,x5/1,pj/h,x8/3,s14,pg/o,x0/10,pm/c,x1/3,s5,pl/p,x11/9,s15,x12/14,pk/f,x11/1,pc/a,x2/4,s5,x7/11,ph/d,x9/2,s6,x1/10,s6,x7/3,s10,x10/5,s14,x0/11,po/f,x8/10,s8,pe/c,x3/14,s12,x15/8,po/k,x2/7,s4,x9/13,s6,ph/i,x3/12,s5,x2/10,s11,x0/13,pc/j,x7/3,s11,x6/14,s11,x13/4,s5,x12/15,s8,x10/6,s6,x3/1,s14,x14/8,s13,pn/f,s1,x13/2,s9,x0/14,s3,x6/10,s7,x13/2,s11,x11/0,s12,x9/13,s11,x7/8,s15,x15/0,s2,x8/5,pi/a,x14/10,ph/b,s2,x1/9,s15,pp/g,x13/14,pj/e,x9/12,pc/l,s4,x5/7,s15,x11/2,ph/j,x7/8,pn/o,x2/0,pc/a,x8/9,pd/e,x14/0,s6,x15/2,s4,x4/3,s14,x9/8,s12,x7/11,s12,pc/n,x6/5,po/l,x7/14,s8,x8/4,s10,x13/9,pc/i,x7/12,pd/j,x4/15,s6,po/h,x13/1,s3,x11/8,s5,x15/0,pg/c,x3/11,s15,x14/0,pj/i,x2/7,pp/f,s4,x9/11,s8,x8/10,s8,x7/13,s15,x0/4,pb/l,s4,x3/9,ph/m,s14,x4/13,s14,x14/0,pp/d,x4/5,s13,x12/1,ph/e,x15/7,s14,x13/2,pa/g,x12/9,pc/f,x0/5,s2,x8/3,pp/h,x4/12,s15,x5/2,s15,x11/4,pb/o,x8/12,pd/m,x1/6,s15,x11/9,s5,x10/1,pa/o,x8/3,s7,x9/2,s4,x7/14,pk/d,x12/3,pg/n,x7/9,s10,x0/12,s15,x15/4,s5,x14/2,s6,x4/7,s1,x14/1,pd/e,x2/11,s12,x7/5,s4,x1/15,s14,x0/10,s7,x12/15,pb/m,x2/3,po/j,x7/1,pd/h,s6,x11/15,pb/f,x6/7,pm/d,x9/15,s3,pj/e,x13/7,s15,x8/14,s1,x2/5,ph/p,x12/11,pa/c,x3/5,pg/f,x10/6,pa/k,s8,x2/8,s5,pb/o,x14/15,s6,x12/13,pn/l,x1/10,s7,x3/12,s10,x5/8,pj/h,s1,pm/o,x13/6,s6,x5/14,s6,x8/7,s5,x13/6,pa/d,s11,x1/7,pl/h,x14/6,pb/k,s7,x10/2,s12,x8/5,s5,x14/15,pl/j,x9/11,pi/p,x5/14,pl/k,x10/9,s12,x5/7,pj/p,s13,pn/l,x0/11,s4,x6/10,pm/e,x2/5,pk/p,x6/9,s15,x14/2,s14,x9/4,pm/n,x6/11,s4,x4/8,po/d,x10/15,s11,x9/13,pg/m,x2/1,s4,pb/a,x15/4,s8,x5/3,pm/h,x0/12,s4,x15/4,pc/e,x0/11,pb/g,x9/6,pm/e,x14/3,pb/c,x8/2,pa/n,s4,pb/p,x7/10,pc/m,x12/6,s13,x5/8,pa/l,x10/3,pp/f,x9/15,s1,x10/2,s15,x9/12,pc/i,x4/11,pb/j,x14/13,s13,x2/1,s10,x5/8,pf/e,s10,x7/14,pl/p,x8/1,s8,x10/9,s3,x8/4,pj/d,s4,pf/h,x2/14,pa/g,s11,x13/1,s5,x9/3,s10,x15/12,pk/o,x13/6,s11,x1/9,s12,x4/14,s2,x11/10,pa/e,s1,x9/14,s14,x4/10,s4,x9/8,s8,pm/p,x12/14,s5,po/k,s14,x6/15,pl/d,x0/8,s12,x2/10,pn/b,x1/7,s8,x12/10,pf/o,x0/7,pl/i,x13/4,s2,x0/2,pd/e,x1/14,s1,pn/k,x8/10,s9,x4/9,s6,x1/5,s5,x7/12,s7,x11/8,pp/h,x9/1,pk/o,x7/0,pc/b,x2/9,s7,x6/15,pp/o,x9/11,pl/f,x3/6,s14,pn/m,x5/9,s2,x13/11,pd/p,x8/10,s1,x3/15,s13,x10/5,pe/g,s4,x11/4,pa/d,x6/14,s13,x7/9,s13,x1/8,pc/g,s2,x2/14,s8,x10/4,pn/o,x7/6,s12,x15/0,pc/l,x3/1,pd/b,x15/7,pp/j,x14/11,s1,x3/15,s7,x14/8,pi/d,x10/11,pb/f,x2/6,pg/l,s11,x0/9,s14,x1/14,s4,x11/10,pe/n,x12/13,pl/m,x9/2,s2,pi/e,x14/3,s6,x15/1,s9,x14/4,s7,x8/7,s13,x1/11,po/f,x6/10,s2,x1/5,s10,x6/3,s14,x9/8,pc/g,x4/1,pm/b,x8/0,pn/a,x2/12,pj/l,x10/5,pc/n,x14/6,pk/m,x8/11,s2,x2/1,pf/e,s14,x14/8,s5,x15/5,pa/d,x6/10,pf/e,s8,x3/2,s13,x0/5,pk/o,x1/3,pc/p,x0/15,s10,x1/2,s9,x3/15,s10,x12/10,s3,x8/11,s5,x0/14,s4,x7/3,s8,x0/9,s1,x14/1,ph/n,s4,x2/10,s15,x4/11,s4,x14/12,s3,x13/7,s4,x11/8,pe/m,x10/14,s9,x5/0,pj/a,x12/9,s7,x4/8,s7,x11/7,pg/c,x3/1,s12,x15/4,s3,x6/1,s14,x9/2,pb/n,x6/7,s10,x8/3,s2,x10/7,s5,x11/3,s7,pf/i,x7/8,s3,x9/15,s6,x13/7,s11,x14/6,s2,x5/4,pn/k,s11,x6/13,s13,x12/2,s12,x4/15,ph/m,x8/9,s7,x10/7,s13,po/j,x4/12,s4,x8/15,s14,x6/14,s11,pm/e,s2,x11/13,pn/f,x15/10,pm/p,s1,x14/13,pe/b,x10/2,s15,x1/15,pl/c,s6,x14/7,s9,x10/1,pk/o,x9/14,s13,x11/0,s7,x2/8,pn/p,x6/12,s10,x11/13,s7,x3/2,pc/g,x12/10,s1,x4/11,pb/j,s9,x12/9,s2,x13/4,s10,x6/11,s8,pg/i,x12/7,s6,x0/6,pb/e,x12/10,s9,x5/6,s8,po/j,x12/9,s2,x6/11,s2,x1/14,s12,x7/12,s13,pc/h,x9/2,s10,x5/10,s12,pa/e,x0/11,s8,x1/9,s7,x10/3,pk/h,x1/13,pa/l,x5/2,s2,x0/12,s15,x4/8,s2,x10/2,pg/i,x14/0,s3,x4/1,s10,x5/12,s9,x7/11,s10,x8/12,po/p,x13/6,pg/f,x2/14,pd/l,s1,x4/8,s1,x3/2,pc/i,x12/14,s10,x3/0,ph/d,x4/2,pf/b,x0/6,s14,x5/4,pi/e,x2/12,pb/h,x5/1,s3,x10/4,pd/k,x13/0,s12,x1/10,po/a,s12,x12/6,s4,x13/2,s7,x6/0,s8,x8/14,s8,x1/9,s6,x8/5,s13,pn/b,x9/0,pp/g,x8/13,s10,pl/j,x2/0,s1,x14/11,s10,x4/6,s6,x9/8,pp/i,x1/7,pa/f,x3/15,s10,x8/9,pd/k,x4/3,pa/j,x9/2,pc/b,x8/14,s3,x0/5,s9,pp/h,x15/10,pm/n,x13/6,pd/i,x2/11,s1,x12/3,s11,x6/10,s2,x9/7,pe/h,x1/5,s5,x7/9,pc/b,x14/3,pi/g,x6/2,po/m,x15/13,s2,x0/5,ph/l,x4/6,s9,x14/15,s10,x7/10,s7,x13/8,s13,x5/3,s10,x2/14,pb/i,x12/8,s8,x13/5,pa/n,x7/9,po/c,x5/0,s7,x15/13,s9,x10/5,s12,x9/13,pp/n,x14/2,pl/e,x10/11,s6,x13/3,s6,pb/c,x4/7,po/p,x1/9,pc/n,x5/12,s12,x8/0,s8,x11/2,pk/o,x6/8,s9,x4/9,pp/m,x0/8,pf/k,x1/6,s13,x2/14,ph/p,x11/8,s1,x3/4,s12,pe/f,s9,x13/10,pn/a,x14/7,s9,x8/0,s6,x6/15,s15,x11/4,s5,x15/8,s8,x13/11,s15,x3/12,s9,x10/8,ph/e,x9/0,s14,x13/5,s3,pn/d,x12/4,s10,x3/11,pk/j,x6/15,pf/c,x0/5,s8,x15/10,s3,x12/0,s11,x4/5,pl/e,x13/12,s12,x11/3,s12,x6/0,pa/f,x15/1,s15,x3/8,pn/c,s15,pi/l,x6/2,pd/c,x12/10,s15,x9/1,s4,x0/14,pa/o,x12/11,pn/i,x2/6,pg/l,x3/9,pa/h,s11,x11/14,s7,x10/13,s15,x9/6,pp/e,x4/13,s12,x9/14,s4,x2/0,s14,x6/13,pm/c,x11/12,s7,x0/2,s3,pp/f,x10/11,pn/e,s10,x12/13,s9,x5/9,s14,x1/0,po/c,x14/9,pl/b,x8/7,pc/a,x14/4,s15,x9/6,s13,x14/0,pf/n,x8/2,pp/a,x10/13,s3,x3/6,ph/g,x4/12,pl/o,x1/6,s2,x9/5,s6,x6/3,s3,x5/11,s9,x1/12,s14,x4/6,s7,x12/7,s6,x11/4,pi/g,s13,x10/3,s8,x5/6,pp/f,s14,pl/j,s7,x15/9,s7,po/g,x8/5,s12,x4/1,pd/p,s4,x15/11,s2,pc/g,x8/2,s8,x13/0,ph/k,x11/6,s9,x9/10,pg/a,x6/5,pf/c,x4/15,s2,x1/11,s9,x3/6,s8,x10/12,s1,x7/11,s5,x12/0,s10,x7/4,s14,x1/10,pl/a,x5/7,pn/j,x12/6,pa/i,x5/1,s5,x4/15,pc/b,x5/14,pf/m,x15/4,s4,x7/9,pd/o,x3/13,pf/a,s12,x0/10,pg/j,x7/8,s10,x6/15,s13,x8/10,ph/c,x7/9,s12,x14/10,pl/m,x12/9,pe/k,x4/6,s8,x13/11,s4,x1/8,s8,x6/5,pb/h,x14/15,s4,x1/8,s2,x5/2,pg/l,x0/12,pf/m,x14/1,pi/h,x11/5,s9,x12/6,pa/p,x4/13,s11,x8/11,s2,x6/13,s3,x5/15,s4,x9/10,s4,x11/5,s15,x15/12,s12,pj/f,x0/11,pg/i,x7/2,s1,x10/6,pb/h,x8/0,po/k,x5/10,s5,x15/9,s7,x8/6,s6,x11/7,pi/l,s12,x14/13,s4,x1/0,s2,pf/o,x9/14,s10,x5/1,s12,x6/12,s3,ph/j,x13/3,s5,x8/12,po/a,s11,x15/3,s9,x1/8,pc/i,x5/7,s11,x4/11,s1,x9/3,ph/f,x10/11,s8,x6/7,s12,x9/12,pj/m,x15/6,pf/i,x9/7,s9,x1/6,pl/a,s14,x10/3,s7,x4/15,s8,x7/2,pp/g,x6/4,pk/d,x11/2,pa/h,x13/10,s5,x6/7,pe/c,x4/3,s8,x9/6,s10,x15/8,pa/h,x5/2,po/k,x9/12,s5,x11/6,pj/d,x3/9,pa/i,x14/0,pc/d,x12/10,po/b,x8/2,pg/h,x3/7,s4,x5/4,pk/m,x10/14,s4,x5/13,s1,x1/14,s10,x15/10,pb/o,x9/13,s5,x15/7,s4,x2/13,s7,x5/15,s3,x14/6,s12,x5/12,s5,x9/14,pi/a,x13/11,s9,x3/10,s11,x9/14,s1,x10/11,s8,x2/15,s10,x8/0,s7,x5/1,s8,x8/12,s5,x15/4,s4,x3/0,s10,x1/5,s1,x11/0,pf/m,x1/6,pl/h,x9/11,s2,x0/12,s6,x9/3,s13,x4/5,pc/i,x2/14,s12,pe/j,s5,x15/8,s14,x10/2,s8,x12/11,s15,x1/6,s15,x10/7,s11,x15/13,pi/c,x14/8,pe/m,s14,x15/7,pk/j,x4/12,s3,x14/11,pd/h,x3/1,s15,x5/2,pi/p,x14/13,s1,x7/0,ph/j,x1/2,s6,x13/12,pn/p,x1/14,s6,x10/4,s13,x15/1,s12,x11/3,s10,x8/6,s9,x3/7,pg/f,x9/6,pa/e,x13/10,pc/j,x8/12,pp/n,x11/0,s14,x5/6,s3,pb/d,x2/0,s6,x11/9,pf/m,x13/7,s12,x15/12,s12,x10/3,s15,x11/2,s15,x12/13,s11,x0/14,s10,x8/15,s4,x13/2,s15,x7/12,pa/d,x1/10,pb/j,x5/9,s1,x4/11,pa/o,x2/10,pg/f,x0/5,s14,x8/14,pd/o,x10/13,pc/e,x2/6,pj/p,x5/7,s8,x15/1,s8,x12/4,pb/a,x5/10,s3,x9/7,s14,x1/12,s11,x4/9,pk/i,x14/7,s7,x6/10,s15,x14/1,pp/o,s13,x9/15,pe/n,x3/2,s9,x13/4,s10,x8/5,pk/o,x2/11,s3,x0/10,pm/n,x12/14,pe/a,x11/0,s10,x10/7,s9,x11/8,pi/d,x13/1,pe/p,x2/0,pk/l,x9/1,pf/n,x2/0,pa/p,x14/8,s7,x15/2,s7,x11/13,s8,x5/10,s7,x15/2,s2,x4/8,s13,x1/12,s1,x11/5,s9,pl/m,x2/9,s3,x5/11,pf/j,x1/13,s14,x8/0,pe/n,s10,x6/13,pb/o,x8/15,s11,x11/7,s10,x8/4,pi/g,x12/13,pj/a,s6,x0/3,pf/b,x14/6,s11,x13/7,pl/g,x4/9,s7,x8/7,pj/h,x0/15,s15,x9/2,s14,x11/12,pm/n,x1/14,s12,x5/13,s10,x9/10,pa/c,x12/6,s15,x2/13,s4,x12/15,s7,pg/b,x1/9,pc/o,x12/4,s12,x15/14,s7,x3/6,pa/l,x8/14,pp/h,x12/10,po/a,x8/0,s3,x1/10,s3,x3/8,pg/j,x2/7,s9,x11/14,s10,pn/i,x2/6,po/a,x14/10,s13,x15/4,pe/k,x2/6,s7,x1/8,pi/b,x13/15,s11,x12/10,pl/j,x9/3,ph/k,x2/14,s5,x4/3,pl/n,x15/1,pe/o,x13/9,s6,x7/6,s15,x8/10,s13,x4/12,s8,x5/15,s6,x13/11,pi/n,x1/6,s15,x0/3,s10,x14/11,s8,x8/3,s11,x2/7,pc/p,x10/14,pm/g,x3/13,s2,x15/5,pi/l,x3/0,s13,x11/6,s11,x7/14,s5,x10/8,s10,ph/n,x3/15,s3,x1/0,s12,po/f,x6/15,s6,x1/5,s5,x11/2,s12,ph/g,s1,pn/c,x15/13,s10,x11/10,s1,x15/5,ph/o,x11/1,s4,x3/8,s6,x6/4,s8,x2/15,pk/m,x5/8,pp/b,x3/11,s5,x12/5,s15,x7/2,pl/m,x5/10,s12,pg/i,x9/13,s11,x4/0,s10,x7/14,pf/p,x0/9,s11,x4/8,s8,x11/15,s15,x5/4,pj/e,x8/3,pd/f,x1/10,pe/o,x6/5,pb/d,x11/4,s6,x14/6,pa/p,x7/9,pg/c,x1/5,pd/k,s5,x3/15,s11,x2/6,s12,x8/4,s8,x12/3,s15,x8/15,s1,x12/1,s10,x2/15,s6,x8/5,s12,pi/f,x12/11,s5,x14/4,pp/l,x15/7,s2,x13/14,s5,x1/11,s9,pk/m,s6,x0/7,s4,x13/3,s6,pp/d,x9/10,pj/b,x3/1,s7,x11/13,pe/i,x15/10,s2,x0/8,s2,x15/12,s12,x4/0,s3,x1/8,s1,x12/7,pf/a,x6/15,s2,x11/13,pp/d,x9/6,ph/c,x8/15,pi/a,x5/2,pg/h,x12/8,pc/p,x13/3,s7,x9/12,pm/d,x5/14,pa/j,s13,x15/10,s3,x2/7,pc/e,x11/13,s3,x10/7,s2,x15/12,s12,x0/11,s4,x5/6,s12,x2/11,s10,x3/4,s10,x11/10,ph/a,x6/8,s9,x4/0,s10,x6/3,s14,x2/8,s2,x13/1,s14,x4/2,s14,x13/15,pd/o,x3/0,s7,x13/14,s13,x3/8,pe/i,x7/4,po/g,x1/10,pl/j,x12/6,s14,pb/h,s4,x9/13,pj/f,x7/10,s11,x6/15,s8,x1/9,pg/b,x0/6,s1,pc/o,x11/9,s4,x2/15,s13,x12/3,s2,pd/l,x6/5,s10,x4/9,s10,x11/5,s15,x0/13,s11,x1/4,s10,x9/3,s7,ph/i,x13/14,pk/o,s6,ph/f,x15/9,s12,pm/j,x10/11,pg/a,s10,x8/9,s5,x7/13,s7,x5/4,s7,x13/12,s15,x5/8,s2,x1/7,pj/k,x11/15,pe/a,x3/13,po/b,x6/7,pp/n,x12/2,s3,x7/0,pd/c,x6/13,s2,x15/2,pg/o,x6/8,ph/p,x12/4,s9,x9/6,pc/l,x5/0,pe/f,s10,x9/4,s5,x3/6,pa/l,x9/1,s14,x8/3,s5,x4/15,s14,x7/8,s7,x14/12,s8,pk/i,x10/7,pf/l,x12/15,s13,x10/14,s5,x7/9,s15,pb/d,x1/3,s1,x10/11,s9,x6/14,pj/a,x15/0,s7,x5/8,pi/e,x2/13,s15,x11/14,s8,x9/15,s2,x6/0,s8,x1/7,s9,x5/14,s5,x11/2,s10,pl/k,s7,x13/15,po/h,x14/1,s14,x4/5,pa/f,x9/10,ph/d,x0/13,pp/k,x15/1,s13,x4/7,pm/b,x8/10,s3,x6/3,pe/d,x4/13,s6,x11/3,pc/p,x9/6,pe/a,x11/0,s12,x12/8,pc/g,x7/4,pl/h,x8/11,s9,x0/3,s4,x10/9,s10,pg/k,x15/8,s3,x11/0,s11,x13/15,ph/j,x1/5,pb/d,x11/9,s14,x10/0,s10,x2/7,pi/m,x14/11,s5,x2/4,s8,x13/12,pn/g,x5/14,pb/d,x9/3,s13,x12/4,s7,x11/5,pf/a,x9/1,s9,x11/0,s14,pn/o,x6/10,s11,x13/15,pm/p,x0/11,pc/o,x6/8,s5,x0/10,s1,pa/d,x1/4,s6,x12/7,pc/g,s10,pm/p,x0/2,s7,x10/5,s2,x0/4,s3,x3/5,s7,pd/g,x2/13,pn/l,x0/10,pk/c,s1,x15/11,pp/f,x14/7,s13,x9/4,s10,x3/8,s15,x7/11,pa/i,x13/6,s11,x1/3,s10,x2/0,pn/f,x3/15,pk/a,s6,x9/12,pl/h,x7/3,s7,x0/9,s6,x15/14,s10,x8/2,s12,x10/9,s14,x2/12,s6,x13/15,s12,x2/14,po/j,s7,x12/7,s3,x15/3,pb/n,x6/2,s5,x11/8,s5,x13/4,pi/c,x14/10,s2,x0/12,s4,pf/o,x8/13,s4,x9/6,s1,x5/0,s14,x1/15,s1,x8/9,s9,x13/12,s2,x14/3,s7,x4/7,s3,x10/2,s11,x0/13,pn/d,x6/9,s10,x11/14,s3,x13/6,s2,x7/5,s1,x14/8,pj/b,x10/4,pc/i,x1/13,s12,x15/3,pb/m,x2/13,pc/h,x4/0,pl/d,x1/10,s3,x7/0,s2,x11/3,pp/a,x1/0,ph/b,x15/12,s5,x10/7,s2,x5/9,po/g,x2/15,s6,pl/j,x12/3,s5,x13/4,s13,x15/8,s7,x10/9,ph/c,x4/14,s15,x6/11,s10,x5/13,s1,x4/0,s5,x6/14,s11,x12/8,s5,x13/15,s6,x3/9,pf/j,s2,x13/15,s4,x4/11,pl/d,x1/10,s2,x6/12,s10,x4/11,s11,x2/15,s4,x4/12,s4,x14/15,po/e,x1/5,s6,x8/15,s6,x6/7,s1,x8/11,pb/f,x10/14,pi/g,s6,x8/1,s11,x9/11,pk/a,x15/0,pl/p,x8/14,pd/f,x5/9,pe/n,x14/8,s2,x12/13,s3,x5/3,pc/i,x14/7,pk/d,x8/5,s2,pa/p,x3/13,s1,x1/5,s12,x10/15,s14,x11/8,s11,x14/3,s6,x13/8,s12,x9/14,s14,x1/2,pc/n,x15/4,pe/a,x13/3,s15,x0/1,pj/m,x8/7,pa/n,x4/15,s12,pj/p,s5,x0/12,po/l,x8/13,s1,x14/15,s1,x12/9,s11,x7/6,s13,x1/10,pg/a,x3/9,ph/n,x12/4,s13,pi/k,x7/6,pf/m,s10,x13/14,s6,x1/6,s9,x5/10,s14,x13/2,pd/l,x4/8,s5,x11/6,pk/g,x15/1,ph/j,x8/5,s15,x11/9,pd/e,x14/6,pi/p,x3/4,po/h,x13/5,s7,x2/0,pk/f,x1/10,s14,x11/5,s5,x12/3,pg/m,x0/14,s2,x11/5,s10,x1/13,pj/f,x14/10,s6,x5/7,s9,pl/a,x1/14,s10,x7/9,s6,pm/n,s7,pa/l,x11/2,pp/h,x13/12,pa/l,x6/8,s12,x4/5,s9,x8/3,pg/j,x12/14,pb/a,x6/1,s13,pl/f,x7/8,s13,x0/9,s14,pb/e,x10/8,s11,pd/a,x5/2,s5,x6/8,s11,x1/3,s1,x2/9,s11,x0/10,s13,x9/6,s11,x15/2,s6,pg/f,x3/1,s3,x15/7,s14,x4/11,s6,x2/6,pc/o,s3,x10/3,s15,x4/13,s7,x3/9,s9,x14/10,pm/p,x12/0,pf/a,s3,x4/15,pg/e,x6/7,s9,x15/10,s15,x7/2,pj/b,x6/1,s12,x0/2,po/f,x1/4,s12,pk/c,x9/2,s12,x15/12,ph/a,s6,pf/j,x1/2,s4,pa/d,x0/11,ph/o,x14/6,pc/n,x3/4,s7,x2/12,s7,x6/8,pa/b,x14/12,s15,x13/0,s6,pk/o,x6/10,s11,x5/0,s8,pj/g,s12,x2/8,s5,pd/h,x9/11,s9,x7/0,pm/a,x2/11,s15,pn/b,s2,x13/7,s9,x15/5,s8,x4/8,pp/k,x3/13,s9,x4/15,s10,x11/1,s8,pb/l,x7/10,s1,x3/5,s11,x1/9,s5,pg/d,x14/12,pf/p,x2/13,s7,x6/7,s2,x15/4,pg/a,x11/9,pp/f,x8/10,pb/k,x14/12,s5,x3/6,pc/e,x1/0,s8,pb/g,x3/12,s11,x2/0,s10,x15/9,s15,x13/4,s11,x3/12,s15,x4/6,s2,x7/5,pp/d,x6/13,s13,pb/l,x5/12,s12,x8/6,s11,x1/12,pi/n,x2/8,pf/a,x14/10,s11,pn/l,x11/15,s15,x13/12,s11,x14/0,pm/h,x12/13,s10,x9/0,s5,pa/i,x7/5,s2,x11/9,pc/f,s12,x6/10,pi/g,s13,x9/4,s4,x11/2,ph/o,x8/5,s8,x15/9,s5,x11/12,s9,x2/7,pp/b,x6/4,s4,pe/m,x2/12,s11,x14/6,s11,x8/15,s1,x3/13,ph/k,x15/5,pj/m,x11/14,pn/i,x12/3,s11,x0/10,s6,x12/7,s8,x8/9,s1,x4/10,pf/o,x11/0,pg/a,s5,x10/15,pl/h,s3,x4/2,s14,x3/5,s2,x13/6,pk/b,x5/11,s2,x13/2,pe/p,x14/15,pj/c,x7/10,pg/h,x1/2,pb/p,x15/6,s4,x11/9,s2,x5/4,s4,x13/10,s11,x0/6,s6,x14/3,po/a,x10/6,pj/h,x5/3,pb/d,x10/4,s12,x13/12,pn/p,x1/9,s6,x3/13,s5,x0/11,s6,x9/14,ph/d,x8/3,s7,x0/1,s2,x3/8,s15,x4/13,pl/b,x2/5,pd/p,x0/3,pj/c,x11/6,pg/n,x15/9,po/h,x11/13,pf/p,x0/12,s4,x6/13,pn/o,x9/10,s6,x15/3,pg/f,s11,x11/10,s15,x3/15,pi/b,x11/1,s15,x4/9,s5,x15/3,pc/o,x13/10,s7,x4/8,s10,x1/14,s11,x6/10,pp/b,x8/3,s5,x1/10,s3,pn/j,x9/15,s11,pe/b,x8/5,s9,x0/6,s1,x10/9,s5,pc/n,s14,x0/12,pf/p,x1/15,pk/e,x6/2,pl/b,x12/5,s14,x6/14,s12,x1/7,pg/o,x6/8,pn/l,s6,x14/9,s1,x6/0,s15,x14/5,s11,pf/e,x9/11,pk/n,x7/13,pp/e,s6,x0/10,pj/l,x6/11,po/f,x0/8,s6,x15/11,s8,pj/b,x8/4,s14,x10/2,pi/k,x7/9,s15,x2/13,s13,pm/d,x3/11,pk/c,x9/4,pn/e,x0/8,pc/p,x15/12,pe/g,x10/11,pb/l,x14/4,s14,x13/2,s2,pe/j,x4/1,pn/o,x12/5,pl/i,x1/11,s12,x0/13,ph/m,x15/6,s5,x7/11,s6,x0/9,s13,x11/10,s11,x6/7,s13,x3/15,s9,x8/11,pg/l,x4/5,ph/f,x11/7,s12,pg/p,x5/10,s13,x13/15,s15,x5/8,s10,x6/9,s15,x4/2,s13,x9/6,pe/a,x2/0,pc/l,x14/9,pf/d,x12/5,s11,x2/9,pn/m,x3/11,s6,x1/8,s11,x5/9,s4,x11/0,s1,pc/b,s1,x8/10,pg/f,x15/3,s9,x8/11,pi/n,x5/3,pe/m,x9/10,s10,pc/k,x3/6,s9,x10/1,pf/g,x4/13,pn/a,x12/0,s10,pp/m,x3/10,s12,x6/0,pn/e,x12/9,s12,pg/b,x4/6,s9,x9/2,s6,x0/15,pi/j,s12,x1/5,po/p,x15/11,s4,x12/4,pj/n,x0/8,s12,x13/6,s10,x2/4,pc/d,x11/15,pf/h,x0/8,s15,x5/7,s13,x14/2,s1,pn/l,x12/7,s15,x11/6,pf/j,x7/0,pl/o,x9/2,pc/p,x11/13,s2,x12/15,pd/i,s2,pk/j,x5/4,pb/f,x10/1,s2,x13/11,s8,x2/3,s15,x10/15,s9,x11/1,s14,x2/8,s2,x4/15,pe/l,x6/7,s5,x8/13,s6,x2/5,s8,x7/6,po/i,x8/5,s6,pe/g,x1/15,s6,pf/d,x3/4,pb/m,x8/9,s12,x2/0,s13,x12/13,s7,x1/15,pp/d,x4/3,s15,x13/2,s9,x9/5,pl/h,x15/2,pp/b,x4/9,s10,x0/7,pg/d,x14/11,s2,x8/15,s7,x6/12,s12,x15/0,pk/a,x7/14,pf/j,s8,x15/11,s8,x8/9,pc/o,s8,x12/13,s6,x6/9,pm/a,x5/4,s7,x3/2,s7,x10/13,s5,x1/12,pf/c,x6/9,s2,x8/1,s1,x5/3,ph/l,x14/0,pg/p,x5/4,pa/e,x8/9,pm/o,x14/12,pe/k,x9/10,s1,x0/6,s7,x15/10,pf/g,x8/13,s11,x4/2,pe/m,s11,x7/12,s12,x10/11,s2,x5/13,s11,x12/3,pd/c,x13/4,s7,x0/14,s8,x8/4,pe/n,s15,x13/7,pb/c,x0/1,s9,x5/14,s12,x12/11,pf/m,x2/1,s6,x0/12,s15,x10/4,s5,x13/2,s11,x10/15,pl/e,x1/14,s12,x2/7,s7,x14/12,s3,po/m,x9/8,s2,x4/11,s7,x0/2,s15,x3/9,s3,x15/14,s11,x2/5,s9,x10/6,s11,x15/4,s11,pb/g,x1/10,pi/e,x3/15,s8,x10/8,pg/j,x1/3,pn/a,x12/13,s5,x14/2,pf/c,x3/7,s4,x12/5,s10,x2/8,pg/m,x0/9,s11,x15/7,s3,pi/b,s11,pa/e,x11/6,po/g,x7/1,s14,x10/8,s12,pk/i,x13/11,pb/p,x12/8,s11,x14/2,s10,x6/10,s6,x0/1,s4,x14/3,pi/l,x12/7,pd/e,s5,x1/13,s15,x12/5,s8,x15/0,s12,x3/13,pi/b,x7/11,po/g,x2/3,s8,x5/0,pk/f,x10/13,pp/o,x0/7,pj/l,x12/5,s12,x13/4,s13,x14/3,pc/b,x4/0,pf/l,x5/1,s13,x13/10,pk/g,x8/2,s13,x0/3,s4,x4/2,s9,x10/11,s1,pm/p,x14/2,s6,pe/h,x8/5,s6,x7/11,pb/j,x6/9,s10,x0/7,pa/l,x6/10,s5,x3/15,s12,x5/12,s10,pn/d,x11/13,s6,x9/3,pc/b,s13,x13/12,po/h,x7/8,s12,x15/1,pm/k,x0/4,pj/h,x10/1,s4,x14/6,pe/p,x9/1,pi/f,x11/0,pa/n,x9/13,s7,x15/14,pe/o,x3/0,pa/i,x14/13,s9,x15/8,pk/o,x14/5,s8,x4/11,s5,pn/a,x6/5,pg/j,x14/8,pa/d,x13/15,s10,x10/7,s13,pc/e,x13/8,pg/k,x12/4,pj/n,x7/0,s10,x5/12,s5,x7/14,s7,x11/2,pf/b,x4/15,pe/h,x0/10,pa/o,x13/3,pf/e,s8,x7/5,s12,x9/6,s6,x1/7,s8,x0/6,s15,pd/h,x1/12,pb/e,x11/15,s10,x13/7,pn/c,x6/9,pb/o,x11/14,s5,x9/4,s5,x2/3,s2,x6/14,pg/j,x5/12,pc/b,x15/7,ph/f,x9/14,s14,x2/7,pa/j,x6/8,s4,x9/14,s9,x10/5,s2,x7/9,s9,x6/12,s3,x8/1,pe/n,s15,pl/g,x15/7,s15,x13/3,s12,x14/1,ph/o,s9,x7/10,s6,pi/c,x9/1,pd/f,s4,x0/13,pc/o,x15/2,s10,x9/7,s14,x14/6,s7,x13/12,pp/k,x3/5,s11,x4/6,pg/m,x12/9,pl/b,x13/10,s1,x9/14,pk/j,x4/1,pi/a,x0/10,s6,x4/15,s10,x9/1,s6,x6/14,s6,x0/7,s7,x5/1,s13,x11/0,s4,x10/7,pm/d,x15/14,s5,x5/3,s2,x13/12,pp/e,x14/15,pg/n,x6/10,s3,x7/4,s4,x5/14,pl/j,x7/1,pm/c,x4/6,pg/e,x11/9,s3,x3/6,pa/o,x5/9,s15,x4/0,pn/e,x2/13
\ No newline at end of file
diff --git a/tests/assert/config.nims b/tests/assert/config.nims
new file mode 100644
index 000000000..f1cffeb6c
--- /dev/null
+++ b/tests/assert/config.nims
@@ -0,0 +1 @@
+--excessiveStackTrace:on
diff --git a/tests/assert/panicoverride.nim b/tests/assert/panicoverride.nim
new file mode 100644
index 000000000..53ad64215
--- /dev/null
+++ b/tests/assert/panicoverride.nim
@@ -0,0 +1,15 @@
+# panicoverride.nim
+
+proc printf(fmt: cstring) {.varargs, importc, header:"stdio.h".}
+proc exit(code: cint) {.importc, header:"stdlib.h".}
+
+{.push stack_trace: off, profiler:off.}
+
+proc rawoutput(s: cstring) =
+  printf("RAW: %s\n", s)
+  
+proc panic(s: cstring) {.noreturn.} =
+  printf("PANIC: %s\n", s)
+  exit(0)
+
+{.pop.}
\ No newline at end of file
diff --git a/tests/assert/t21195.nim b/tests/assert/t21195.nim
new file mode 100644
index 000000000..b690d22a0
--- /dev/null
+++ b/tests/assert/t21195.nim
@@ -0,0 +1,6 @@
+discard """
+  matrix: "--verbosity:0 --os:standalone --mm:none"
+"""
+# bug #21195
+var n = 11
+assert(n == 12)
diff --git a/tests/assert/tassert.nim b/tests/assert/tassert.nim
new file mode 100644
index 000000000..a14fec317
--- /dev/null
+++ b/tests/assert/tassert.nim
@@ -0,0 +1,20 @@
+discard """
+  outputsub: "assertion failure!this shall be always written"
+  exitcode: "1"
+"""
+# test assert and exception handling
+
+proc callB() = assert(false)
+proc callA() = callB()
+proc callC() = callA()
+
+try:
+  callC()
+except AssertionDefect:
+  write(stdout, "assertion failure!")
+except:
+  write(stdout, "unknown exception!")
+finally:
+  system.write(stdout, "this shall be always written")
+
+assert(false) #OUT assertion failure!this shall be always written
diff --git a/tests/assert/tassert2.nim b/tests/assert/tassert2.nim
new file mode 100644
index 000000000..e32ab72e1
--- /dev/null
+++ b/tests/assert/tassert2.nim
@@ -0,0 +1,111 @@
+discard """
+  output: '''
+`false` first assertion from bar
+`false` second assertion from bar
+-1
+'''
+"""
+from strutils import endsWith
+
+type
+  TLineInfo = tuple[filename: string, line: int, column: int]
+  TMyError = object of Exception
+    lineinfo: TLineInfo
+  EMyError = ref TMyError
+
+
+# NOTE: when entering newlines, adjust `expectedEnd` outputs
+
+try:
+  doAssert(false, "msg1") # doAssert test
+except AssertionDefect as e:
+  assert e.msg.endsWith "tassert2.nim(20, 11) `false` msg1"
+
+try:
+  assert false # assert test with no msg
+except AssertionDefect as e:
+  assert e.msg.endsWith "tassert2.nim(25, 3) `false` "
+
+try:
+  let a = 1
+  doAssert(a+a==1) # assert test with Ast expression
+  # BUG: const folding would make "1+1==1" appear as `false` in
+  # assert message
+except AssertionDefect as e:
+  assert e.msg.endsWith "`a + a == 1` "
+
+try:
+  let a = 1
+  doAssert a+a==1 # ditto with `doAssert` and no parens
+except AssertionDefect as e:
+  assert e.msg.endsWith "`a + a == 1` "
+
+proc fooStatic() =
+  # protect against https://github.com/nim-lang/Nim/issues/8758
+  static: doAssert(true)
+fooStatic()
+
+
+
+
+
+block:
+  # scope-wide policy to change the failed assert
+  # exception type in order to include a lineinfo
+  onFailedAssert(msg):
+    var e = new(TMyError)
+    e.msg = msg
+    e.lineinfo = instantiationInfo(-2)
+    raise e
+
+  proc foo =
+    assert(false, "assertion from foo")
+
+
+  proc bar: int =
+    # local overrides that are active only in this proc
+    onFailedAssert(msg):
+      echo msg[^32..^1]
+
+    assert(false, "first assertion from bar")
+
+    onFailedAssert(msg):
+      echo msg[^33..^1]
+      return -1
+
+    assert(false, "second assertion from bar")
+    return 10
+
+  echo(bar())
+
+  try:
+    foo()
+  except:
+    let e = EMyError(getCurrentException())
+    assert e.msg.endsWith "tassert2.nim(62, 11) `false` assertion from foo"
+
+block: ## checks for issue https://github.com/nim-lang/Nim/issues/8518
+  template fun(a: string): string =
+      const pattern = a & a
+      pattern
+
+  try:
+    doAssert fun("foo1") == fun("foo2"), "mymsg"
+  except AssertionDefect as e:
+    # used to expand out the template instantiaiton, sometimes filling hundreds of lines
+    assert e.msg.endsWith ""
+
+block: ## checks for issue https://github.com/nim-lang/Nim/issues/9301
+  try:
+    doAssert 1 + 1 == 3
+  except AssertionDefect as e:
+    # used to const fold as false
+    assert e.msg.endsWith "tassert2.nim(100, 5) `1 + 1 == 3` "
+
+block: ## checks AST isn't transformed as it used to
+  let a = 1
+  try:
+    doAssert a > 1
+  except AssertionDefect as e:
+    # used to rewrite as `1 < a`
+    assert e.msg.endsWith "tassert2.nim(108, 5) `a > 1` "
diff --git a/tests/assert/tassert_c.nim b/tests/assert/tassert_c.nim
new file mode 100644
index 000000000..e3e3b8147
--- /dev/null
+++ b/tests/assert/tassert_c.nim
@@ -0,0 +1,40 @@
+discard """
+  matrix: "-d:nimPreviewSlimSystem --stackTrace:on --excessiveStackTrace:off"
+  output: '''true'''
+"""
+import std/assertions
+const expected = """
+tassert_c.nim(35)        tassert_c
+tassert_c.nim(34)        foo
+assertions.nim(*)       failedAssertImpl
+assertions.nim(*)       raiseAssert
+"""
+
+proc tmatch(x, p: string): bool =
+  var i = 0
+  var k = 0
+  while i < p.len:
+    if p[i] == '*':
+      let oldk = k
+      while k < x.len and x[k] in {'0'..'9'}: inc k
+      # no digit skipped?
+      if oldk == k: return false
+      inc i
+    elif k < x.len and p[i] == x[k]:
+      inc i
+      inc k
+    else:
+      return false
+  while k < x.len and x[k] in {' ', '\L', '\C'}: inc k
+  result = i >= p.len and k >= x.len
+
+
+try:
+  proc foo() =
+    assert(false)
+  foo()
+except AssertionDefect:
+  let e = getCurrentException()
+  let trace = e.getStackTrace
+  if tmatch(trace, expected): echo true
+  else: echo "wrong trace:\n" & trace
diff --git a/tests/assert/tunittests.nim b/tests/assert/tunittests.nim
new file mode 100644
index 000000000..de917511c
--- /dev/null
+++ b/tests/assert/tunittests.nim
@@ -0,0 +1,4 @@
+discard """
+output: ""
+"""
+import "../template/utemplates", "../closure/uclosures"
diff --git a/tests/assert/tuserassert.nim b/tests/assert/tuserassert.nim
new file mode 100644
index 000000000..274c78921
--- /dev/null
+++ b/tests/assert/tuserassert.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "x == 45ugh"
+"""
+
+template myAssert(cond: untyped) =
+  when 3 <= 3:
+    let c = cond.astToStr
+    if not cond:
+      echo c, "ugh"
+
+var x = 454
+myAssert(x == 45)
+
diff --git a/tests/assign/moverload_asgn2.nim b/tests/assign/moverload_asgn2.nim
new file mode 100644
index 000000000..cfea48cd1
--- /dev/null
+++ b/tests/assign/moverload_asgn2.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "--mm:refc"
+"""
+
+type
+  Concrete* = object
+    a*, b*: string
+    rc*: int # refcount
+
+proc `=`(d: var Concrete; src: Concrete) =
+  shallowCopy(d.a, src.a)
+  shallowCopy(d.b, src.b)
+  dec d.rc
+  d.rc = src.rc + 1
diff --git a/tests/assign/tassign.nim b/tests/assign/tassign.nim
new file mode 100644
index 000000000..fdec04d22
--- /dev/null
+++ b/tests/assign/tassign.nim
@@ -0,0 +1,218 @@
+discard """
+  output:
+'''
+TEMP=C:\Programs\xyz\bin
+8 5 0 0
+pre test a:test b:1 c:2 haha:3
+assignment test a:test b:1 c:2 haha:3
+abc123
+'''
+"""
+
+#[
+Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+Concrete '='
+GenericT[T] '=' int
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' float
+GenericT[T] '=' string
+GenericT[T] '=' int8
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+GenericT[T] '=' bool
+]#
+
+block tassign:
+# Test the assignment operator for complex types which need RTTI
+  type
+    TRec = object
+      x, y: int
+      s: string
+      seq: seq[string]
+      arr: seq[seq[array[0..3, string]]]
+    TRecSeq = seq[TRec]
+
+  proc test() =
+    var
+      a, b: TRec
+    a.x = 1
+    a.y = 2
+    a.s = "Hallo!"
+    a.seq = @["abc", "def", "ghi", "jkl"]
+    a.arr = @[]
+    setLen(a.arr, 4)
+    a.arr[0] = @[]
+    a.arr[1] = @[]
+
+    b = a # perform a deep copy here!
+    b.seq = @["xyz", "huch", "was", "soll"]
+    doAssert len(a.seq) == 4
+    doAssert a.seq[3] == "jkl"
+    doAssert len(b.seq) == 4
+    doAssert b.seq[3] == "soll"
+    doAssert b.y == 2
+
+  test()
+
+
+
+import strutils
+block tcopy:
+  proc main() =
+    const
+      example = r"TEMP=C:\Programs\xyz\bin"
+    var
+      a, b: string
+      p: int
+    p = find(example, "=")
+    a = substr(example, 0, p-1)
+    b = substr(example, p+1)
+    writeLine(stdout, a & '=' & b)
+
+  main()
+
+
+
+block tgenericassign:
+  type
+    TAny {.pure.} = object
+      value: pointer
+      rawType: pointer
+
+  proc newAny(value, rawType: pointer): TAny =
+    result.value = value
+    result.rawType = rawType
+
+  var name: cstring = "example"
+
+  var ret: seq[tuple[name: string, a: TAny]] = @[]
+  for i in 0 .. 8000:
+    var tup = ($name, newAny(nil, nil))
+    doAssert(tup[0] == "example")
+    ret.add(tup)
+    doAssert(ret[ret.len()-1][0] == "example")
+
+
+
+block tgenericassign_tuples:
+  var t, s: tuple[x: string, c: int]
+
+  proc ugh: seq[tuple[x: string, c: int]] =
+    result = @[("abc", 232)]
+
+  t = ugh()[0]
+  s = t
+  s = ugh()[0]
+
+  doAssert s[0] == "abc"
+  doAssert s[1] == 232
+
+
+
+block tobjasgn:
+  type
+    TSomeObj = object of RootObj
+      a, b: int
+    PSomeObj = ref object
+      a, b: int
+
+  var a = TSomeObj(a: 8)
+  var b = PSomeObj(a: 5)
+  echo a.a, " ", b.a, " ", a.b, " ", b.b
+
+  # bug #575
+
+  type
+    Something = object of RootObj
+      a: string
+      b, c: int32
+
+  type
+    Other = object of Something
+      haha: int
+
+  proc `$`(x: Other): string =
+    result = "a:" & x.a & " b:" & $x.b & " c:" & $x.c & " haha:" & $x.haha
+
+  var
+    t: Other
+
+  t.a = "test"
+  t.b = 1
+  t.c = 2
+  t.haha = 3
+
+  echo "pre test ", $t
+  var x = t
+  echo "assignment test ", x
+
+
+when false:
+  type
+    Concrete = object
+      a, b: string
+
+  proc `=`(d: var Concrete; src: Concrete) =
+    shallowCopy(d.a, src.a)
+    shallowCopy(d.b, src.b)
+    echo "Concrete '='"
+
+  var x, y: array[0..2, Concrete]
+  var cA, cB: Concrete
+
+  var cATup, cBTup: tuple[x: int, ha: Concrete]
+
+  x = y
+  cA = cB
+  cATup = cBTup
+
+  type
+    GenericT[T] = object
+      a, b: T
+
+  proc `=`[T](d: var GenericT[T]; src: GenericT[T]) =
+    shallowCopy(d.a, src.a)
+    shallowCopy(d.b, src.b)
+    echo "GenericT[T] '=' ", typeof(T).name
+
+  var ag: GenericT[int]
+  var bg: GenericT[int]
+
+  ag = bg
+
+  var xg, yg: array[0..2, GenericT[float]]
+  var cAg, cBg: GenericT[string]
+
+  var cATupg, cBTupg: tuple[x: int, ha: GenericT[int8]]
+
+  xg = yg
+  cAg = cBg
+  cATupg = cBTupg
+
+  var caSeqg, cbSeqg: seq[GenericT[bool]]
+  newSeq(cbSeqg, 4)
+  caSeqg = cbSeqg
+
+  when false:
+    type
+      Foo = object
+        case b: bool
+        of false: xx: GenericT[int]
+        of true: yy: bool
+
+    var
+      a, b: Foo
+    a = b
+
+block tgeneric_assign_varargs:
+  template fatal(msgs: varargs[string]) =
+    for msg in msgs:
+      stdout.write(msg)
+    stdout.write('\n')
+
+  fatal "abc", "123"
diff --git a/tests/assign/tobject_assign.nim b/tests/assign/tobject_assign.nim
new file mode 100644
index 000000000..8e39ead53
--- /dev/null
+++ b/tests/assign/tobject_assign.nim
@@ -0,0 +1,49 @@
+# bug #16706
+
+block: # reduced example
+  type
+    A = object of RootObj
+      a0: string
+    B = object
+      b0: seq[A]
+  var c = newSeq[A](2)
+  var d = B(b0: c)
+
+when true: # original example
+  import std/[options, tables, times]
+
+  type
+    Data* = object
+      shifts*: OrderedTable[int64, Shift]
+      balance*: float
+
+    Shift* = object
+      quoted*: bool
+      date*: DateTime
+      description*: string
+      start*: Option[DateTime]
+      finish*: Option[DateTime]
+      breakTime*: Option[Duration]
+      rate*: float
+      qty: Option[float]
+      id*: int64
+
+  let shift = Shift(
+    quoted: true,
+    date: parse("2000-01-01", "yyyy-MM-dd"),
+    description: "abcdef",
+    start: none(DateTime),
+    finish: none(DateTime),
+    breakTime: none(Duration),
+    rate: 462.11,
+    qty: some(10.0),
+    id: getTime().toUnix()
+  )
+
+  var shifts: OrderedTable[int64, Shift]
+  shifts[shift.id] = shift
+
+  discard Data(
+    shifts: shifts,
+    balance: 0.00
+  )
diff --git a/tests/assign/toverload_asgn2.nim b/tests/assign/toverload_asgn2.nim
new file mode 100644
index 000000000..1104be92b
--- /dev/null
+++ b/tests/assign/toverload_asgn2.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''i value 88
+2aa'''
+  disabled: "true"
+"""
+
+import moverload_asgn2
+
+proc passAround(i: int): Concrete =
+  echo "i value ", i
+  result = Concrete(a: "aa", b: "bb", rc: 0)
+
+proc main =
+  let
+    i = 88
+    v = passAround(i)
+    z = v.a
+  var
+    x: Concrete
+  x = v
+  echo x.rc, z # 2aa
+
+main()
diff --git a/tests/assign/tvariantasgn.nim b/tests/assign/tvariantasgn.nim
new file mode 100644
index 000000000..4c3c38ca5
--- /dev/null
+++ b/tests/assign/tvariantasgn.nim
@@ -0,0 +1,39 @@
+discard """
+  output: "came here"
+"""
+
+#BUG
+type
+  TAnyKind = enum
+    nkInt,
+    nkFloat,
+    nkString
+  TAny = object
+    case kind: TAnyKind
+    of nkInt: intVal: int
+    of nkFloat: floatVal: float
+    of nkString: strVal: string
+
+var s: TAny
+s = TAny(kind: nkString, strVal: "test")
+
+var nr: TAny
+s = TAny(kind: nkInt, intVal: 78)
+
+
+# s = nr # works
+nr = s # fails!
+echo "came here"
+
+block: # bug #12464
+  type
+    Foo = object
+      case isFunc: bool
+      of false: nil
+      of true:
+        fun: proc(): int
+
+  const i = Foo(isFunc: false)
+
+  let j = i
+  doAssert not j.isFunc
diff --git a/tests/ast_pattern_matching.nim b/tests/ast_pattern_matching.nim
new file mode 100644
index 000000000..0ba0aa57a
--- /dev/null
+++ b/tests/ast_pattern_matching.nim
@@ -0,0 +1,584 @@
+# this is a copy paste implementation of github.com/krux02/ast_pattern_matching
+# Please provide bugfixes upstream first before adding them here.
+
+import macros, strutils, tables
+
+export macros
+
+when isMainModule:
+  template debug(args: varargs[untyped]): untyped =
+    echo args
+else:
+  template debug(args: varargs[untyped]): untyped =
+    discard
+
+const
+  nnkIntLiterals*   = nnkCharLit..nnkUInt64Lit
+  nnkStringLiterals* = nnkStrLit..nnkTripleStrLit
+  nnkFloatLiterals* = nnkFloatLit..nnkFloat64Lit
+
+proc newLit[T: enum](arg: T): NimNode =
+  newIdentNode($arg)
+
+proc newLit[T](arg: set[T]): NimNode =
+  ## does not work for the empty sets
+  result = nnkCurly.newTree
+  for x in arg:
+    result.add newLit(x)
+
+type SomeFloat = float | float32 | float64
+
+proc len[T](arg: set[T]): int = card(arg)
+
+type
+  MatchingErrorKind* = enum
+    NoError
+    WrongKindLength
+    WrongKindValue
+    WrongIdent
+    WrongCustomCondition
+
+  MatchingError = object
+    node*: NimNode
+    expectedKind*: set[NimNodeKind]
+    case kind*: MatchingErrorKind
+    of NoError:
+      discard
+    of WrongKindLength:
+      expectedLength*: int
+    of WrongKindValue:
+      expectedValue*: NimNode
+    of WrongIdent, WrongCustomCondition:
+      strVal*: string
+
+proc `$`*(arg: MatchingError): string =
+  let n = arg.node
+  case arg.kind
+  of NoError:
+    "no error"
+  of WrongKindLength:
+    let k = arg.expectedKind
+    let l = arg.expectedLength
+    var msg = "expected "
+    if k.len == 0:
+      msg.add "any node"
+    elif k.len == 1:
+      for el in k:  # only one element but there is no index op for sets
+        msg.add $el
+    else:
+      msg.add "a node in" & $k
+
+    if l >= 0:
+      msg.add " with " & $l & " child(ren)"
+    msg.add ", but got " & $n.kind
+    if l >= 0:
+      msg.add " with " & $n.len & " child(ren)"
+    msg
+  of WrongKindValue:
+    let k = $arg.expectedKind
+    let v = arg.expectedValue.repr
+    var msg = "expected " & k & " with value " & v & " but got " & n.lispRepr
+    if n.kind in {nnkOpenSymChoice, nnkClosedSymChoice}:
+      msg = msg & " (a sym-choice does not have a strVal member, maybe you should match with `ident`)"
+    msg
+  of WrongIdent:
+    let prefix = "expected ident `" & arg.strVal & "` but got "
+    if n.kind in {nnkIdent, nnkSym, nnkOpenSymChoice, nnkClosedSymChoice}:
+      prefix & "`" & n.strVal & "`"
+    else:
+      prefix & $n.kind & " with " & $n.len & " child(ren)"
+  of WrongCustomCondition:
+    "custom condition check failed: " & arg.strVal
+
+
+proc failWithMatchingError*(arg: MatchingError): void {.compileTime, noReturn.} =
+  error($arg, arg.node)
+
+proc expectValue(arg: NimNode; value: SomeInteger): void {.compileTime.} =
+  arg.expectKind nnkLiterals
+  if arg.intVal != int(value):
+    error("expected value " & $value & " but got " & arg.repr, arg)
+
+proc expectValue(arg: NimNode; value: SomeFloat): void {.compileTime.} =
+  arg.expectKind nnkLiterals
+  if arg.floatVal != float(value):
+    error("expected value " & $value & " but got " & arg.repr, arg)
+
+proc expectValue(arg: NimNode; value: string): void {.compileTime.} =
+  arg.expectKind nnkLiterals
+  if arg.strVal != value:
+    error("expected value " & value & " but got " & arg.repr, arg)
+
+proc expectValue[T](arg: NimNode; value: pointer): void {.compileTime.} =
+  arg.expectKind nnkLiterals
+  if value != nil:
+    error("Expect Value for pointers works only on `nil` when the argument is a pointer.")
+  arg.expectKind nnkNilLit
+
+proc expectIdent(arg: NimNode; strVal: string): void {.compileTime.} =
+  if not arg.eqIdent(strVal):
+    error("Expect ident `" & strVal & "` but got " & arg.repr)
+
+proc matchLengthKind*(arg: NimNode; kind: set[NimNodeKind]; length: int): MatchingError {.compileTime.} =
+  let kindFail   = not(kind.card == 0 or arg.kind in kind)
+  let lengthFail = not(length < 0 or length == arg.len)
+  if kindFail or lengthFail:
+    result.node = arg
+    result.kind = WrongKindLength
+    result.expectedLength = length
+    result.expectedKind   = kind
+
+
+proc matchLengthKind*(arg: NimNode; kind: NimNodeKind; length: int): MatchingError {.compileTime.} =
+  matchLengthKind(arg, {kind}, length)
+
+proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: SomeInteger): MatchingError {.compileTime.} =
+  template kindFail: bool  = not(kind.card == 0 or arg.kind in kind)
+  template valueFail: bool = arg.intVal != int(value)
+  if kindFail or valueFail:
+    result.node = arg
+    result.kind = WrongKindValue
+    result.expectedKind  = kind
+    result.expectedValue = newLit(value)
+
+proc matchValue(arg: NimNode; kind: NimNodeKind; value: SomeInteger): MatchingError {.compileTime.} =
+  matchValue(arg, {kind}, value)
+
+proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: SomeFloat): MatchingError {.compileTime.} =
+  let kindFail   = not(kind.card == 0 or arg.kind in kind)
+  let valueFail  = arg.floatVal != float(value)
+  if kindFail or valueFail:
+    result.node = arg
+    result.kind = WrongKindValue
+    result.expectedKind  = kind
+    result.expectedValue = newLit(value)
+
+proc matchValue(arg: NimNode; kind: NimNodeKind; value: SomeFloat): MatchingError {.compileTime.} =
+  matchValue(arg, {kind}, value)
+
+const nnkStrValKinds = {nnkStrLit, nnkRStrLit, nnkTripleStrLit, nnkIdent, nnkSym}
+
+proc matchValue(arg: NimNode; kind: set[NimNodeKind]; value: string): MatchingError {.compileTime.} =
+  # if kind * nnkStringLiterals TODO do something that ensures that here is only checked for string literals
+  let kindFail   = not(kind.card == 0 or arg.kind in kind)
+  let valueFail  =
+    if kind.card == 0:
+      false
+    else:
+      arg.kind notin (kind * nnkStrValKinds) or arg.strVal != value
+  if kindFail or valueFail:
+    result.node = arg
+    result.kind = WrongKindValue
+    result.expectedKind  = kind
+    result.expectedValue = newLit(value)
+
+proc matchValue(arg: NimNode; kind: NimNodeKind; value: string): MatchingError {.compileTime.} =
+  matchValue(arg, {kind}, value)
+
+proc matchValue[T](arg: NimNode; value: pointer): MatchingError {.compileTime.} =
+  if value != nil:
+    error("Expect Value for pointers works only on `nil` when the argument is a pointer.")
+  arg.matchLengthKind(nnkNilLit, -1)
+
+proc matchIdent*(arg:NimNode; value: string): MatchingError =
+  if not arg.eqIdent(value):
+    result.node = arg
+    result.kind = Wrongident
+    result.strVal = value
+
+proc checkCustomExpr*(arg: NimNode; cond: bool, exprstr: string): MatchingError =
+  if not cond:
+    result.node = arg
+    result.kind = WrongCustomCondition
+    result.strVal = exprstr
+
+static:
+  var literals: array[19, NimNode]
+  var i = 0
+  for litKind in nnkLiterals:
+    literals[i] = ident($litKind)
+    i += 1
+
+  var nameToKind = newTable[string, NimNodeKind]()
+  for kind in NimNodeKind:
+    nameToKind[ ($kind)[3..^1] ] = kind
+
+  let identifierKinds = newLit({nnkSym, nnkIdent, nnkOpenSymChoice, nnkClosedSymChoice})
+
+proc generateMatchingCode(astSym: NimNode, pattern: NimNode, depth: int, blockLabel, errorSym, localsArraySym: NimNode; dest: NimNode): int =
+  ## return the number of indices used in the array for local variables.
+
+  var currentLocalIndex = 0
+
+  proc nodeVisiting(astSym: NimNode, pattern: NimNode, depth: int): void =
+    let ind = "  ".repeat(depth) # indentation
+
+    proc genMatchLogic(matchProc, argSym1, argSym2: NimNode): void =
+      dest.add quote do:
+        `errorSym` = `astSym`.`matchProc`(`argSym1`, `argSym2`)
+        if `errorSym`.kind != NoError:
+          break `blockLabel`
+
+    proc genIdentMatchLogic(identValueLit: NimNode): void =
+      dest.add quote do:
+        `errorSym` = `astSym`.matchIdent(`identValueLit`)
+        if `errorSym`.kind != NoError:
+          break `blockLabel`
+
+    proc genCustomMatchLogic(conditionExpr: NimNode): void =
+      let exprStr = newLit(conditionExpr.repr)
+      dest.add quote do:
+        `errorSym` = `astSym`.checkCustomExpr(`conditionExpr`, `exprStr`)
+        if `errorSym`.kind != NoError:
+          break `blockLabel`
+
+    # proc handleKindMatching(kindExpr: NimNode): void =
+    #   if kindExpr.eqIdent("_"):
+    #     # this is the wildcand that matches any kind
+    #     return
+    #   else:
+    #     genMatchLogic(bindSym"matchKind", kindExpr)
+
+    # generate recursively a matching expression
+    if pattern.kind == nnkCall:
+      pattern.expectMinLen(1)
+
+      debug ind, pattern[0].repr, "("
+
+      let kindSet = if pattern[0].eqIdent("_"): nnkCurly.newTree else: pattern[0]
+      # handleKindMatching(pattern[0])
+
+      if pattern.len == 2 and pattern[1].kind == nnkExprEqExpr:
+        if pattern[1][1].kind in nnkStringLiterals:
+          pattern[1][0].expectIdent("strVal")
+        elif pattern[1][1].kind in nnkIntLiterals:
+          pattern[1][0].expectIdent("intVal")
+        elif pattern[1][1].kind in nnkFloatLiterals:
+          pattern[1][0].expectIdent("floatVal")
+
+        genMatchLogic(bindSym"matchValue", kindSet, pattern[1][1])
+
+      else:
+        let lengthLit = newLit(pattern.len - 1)
+        genMatchLogic(bindSym"matchLengthKind", kindSet, lengthLit)
+
+        for i in 1 ..< pattern.len:
+          let childSym = nnkBracketExpr.newTree(localsArraySym, newLit(currentLocalIndex))
+          currentLocalIndex += 1
+          let indexLit = newLit(i - 1)
+          dest.add quote do:
+            `childSym` = `astSym`[`indexLit`]
+          nodeVisiting(childSym, pattern[i], depth + 1)
+      debug ind, ")"
+    elif pattern.kind == nnkCallStrLit and pattern[0].eqIdent("ident"):
+      genIdentMatchLogic(pattern[1])
+
+    elif pattern.kind == nnkPar and pattern.len == 1:
+      nodeVisiting(astSym, pattern[0], depth)
+    elif pattern.kind == nnkPrefix:
+      error("prefix patterns not implemented", pattern)
+    elif pattern.kind == nnkAccQuoted:
+      debug ind, pattern.repr
+      let matchedExpr = pattern[0]
+      matchedExpr.expectKind nnkIdent
+      dest.add quote do:
+        let `matchedExpr` = `astSym`
+
+    elif pattern.kind == nnkInfix and pattern[0].eqIdent("@"):
+      pattern[1].expectKind nnkAccQuoted
+
+      let matchedExpr = pattern[1][0]
+      matchedExpr.expectKind nnkIdent
+      dest.add quote do:
+        let `matchedExpr` = `astSym`
+
+      debug ind, pattern[1].repr, " = "
+      nodeVisiting(matchedExpr, pattern[2], depth + 1)
+
+    elif pattern.kind == nnkInfix and pattern[0].eqIdent("|="):
+      nodeVisiting(astSym, pattern[1], depth + 1)
+      genCustomMatchLogic(pattern[2])
+
+    elif pattern.kind in nnkCallKinds:
+      error("only boring call syntax allowed, this is " & $pattern.kind & ".", pattern)
+    elif pattern.kind in nnkLiterals:
+      genMatchLogic(bindSym"matchValue", nnkCurly.newTree, pattern)
+    elif not pattern.eqIdent("_"):
+      # When it is not one of the other branches, it is simply treated
+      # as an expression for the node kind, without checking child
+      # nodes.
+      debug ind, pattern.repr
+      genMatchLogic(bindSym"matchLengthKind", pattern, newLit(-1))
+
+  nodeVisiting(astSym, pattern, depth)
+
+  return currentLocalIndex
+
+macro matchAst*(astExpr: NimNode; args: varargs[untyped]): untyped =
+  let astSym = genSym(nskLet, "ast")
+  let beginBranches = if args[0].kind == nnkIdent: 1 else: 0
+  let endBranches   = if args[^1].kind == nnkElse: args.len - 1 else: args.len
+  for i in beginBranches ..< endBranches:
+    args[i].expectKind nnkOfBranch
+
+  let outerErrorSym: NimNode =
+    if beginBranches == 1:
+      args[0].expectKind nnkIdent
+      args[0]
+    else:
+      nil
+
+  let elseBranch: NimNode =
+    if endBranches == args.len - 1:
+      args[^1].expectKind(nnkElse)
+      args[^1][0]
+    else:
+      nil
+
+  let outerBlockLabel = genSym(nskLabel, "matchingSection")
+  let outerStmtList = newStmtList()
+  let errorSymbols = nnkBracket.newTree
+
+  ## the vm only allows 255 local variables. This sucks a lot and I
+  ## have to work around it.  So instead of creating a lot of local
+  ## variables, I just create one array of local variables. This is
+  ## just annoying.
+  let localsArraySym = genSym(nskVar, "locals")
+  var localsArrayLen: int = 0
+
+  for i in beginBranches ..< endBranches:
+    let ofBranch = args[i]
+
+    ofBranch.expectKind(nnkOfBranch)
+    ofBranch.expectLen(2)
+    let pattern = ofBranch[0]
+    let code = ofBranch[1]
+    code.expectKind nnkStmtList
+    let stmtList = newStmtList()
+    let blockLabel = genSym(nskLabel, "matchingBranch")
+    let errorSym = genSym(nskVar, "branchError")
+
+    errorSymbols.add errorSym
+    let numLocalsUsed = generateMatchingCode(astSym, pattern, 0, blockLabel, errorSym, localsArraySym, stmtList)
+    localsArrayLen = max(localsArrayLen, numLocalsUsed)
+    stmtList.add code
+    # maybe there is a better mechanism disable errors for statement after return
+    if code[^1].kind != nnkReturnStmt:
+      stmtList.add nnkBreakStmt.newTree(outerBlockLabel)
+
+    outerStmtList.add quote do:
+      var `errorSym`: MatchingError
+      block `blockLabel`:
+        `stmtList`
+
+  if elseBranch != nil:
+    if outerErrorSym != nil:
+      outerStmtList.add quote do:
+        let `outerErrorSym` = @`errorSymbols`
+        `elseBranch`
+    else:
+      outerStmtList.add elseBranch
+
+  else:
+    if errorSymbols.len == 1:
+      # there is only one of branch and no else branch
+      # the error message can be very precise here.
+      let errorSym = errorSymbols[0]
+      outerStmtList.add quote do:
+        failWithMatchingError(`errorSym`)
+    else:
+
+      var patterns: string = ""
+      for i in beginBranches ..< endBranches:
+        let ofBranch = args[i]
+        let pattern = ofBranch[0]
+        patterns.add pattern.repr
+        patterns.add "\n"
+
+      let patternsLit = newLit(patterns)
+      outerStmtList.add quote do:
+        error("Ast pattern mismatch: got " & `astSym`.lispRepr & "\nbut expected one of:\n" & `patternsLit`, `astSym`)
+
+  let lengthLit = newLit(localsArrayLen)
+  result = quote do:
+    block `outerBlockLabel`:
+      let `astSym` = `astExpr`
+      var `localsArraySym`: array[`lengthLit`, NimNode]
+      `outerStmtList`
+
+  debug result.repr
+
+proc recursiveNodeVisiting*(arg: NimNode, callback: proc(arg: NimNode): bool) =
+  ## if `callback` returns true, visitor continues to visit the
+  ## children of `arg` otherwise it stops.
+  if callback(arg):
+    for child in arg:
+      recursiveNodeVisiting(child, callback)
+
+macro matchAstRecursive*(ast: NimNode; args: varargs[untyped]): untyped =
+  # Does not recurse further on matched nodes.
+  if args[^1].kind == nnkElse:
+    error("Recursive matching with an else branch is pointless.", args[^1])
+
+  let visitor = genSym(nskProc, "visitor")
+  let visitorArg = genSym(nskParam, "arg")
+
+  let visitorStmtList = newStmtList()
+
+  let matchingSection = genSym(nskLabel, "matchingSection")
+
+  let localsArraySym = genSym(nskVar, "locals")
+  let branchError = genSym(nskVar, "branchError")
+  var localsArrayLen = 0
+
+  for ofBranch in args:
+    ofBranch.expectKind(nnkOfBranch)
+    ofBranch.expectLen(2)
+    let pattern = ofBranch[0]
+    let code = ofBranch[1]
+    code.expectkind(nnkStmtList)
+
+    let stmtList = newStmtList()
+    let matchingBranch = genSym(nskLabel, "matchingBranch")
+
+    let numLocalsUsed = generateMatchingCode(visitorArg, pattern, 0, matchingBranch, branchError, localsArraySym, stmtList)
+    localsArrayLen = max(localsArrayLen, numLocalsUsed)
+
+    stmtList.add code
+    stmtList.add nnkBreakStmt.newTree(matchingSection)
+
+
+    visitorStmtList.add quote do:
+      `branchError`.kind = NoError
+      block `matchingBranch`:
+        `stmtList`
+
+  let resultIdent = ident"result"
+
+  let visitingProc = bindSym"recursiveNodeVisiting"
+  let lengthLit = newLit(localsArrayLen)
+
+  result = quote do:
+    proc `visitor`(`visitorArg`: NimNode): bool =
+      block `matchingSection`:
+        var `localsArraySym`: array[`lengthLit`, NimNode]
+        var `branchError`: MatchingError
+        `visitorStmtList`
+        `resultIdent` = true
+
+    `visitingProc`(`ast`, `visitor`)
+
+  debug result.repr
+
+################################################################################
+################################# Example Code #################################
+################################################################################
+
+when isMainModule:
+  static:
+    let mykinds = {nnkIdent, nnkCall}
+
+  macro foo(arg: untyped): untyped =
+    matchAst(arg, matchError):
+    of nnkStmtList(nnkIdent, nnkIdent, nnkIdent):
+      echo(88*88+33*33)
+    of nnkStmtList(
+      _(
+        nnkIdentDefs(
+          ident"a",
+          nnkEmpty, nnkIntLit(intVal = 123)
+        )
+      ),
+      _,
+      nnkForStmt(
+        nnkIdent(strVal = "i"),
+        nnkInfix,
+        `mysym` @ nnkStmtList
+      )
+    ):
+      echo "The AST did match!!!"
+      echo "The matched sub tree is the following:"
+      echo mysym.lispRepr
+    #else:
+    #  echo "sadly the AST did not match :("
+    #  echo arg.treeRepr
+    #  failWithMatchingError(matchError[1])
+
+  foo:
+    let a = 123
+    let b = 342
+    for i in a ..< b:
+      echo "Hallo", i
+
+  static:
+
+    var ast = quote do:
+      type
+        A[T: static[int]] = object
+
+    ast = ast[0]
+    ast.matchAst(err):  # this is a sub ast for this a findAst or something like that is useful
+    of nnkTypeDef(_, nnkGenericParams( nnkIdentDefs( nnkIdent(strVal = "T"), `staticTy`, nnkEmpty )), _):
+      echo "`", staticTy.repr, "` used to be of nnkStaticTy, now it is ", staticTy.kind, " with ", staticTy[0].repr
+    ast = quote do:
+      if cond1: expr1 elif cond2: expr2 else: expr3
+
+    ast.matchAst:
+    of {nnkIfExpr, nnkIfStmt}(
+      {nnkElifExpr, nnkElifBranch}(`cond1`, `expr1`),
+      {nnkElifExpr, nnkElifBranch}(`cond2`, `expr2`),
+      {nnkElseExpr, nnkElse}(`expr3`)
+    ):
+      echo "ok"
+
+    let ast2 = nnkStmtList.newTree( newLit(1) )
+
+    ast2.matchAst:
+    of nnkIntLit( 1 ):
+      echo "fail"
+    of nnkStmtList( 1 ):
+      echo "ok"
+
+    ast = bindSym"[]"
+    ast.matchAst(errors):
+    of nnkClosedSymChoice(strVal = "[]"):
+      echo "fail, this is the wrong syntax, a sym choice does not have a `strVal` member."
+    of ident"[]":
+      echo "ok"
+
+    const myConst = 123
+    ast = newLit(123)
+
+    ast.matchAst:
+    of _(intVal = myConst):
+      echo "ok"
+
+    macro testRecCase(ast: untyped): untyped =
+      ast.matchAstRecursive:
+      of nnkIdentDefs(`a`,`b`,`c`):
+        echo "got ident defs a: ", a.repr, " b: ", b.repr, " c: ", c.repr
+      of ident"m":
+        echo "got the ident m"
+
+    testRecCase:
+      type Obj[T] {.inheritable.} = object
+        name: string
+        case isFat: bool
+        of true:
+          m: array[100_000, T]
+        of false:
+          m: array[10, T]
+
+
+    macro testIfCondition(ast: untyped): untyped =
+      let literals = nnkBracket.newTree
+      ast.matchAstRecursive:
+      of `intLit` @ nnkIntLit |= intLit.intVal > 5:
+        literals.add intLit
+
+      let literals2 = quote do:
+        [6,7,8,9]
+
+      doAssert literals2 == literals
+
+    testIfCondition([1,6,2,7,3,8,4,9,5,0,"123"])
diff --git a/tests/astoverload/tastoverload1.nim b/tests/astoverload/tastoverload1.nim
new file mode 100644
index 000000000..c8705547a
--- /dev/null
+++ b/tests/astoverload/tastoverload1.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''string literal
+no string literal
+no string literal'''
+"""
+
+proc optLit(a: string{lit}) =
+  echo "string literal"
+
+proc optLit(a: string) =
+  echo "no string literal"
+
+const
+  constant = "abc"
+
+var
+  variable = "xyz"
+
+optLit("literal")
+optLit(constant)
+optLit(variable)
diff --git a/tests/astspec/tastspec.nim b/tests/astspec/tastspec.nim
new file mode 100644
index 000000000..c99d8ec79
--- /dev/null
+++ b/tests/astspec/tastspec.nim
@@ -0,0 +1,1119 @@
+discard """
+action: compile
+"""
+
+# this test should ensure that the AST doesn't change slightly without it getting noticed.
+
+import ../ast_pattern_matching
+
+template expectNimNode(arg: untyped): NimNode = arg
+  ## This template here is just to be injected by `myquote`, so that
+  ## a nice error message appears when the captured symbols are not of
+  ## type `NimNode`.
+
+proc substitudeComments(symbols, values, n: NimNode): NimNode =
+  ## substitutes all nodes of kind nnkCommentStmt to parameter
+  ## symbols. Consumes the argument `n`.
+  if n.kind == nnkCommentStmt:
+    values.add newCall(bindSym"newCommentStmtNode", newLit(n.strVal))
+    # Gensym doesn't work for parameters. These identifiers won't
+    # clash unless an argument is constructed to clash here.
+    symbols.add ident("comment" & $values.len & "_XObBdOnh6meCuJK2smZV")
+    return symbols[^1]
+  for i in 0 ..< n.len:
+    n[i] = substitudeComments(symbols, values, n[i])
+  return n
+
+macro myquote*(args: varargs[untyped]): untyped =
+  expectMinLen(args, 1)
+
+  # This is a workaround for #10430 where comments are removed in
+  # template expansions. This workaround lifts all comments
+  # statements to be arguments of the temporary template.
+
+  let extraCommentSymbols = newNimNode(nnkBracket)
+  let extraCommentGenExpr = newNimNode(nnkBracket)
+  let body = substitudeComments(
+    extraCommentSymbols, extraCommentGenExpr, args[^1]
+  )
+
+  let formalParams = nnkFormalParams.newTree(ident"untyped")
+  for i in 0 ..< args.len-1:
+    formalParams.add nnkIdentDefs.newTree(
+      args[i], ident"untyped", newEmptyNode()
+    )
+  for sym in extraCommentSymbols:
+    formalParams.add nnkIdentDefs.newTree(
+      sym, ident"untyped", newEmptyNode()
+    )
+
+  let templateSym = genSym(nskTemplate)
+  let templateDef = nnkTemplateDef.newTree(
+    templateSym,
+    newEmptyNode(),
+    newEmptyNode(),
+    formalParams,
+    nnkPragma.newTree(ident"dirty"),
+    newEmptyNode(),
+    args[^1]
+  )
+
+  let templateCall = newCall(templateSym)
+  for i in 0 ..< args.len-1:
+    let symName = args[i]
+    # identifiers and quoted identifiers are allowed.
+    if symName.kind == nnkAccQuoted:
+      symName.expectLen 1
+      symName[0].expectKind nnkIdent
+    else:
+      symName.expectKind nnkIdent
+    templateCall.add newCall(bindSym"expectNimNode", symName)
+  for expr in extraCommentGenExpr:
+    templateCall.add expr
+  let getAstCall = newCall(bindSym"getAst", templateCall)
+  result = newStmtList(templateDef, getAstCall)
+
+
+macro testAddrAst(arg: typed): bool =
+  arg.expectKind nnkStmtListExpr
+  arg[0].expectKind(nnkVarSection)
+  arg[1].expectKind({nnkAddr, nnkCall})
+  result = newLit(arg[1].kind == nnkCall)
+
+const newAddrAst: bool = testAddrAst((var x: int; addr(x)))
+
+static:
+  echo "new addr ast: ", newAddrAst
+
+# TODO test on matching failures
+
+proc peelOff*(arg: NimNode, kinds: set[NimNodeKind]): NimNode {.compileTime.} =
+  ## Peel off  nodes of a specific kinds.
+  if arg.len == 1 and arg.kind in kinds:
+    arg[0].peelOff(kinds)
+  else:
+    arg
+
+proc peelOff*(arg: NimNode, kind: NimNodeKind): NimNode {.compileTime.} =
+  ## Peel off nodes of a specific kind.
+  if arg.len == 1 and arg.kind == kind:
+    arg[0].peelOff(kind)
+  else:
+    arg
+
+static:
+  template testPattern(pattern, astArg: untyped): untyped =
+    let ast = quote do: `astArg`
+    ast.matchAst:
+    of `pattern`:
+      echo "ok"
+
+  template testPatternFail(pattern, astArg: untyped): untyped =
+    let ast = quote do: `astArg`
+    ast.matchAst:
+    of `pattern`:
+      error("this should not match", ast)
+    else:
+      echo "OK"
+
+
+  testPattern nnkIntLit(intVal = 42), 42
+  testPattern nnkInt8Lit(intVal = 42), 42'i8
+  testPattern nnkInt16Lit(intVal = 42), 42'i16
+  testPattern nnkInt32Lit(intVal = 42), 42'i32
+  testPattern nnkInt64Lit(intVal = 42), 42'i64
+  testPattern nnkUInt8Lit(intVal = 42), 42'u8
+  testPattern nnkUInt16Lit(intVal = 42), 42'u16
+  testPattern nnkUInt32Lit(intVal = 42), 42'u32
+  testPattern nnkUInt64Lit(intVal = 42), 42'u64
+  #testPattern nnkFloat64Lit(floatVal = 42.0), 42.0
+  testPattern nnkFloat32Lit(floatVal = 42.0), 42.0'f32
+  #testPattern nnkFloat64Lit(floatVal = 42.0), 42.0'f64
+  testPattern nnkStrLit(strVal = "abc"), "abc"
+  testPattern nnkRStrLit(strVal = "abc"), r"abc"
+  testPattern nnkTripleStrLit(strVal = "abc"), """abc"""
+  testPattern nnkCharLit(intVal = 32), ' '
+  testPattern nnkNilLit(), nil
+  testPattern nnkIdent(strVal = "myIdentifier"), myIdentifier
+
+  testPatternFail nnkInt8Lit(intVal = 42), 42'i16
+  testPatternFail nnkInt16Lit(intVal = 42), 42'i8
+
+
+
+# this should be just `block` but it doesn't work that way anymore because of VM.
+macro scope(arg: untyped): untyped =
+  let procSym = genSym(nskProc)
+  result = quote do:
+    proc `procSym`() {.compileTime.} =
+      `arg`
+
+    `procSym`()
+
+static:
+  ## Command call
+  scope:
+
+    let ast = myquote:
+      echo "abc", "xyz"
+
+    ast.matchAst:
+    of nnkCommand(ident"echo", "abc", "xyz"):
+      echo "ok"
+
+  ## Call with ``()``
+
+  scope:
+    let ast = myquote:
+      echo("abc", "xyz")
+
+    ast.matchAst:
+    of nnkCall(ident"echo", "abc", "xyz"):
+      echo "ok"
+
+  ## Infix operator call
+
+  macro testInfixOperatorCall(ast: untyped): untyped =
+    ast.matchAst(errorSym):
+    of nnkInfix(
+      ident"&",
+      nnkStrLit(strVal = "abc"),
+      nnkStrLit(strVal = "xyz")
+    ):
+      echo "ok1"
+    of nnkInfix(
+      ident"+",
+      nnkIntLit(intVal = 5),
+      nnkInfix(
+        ident"*",
+        nnkIntLit(intVal = 3),
+        nnkIntLit(intVal = 4)
+      )
+    ):
+      echo "ok2"
+    of nnkCall(
+      nnkAccQuoted(
+        ident"+"
+      ),
+      nnkIntLit(intVal = 3),
+      nnkIntLit(intVal = 4)
+    ):
+      echo "ok3"
+
+  testInfixOperatorCall("abc" & "xyz")
+  testInfixOperatorCall(5 + 3 * 4)
+  testInfixOperatorCall(`+`(3, 4))
+
+
+  ## Prefix operator call
+
+  scope:
+
+    let ast = myquote:
+      ? "xyz"
+
+    ast.matchAst(err):
+    of nnkPrefix(
+      ident"?",
+      nnkStrLit(strVal = "xyz")
+    ):
+      echo "ok"
+
+
+  ## Postfix operator call
+
+  scope:
+
+    let ast = myquote:
+      proc identifier*
+
+    ast[0].matchAst(err):
+    of nnkPostfix(
+      ident"*",
+      ident"identifier"
+    ):
+      echo "ok"
+
+
+  ## Call with named arguments
+
+  macro testCallWithNamedArguments(ast: untyped): untyped =
+    ast.peelOff(nnkStmtList).matchAst:
+    of nnkCall(
+      ident"writeLine",
+      nnkExprEqExpr(
+        ident"file",
+        ident"stdout"
+      ),
+      nnkStrLit(strVal = "hallo")
+    ):
+      echo "ok"
+
+  testCallWithNamedArguments:
+    writeLine(file=stdout, "hallo")
+
+  ## Call with raw string literal
+  scope:
+    let ast = myquote:
+      echo"abc"
+
+
+    ast.matchAst(err):
+    of nnkCallStrLit(
+      ident"echo",
+      nnkRStrLit(strVal = "abc")
+    ):
+      echo "ok"
+
+  ## Dereference operator ``[]``
+
+  scope:
+    # The dereferece operator exists only on a typed ast.
+    macro testDereferenceOperator(ast: typed): untyped =
+      ast.matchAst(err):
+      of nnkDerefExpr(_):
+        echo "ok"
+
+    var x: ptr int
+    testDereferenceOperator(x[])
+
+
+
+  ## Addr operator
+
+  scope:
+    # The addr operator exists only on a typed ast.
+    macro testAddrOperator(ast: untyped): untyped =
+      echo ast.treeRepr
+      ast.matchAst(err):
+      of nnkAddr(ident"x"):
+        echo "old nim"
+      of nnkCall(ident"addr", ident"x"):
+        echo "ok"
+
+    var x: int
+    testAddrOperator(addr(x))
+
+
+  ## Cast operator
+
+  scope:
+
+    let ast = myquote:
+      cast[T](x)
+
+    ast.matchAst:
+    of nnkCast(ident"T", ident"x"):
+      echo "ok"
+
+
+  ## Object access operator ``.``
+
+  scope:
+
+    let ast = myquote:
+      x.y
+
+    ast.matchAst:
+    of nnkDotExpr(ident"x", ident"y"):
+      echo "ok"
+
+  ## Array access operator ``[]``
+
+  macro testArrayAccessOperator(ast: untyped): untyped =
+    ast.matchAst:
+    of nnkBracketExpr(ident"x", ident"y"):
+      echo "ok"
+
+  testArrayAccessOperator(x[y])
+
+  ## Parentheses
+
+  scope:
+    let ast = myquote:
+      (a + b) * c
+
+    ast.matchAst:
+    of nnkInfix(ident"*", nnkPar(nnkInfix(ident"+", ident"a", ident"b")), ident"c"):
+      echo "parentheses ok"
+
+  ## Tuple Constructors
+
+  scope:
+    let ast = myquote:
+      (1, 2, 3)
+      (a: 1, b: 2, c: 3)
+      (1,)
+      (a: 1)
+      ()
+
+    for it in ast:
+      echo it.lispRepr
+      it.matchAst:
+      of nnkTupleConstr(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
+        echo "simple tuple ok"
+      of nnkTupleConstr(
+        nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1)),
+        nnkExprColonExpr(ident"b", nnkIntLit(intVal = 2)),
+        nnkExprColonExpr(ident"c", nnkIntLit(intVal = 3))
+      ):
+        echo "named tuple ok"
+      of nnkTupleConstr(nnkIntLit(intVal = 1)):
+        echo "one tuple ok"
+      of nnkTupleConstr(nnkExprColonExpr(ident"a", nnkIntLit(intVal = 1))):
+        echo "named one tuple ok"
+      of nnkTupleConstr():
+       echo "empty tuple ok"
+
+  ## Curly braces
+
+  scope:
+
+    let ast = myquote:
+      {1, 2, 3}
+
+    ast.matchAst:
+    of nnkCurly(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      {a: 3, b: 5}
+
+    ast.matchAst:
+    of nnkTableConstr(
+      nnkExprColonExpr(ident"a", nnkIntLit(intVal = 3)),
+      nnkExprColonExpr(ident"b", nnkIntLit(intVal = 5))
+    ):
+      echo "ok"
+
+
+  ## Brackets
+
+  scope:
+
+    let ast = myquote:
+      [1, 2, 3]
+
+    ast.matchAst:
+    of nnkBracket(nnkIntLit(intVal = 1), nnkIntLit(intVal = 2), nnkIntLit(intVal = 3)):
+      echo "ok"
+
+
+  ## Ranges
+
+  scope:
+
+    let ast = myquote:
+      1..3
+
+    ast.matchAst:
+    of nnkInfix(
+      ident"..",
+      nnkIntLit(intVal = 1),
+      nnkIntLit(intVal = 3)
+    ):
+      echo "ok"
+
+
+  ## If expression
+
+  scope:
+
+    let ast = myquote:
+      if cond1: expr1 elif cond2: expr2 else: expr3
+
+    ast.matchAst:
+    of {nnkIfExpr, nnkIfStmt}(
+      {nnkElifExpr, nnkElifBranch}(`cond1`, `expr1`),
+      {nnkElifExpr, nnkElifBranch}(`cond2`, `expr2`),
+      {nnkElseExpr, nnkElse}(`expr3`)
+    ):
+      echo "ok"
+
+  ## Documentation Comments
+
+  scope:
+
+    let ast = myquote:
+      ## This is a comment
+      ## This is part of the first comment
+      stmt1
+      ## Yet another
+
+    ast.matchAst:
+    of nnkStmtList(
+      nnkCommentStmt(),
+      `stmt1`,
+      nnkCommentStmt()
+    ):
+      echo "ok"
+    else:
+      echo "warning!"
+      echo ast.treeRepr
+      echo "TEST causes no fail, because of a regression in Nim."
+
+  scope:
+    let ast = myquote:
+      {.emit: "#include <stdio.h>".}
+
+    ast.matchAst:
+    of nnkPragma(
+      nnkExprColonExpr(
+        ident"emit",
+        nnkStrLit(strVal = "#include <stdio.h>") # the "argument"
+      )
+    ):
+      echo "ok"
+
+  scope:
+    let ast = myquote:
+      {.pragma: cdeclRename, cdecl.}
+
+    ast.matchAst:
+    of nnkPragma(
+      nnkExprColonExpr(
+        ident"pragma", # this is always first when declaring a new pragma
+        ident"cdeclRename" # the name of the pragma
+      ),
+      ident"cdecl"
+    ):
+      echo "ok"
+
+
+
+  scope:
+    let ast = myquote:
+      if cond1:
+        stmt1
+      elif cond2:
+        stmt2
+      elif cond3:
+        stmt3
+      else:
+        stmt4
+
+    ast.matchAst:
+    of nnkIfStmt(
+      nnkElifBranch(`cond1`, `stmt1`),
+      nnkElifBranch(`cond2`, `stmt2`),
+      nnkElifBranch(`cond3`, `stmt3`),
+      nnkElse(`stmt4`)
+    ):
+      echo "ok"
+
+
+
+  scope:
+    let ast = myquote:
+      x = 42
+
+    ast.matchAst:
+    of nnkAsgn(ident"x", nnkIntLit(intVal = 42)):
+      echo "ok"
+
+
+
+  scope:
+    let ast = myquote:
+      stmt1
+      stmt2
+      stmt3
+
+    ast.matchAst:
+    of nnkStmtList(`stmt1`, `stmt2`, `stmt3`):
+      assert stmt1.strVal == "stmt1"
+      assert stmt2.strVal == "stmt2"
+      assert stmt3.strVal == "stmt3"
+      echo "ok"
+
+  ## Case statement
+
+  scope:
+
+    let ast = myquote:
+      case expr1
+      of expr2, expr3..expr4:
+        stmt1
+      of expr5:
+        stmt2
+      elif cond1:
+        stmt3
+      else:
+        stmt4
+
+    ast.matchAst:
+    of nnkCaseStmt(
+      `expr1`,
+      nnkOfBranch(`expr2`, {nnkRange, nnkInfix}(_, `expr3`, `expr4`), `stmt1`),
+      nnkOfBranch(`expr5`, `stmt2`),
+      nnkElifBranch(`cond1`, `stmt3`),
+      nnkElse(`stmt4`)
+    ):
+      echo "ok"
+
+  ## While statement
+
+  scope:
+
+    let ast = myquote:
+      while expr1:
+        stmt1
+
+    ast.matchAst:
+    of nnkWhileStmt(`expr1`, `stmt1`):
+      echo "ok"
+
+
+  ## For statement
+
+  scope:
+
+    let ast = myquote:
+      for ident1, ident2 in expr1:
+        stmt1
+
+    ast.matchAst:
+    of nnkForStmt(`ident1`, `ident2`, `expr1`, `stmt1`):
+      echo "ok"
+
+
+  ## Try statement
+
+  scope:
+
+    let ast = myquote:
+      try:
+        stmt1
+      except e1, e2:
+        stmt2
+      except e3:
+        stmt3
+      except:
+        stmt4
+      finally:
+        stmt5
+
+    ast.matchAst:
+    of nnkTryStmt(
+      `stmt1`,
+      nnkExceptBranch(`e1`, `e2`, `stmt2`),
+      nnkExceptBranch(`e3`, `stmt3`),
+      nnkExceptBranch(`stmt4`),
+      nnkFinally(`stmt5`)
+    ):
+      echo "ok"
+
+
+  ## Return statement
+
+  scope:
+
+    let ast = myquote:
+      return expr1
+
+    ast.matchAst:
+    of nnkReturnStmt(`expr1`):
+      echo "ok"
+
+
+  ## Continue statement
+
+  scope:
+    let ast = myquote:
+      continue
+
+    ast.matchAst:
+    of nnkContinueStmt:
+      echo "ok"
+
+  ## Break statement
+
+  scope:
+
+    let ast = myquote:
+      break otherLocation
+
+    ast.matchAst:
+    of nnkBreakStmt(ident"otherLocation"):
+      echo "ok"
+
+  ## Block statement
+
+  scope:
+
+    template blockStatement {.dirty.} =
+      block name:
+        discard
+
+    let ast = getAst(blockStatement())
+
+    ast.matchAst:
+    of nnkBlockStmt(ident"name", nnkStmtList):
+      echo "ok"
+
+  ## Asm statement
+
+  scope:
+
+    let ast = myquote:
+      asm """some asm"""
+
+    ast.matchAst:
+    of nnkAsmStmt(
+      nnkEmpty(), # for pragmas
+      nnkTripleStrLit(strVal = "some asm"),
+    ):
+      echo "ok"
+
+  ## Import section
+
+  scope:
+
+    let ast = myquote:
+      import math
+
+    ast.matchAst:
+    of nnkImportStmt(ident"math"):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      import math except pow
+
+    ast.matchAst:
+    of nnkImportExceptStmt(ident"math",ident"pow"):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      import strutils as su
+
+    ast.matchAst:
+    of nnkImportStmt(
+      nnkInfix(
+        ident"as",
+        ident"strutils",
+        ident"su"
+      )
+    ):
+      echo "ok"
+
+  ## From statement
+
+  scope:
+
+    let ast = myquote:
+      from math import pow
+
+    ast.matchAst:
+    of nnkFromStmt(ident"math", ident"pow"):
+      echo "ok"
+
+  ## Export statement
+
+  scope:
+
+    let ast = myquote:
+      export unsigned
+
+    ast.matchAst:
+    of nnkExportStmt(ident"unsigned"):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      export math except pow # we're going to implement our own exponentiation
+
+    ast.matchAst:
+    of nnkExportExceptStmt(ident"math",ident"pow"):
+      echo "ok"
+
+  ## Include statement
+
+  scope:
+
+    let ast = myquote:
+      include blocks
+
+    ast.matchAst:
+    of nnkIncludeStmt(ident"blocks"):
+      echo "ok"
+
+  ## Var section
+
+  scope:
+
+    let ast = myquote:
+      var a = 3
+
+    ast.matchAst:
+    of nnkVarSection(
+      nnkIdentDefs(
+        ident"a",
+        nnkEmpty(), # or nnkIdent(...) if the variable declares the type
+        nnkIntLit(intVal = 3),
+      )
+    ):
+      echo "ok"
+
+  ## Let section
+
+  scope:
+
+    let ast = myquote:
+      let a = 3
+
+    ast.matchAst:
+    of nnkLetSection(
+      nnkIdentDefs(
+        ident"a",
+        nnkEmpty(), # or nnkIdent(...) for the type
+        nnkIntLit(intVal = 3),
+      )
+    ):
+      echo "ok"
+
+  ## Const section
+
+  scope:
+
+    let ast = myquote:
+      const a = 3
+
+    ast.matchAst:
+    of nnkConstSection(
+      nnkConstDef( # not nnkConstDefs!
+        ident"a",
+        nnkEmpty(), # or nnkIdent(...) if the variable declares the type
+        nnkIntLit(intVal = 3), # required in a const declaration!
+      )
+    ):
+      echo "ok"
+
+  ## Type section
+
+  scope:
+
+    let ast = myquote:
+      type A = int
+
+    ast.matchAst:
+    of nnkTypeSection(
+      nnkTypeDef(
+        ident"A",
+        nnkEmpty(),
+        ident"int"
+      )
+    ):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      type MyInt = distinct int
+
+    ast.peelOff({nnkTypeSection}).matchAst:
+    of# ...
+      nnkTypeDef(
+      ident"MyInt",
+      nnkEmpty(),
+      nnkDistinctTy(
+        ident"int"
+      )
+    ):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      type A[T] = expr1
+
+    ast.matchAst:
+    of nnkTypeSection(
+      nnkTypeDef(
+        ident"A",
+        nnkGenericParams(
+          nnkIdentDefs(
+            ident"T",
+            nnkEmpty(), # if the type is declared with options, like
+                        # ``[T: SomeInteger]``, they are given here
+            nnkEmpty()
+          )
+        ),
+        `expr1`
+      )
+    ):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      type IO = object of RootObj
+
+    ast.peelOff(nnkTypeSection).matchAst:
+    of nnkTypeDef(
+      ident"IO",
+      nnkEmpty(),
+      nnkObjectTy(
+        nnkEmpty(), # no pragmas here
+        nnkOfInherit(
+          ident"RootObj" # inherits from RootObj
+        ),
+        nnkEmpty()
+      )
+    ):
+      echo "ok"
+
+  scope:
+    macro testRecCase(ast: untyped): untyped =
+      ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst:
+      of nnkTypeDef(
+        nnkPragmaExpr(
+          ident"Obj",
+          nnkPragma(ident"inheritable")
+        ),
+        nnkGenericParams(
+        nnkIdentDefs(
+          ident"T",
+          nnkEmpty(),
+          nnkEmpty())
+        ),
+        nnkObjectTy(
+        nnkEmpty(),
+        nnkEmpty(),
+        nnkRecList( # list of object parameters
+          nnkIdentDefs(
+            ident"name",
+            ident"string",
+            nnkEmpty()
+          ),
+          nnkRecCase( # case statement within object (not nnkCaseStmt)
+            nnkIdentDefs(
+              ident"isFat",
+              ident"bool",
+              nnkEmpty()
+            ),
+            nnkOfBranch(
+              ident"true",
+              nnkRecList( # again, a list of object parameters
+                nnkIdentDefs(
+                  ident"m",
+                  nnkBracketExpr(
+                    ident"array",
+                    nnkIntLit(intVal = 100000),
+                    ident"T"
+                  ),
+                  nnkEmpty()
+                )
+              )
+            ),
+            nnkOfBranch(
+              ident"false",
+              nnkRecList(
+                nnkIdentDefs(
+                  ident"m",
+                  nnkBracketExpr(
+                    ident"array",
+                    nnkIntLit(intVal = 10),
+                    ident"T"
+                  ),
+                  nnkEmpty()
+                  )
+                )
+              )
+            )
+          )
+        )
+      ):
+        echo "ok"
+
+    testRecCase:
+      type Obj[T] {.inheritable.} = object
+        name: string
+        case isFat: bool
+        of true:
+          m: array[100_000, T]
+        of false:
+          m: array[10, T]
+
+  scope:
+
+    let ast = myquote:
+      type X = enum
+        First
+
+    ast.peelOff({nnkStmtList, nnkTypeSection})[2].matchAst:
+    of nnkEnumTy(
+      nnkEmpty(),
+      ident"First" # you need at least one nnkIdent or the compiler complains
+    ):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      type Con = concept x,y,z
+        (x & y & z) is string
+
+    ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst:
+    of nnkTypeDef(_, _, nnkTypeClassTy(nnkArgList, _, _, nnkStmtList)):
+      # note this isn't nnkConceptTy!
+      echo "ok"
+
+
+  scope:
+
+    let astX = myquote:
+      type
+        A[T: static[int]] = object
+
+    let ast = astX.peelOff({nnkStmtList, nnkTypeSection})
+
+    ast.matchAst(err):  # this is a sub ast for this a findAst or something like that is useful
+    of nnkTypeDef(_, nnkGenericParams( nnkIdentDefs( ident"T", nnkCall( ident"[]", ident"static", _ ), _ )), _):
+      echo "ok"
+    else:
+      echo "foobar"
+      echo ast.treeRepr
+
+
+  scope:
+    let ast = myquote:
+      type MyProc[T] = proc(x: T)
+
+    ast.peelOff({nnkStmtList, nnkTypeSection}).matchAst(err):
+    of nnkTypeDef(
+      ident"MyProc",
+      nnkGenericParams, # here, not with the proc
+      nnkProcTy( # behaves like a procedure declaration from here on
+        nnkFormalParams, _
+      )
+    ):
+      echo "ok"
+
+  ## Mixin statement
+
+  macro testMixinStatement(ast: untyped): untyped =
+    ast.peelOff(nnkStmtList).matchAst:
+    of nnkMixinStmt(ident"x"):
+      echo "ok"
+
+  testMixinStatement:
+    mixin x
+
+  ## Bind statement
+
+
+  macro testBindStmt(ast: untyped): untyped =
+    ast[0].matchAst:
+    of `node` @ nnkBindStmt(ident"x"):
+      echo "ok"
+
+  testBindStmt:
+    bind x
+
+  ## Procedure declaration
+
+  macro testProcedureDeclaration(ast: untyped): untyped =
+    # NOTE this is wrong in astdef
+
+    ast.peelOff(nnkStmtList).matchAst:
+    of nnkProcDef(
+      nnkPostfix(ident"*", ident"hello"), # the exported proc name
+      nnkEmpty, # patterns for term rewriting in templates and macros (not procs)
+      nnkGenericParams( # generic type parameters, like with type declaration
+        nnkIdentDefs(
+          ident"T",
+          ident"SomeInteger", _
+        )
+      ),
+      nnkFormalParams(
+        ident"int", # the first FormalParam is the return type. nnkEmpty if there is none
+        nnkIdentDefs(
+          ident"x",
+          ident"int", # type type (required for procs, not for templates)
+          nnkIntLit(intVal = 3) # a default value
+        ),
+        nnkIdentDefs(
+          ident"y",
+          ident"float32",
+          nnkEmpty
+        )
+      ),
+      nnkPragma(ident"inline"),
+      nnkEmpty, # reserved slot for future use
+      `meat` @ nnkStmtList # the meat of the proc
+    ):
+      echo "ok got meat: ", meat.lispRepr
+
+  testProcedureDeclaration:
+    proc hello*[T: SomeInteger](x: int = 3, y: float32): int {.inline.} = discard
+
+  scope:
+    var ast = myquote:
+      proc foobar(a, b: int): void
+
+    ast = ast[3]
+
+    ast.matchAst:  # sub expression
+    of nnkFormalParams(
+      _, # return would be here
+      nnkIdentDefs(
+        ident"a", # the first parameter
+        ident"b", # directly to the second parameter
+        ident"int", # their shared type identifier
+        nnkEmpty, # default value would go here
+      )
+    ):
+      echo "ok"
+
+  scope:
+
+    let ast = myquote:
+      proc hello(): var int
+
+    ast[3].matchAst: # subAst
+    of nnkFormalParams(
+      nnkVarTy(
+        ident"int"
+      )
+    ):
+      echo "ok"
+
+  ## Iterator declaration
+
+  scope:
+
+    let ast = myquote:
+      iterator nonsense[T](x: seq[T]): float {.closure.} =
+        discard
+
+    ast.matchAst:
+    of nnkIteratorDef(ident"nonsense", nnkEmpty, _, _, _, _, _):
+      echo "ok"
+
+  ## Converter declaration
+
+  scope:
+
+    let ast = myquote:
+      converter toBool(x: float): bool
+
+    ast.matchAst:
+    of nnkConverterDef(ident"toBool",_,_,_,_,_,_):
+      echo "ok"
+
+  ## Template declaration
+
+  scope:
+    let ast = myquote:
+      template optOpt{expr1}(a: int): int
+
+    ast.matchAst:
+    of nnkTemplateDef(ident"optOpt", nnkStmtList(`expr1`), _, _, _, _, _):
+      echo "ok"
diff --git a/tests/async/hello.txt b/tests/async/hello.txt
new file mode 100644
index 000000000..854d6c20a
--- /dev/null
+++ b/tests/async/hello.txt
@@ -0,0 +1 @@
+hello humans!
\ No newline at end of file
diff --git a/tests/async/nim.cfg b/tests/async/nim.cfg
new file mode 100644
index 000000000..be50f572c
--- /dev/null
+++ b/tests/async/nim.cfg
@@ -0,0 +1 @@
+--experimental:strictEffects
diff --git a/tests/async/t11558.nim b/tests/async/t11558.nim
new file mode 100644
index 000000000..99961e7b6
--- /dev/null
+++ b/tests/async/t11558.nim
@@ -0,0 +1,13 @@
+discard """
+output: "Hello\n9"
+"""
+import std/asyncdispatch
+
+proc foo(): Future[string] {.async.} =
+  "Hello"
+
+proc bar(): Future[int] {.async.} =
+  result = 9
+
+echo waitFor foo()
+echo waitFor bar()
diff --git a/tests/async/t12221.nim b/tests/async/t12221.nim
new file mode 100644
index 000000000..e8bd9c11a
--- /dev/null
+++ b/tests/async/t12221.nim
@@ -0,0 +1,40 @@
+import asyncdispatch, os, times
+
+proc doubleSleep(hardSleep: int) {.async.} =
+  await sleepAsync(50)
+  sleep(hardSleep)
+
+template assertTime(target, timeTook: float): untyped {.dirty.} =
+  doAssert(timeTook*1000 > target - 1000, "Took too short, should've taken " &
+    $target & "ms, but took " & $(timeTook*1000) & "ms")
+  doAssert(timeTook*1000 < target + 1000, "Took too long, should've taken " &
+    $target & "ms, but took " & $(timeTook*1000) & "ms")
+
+var
+  start: float
+  fut: Future[void]
+
+# NOTE: this uses poll(3000) to limit timing error potential.
+start = epochTime()
+fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20)
+while not fut.finished:
+  poll(1000)
+assertTime(150, epochTime() - start)
+
+start = epochTime()
+fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(50)
+while not fut.finished:
+  poll(1000)
+assertTime(200, epochTime() - start)
+
+start = epochTime()
+fut = sleepAsync(40) and sleepAsync(100) and doubleSleep(20) and sleepAsync(200)
+while not fut.finished:
+  poll(1000)
+assertTime(300, epochTime() - start)
+
+start = epochTime()
+fut = (sleepAsync(40) and sleepAsync(100) and doubleSleep(20)) or sleepAsync(300)
+while not fut.finished:
+  poll(1000)
+assertTime(150, epochTime() - start)
diff --git a/tests/async/t13889.nim b/tests/async/t13889.nim
new file mode 100644
index 000000000..fe75fe38a
--- /dev/null
+++ b/tests/async/t13889.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''
+believer Foo is saved:true
+believer Bar is saved:true
+believer Baz is saved:true
+'''
+"""
+
+import asyncdispatch
+
+var
+  promise = newFuture[bool]()
+
+proc believers(name: string) {.async.} =
+  let v = await promise
+  echo "believer " & name & " is saved:" & $v
+
+asyncCheck believers("Foo")
+asyncCheck believers("Bar")
+asyncCheck believers("Baz")
+
+proc savior() {.async.} =
+  await sleepAsync(50)
+  complete(promise, true)
+  await sleepAsync(50) # give enough time to see who was saved
+
+waitFor(savior())
diff --git a/tests/async/t14820.nim b/tests/async/t14820.nim
new file mode 100644
index 000000000..359884468
--- /dev/null
+++ b/tests/async/t14820.nim
@@ -0,0 +1,25 @@
+discard """
+output: '''
+iteration: 1
+iteration: 2
+iteration: 3
+iteration: 4
+async done
+iteration: 5
+'''
+"""
+
+import asyncdispatch, times
+
+var done = false
+proc somethingAsync() {.async.} =
+  yield sleepAsync 5000
+  echo "async done"
+  done = true
+  
+asyncCheck somethingAsync()
+var count = 0
+while not done:
+  count += 1
+  drain 1000
+  echo "iteration: ", count 
diff --git a/tests/async/t15148.nim b/tests/async/t15148.nim
new file mode 100644
index 000000000..ba14c1157
--- /dev/null
+++ b/tests/async/t15148.nim
@@ -0,0 +1,12 @@
+import asyncdispatch, asyncfile, os
+
+const Filename = "t15148.txt"
+
+proc saveEmpty() {.async.} =
+  let
+    text = ""
+    file = openAsync(Filename, fmWrite)
+  await file.write(text)
+  file.close()
+
+waitFor saveEmpty()
diff --git a/tests/async/t15804.nim b/tests/async/t15804.nim
new file mode 100644
index 000000000..8de012196
--- /dev/null
+++ b/tests/async/t15804.nim
@@ -0,0 +1,15 @@
+import asyncdispatch
+
+type
+  Foo*[E] = ref object 
+    op: proc(): Future[bool] {.gcsafe.}
+
+proc newFoo*[E](): Foo[E] =
+  result = Foo[E]()
+  result.op = proc(): Future[bool] {.gcsafe,async.} =
+    await sleepAsync(100)
+    result = false
+
+when isMainModule:
+  let f = newFoo[int]()
+  echo waitFor f.op()
diff --git a/tests/async/t17045.nim b/tests/async/t17045.nim
new file mode 100644
index 000000000..2b5acf48a
--- /dev/null
+++ b/tests/async/t17045.nim
@@ -0,0 +1,28 @@
+discard """
+  targets: "c cpp"
+  matrix: "--mm:refc; --mm:arc"
+"""
+
+type Future = ref object
+
+iterator paths: string = 
+  # without "when nimvm" everything works
+  when nimvm:
+    yield "test.md"
+  else:
+    yield "test.md"
+
+template await(f: Future): string =
+  # need this yield, also the template has to return something
+  yield f
+  "hello world"
+
+proc generatePostContextsAsync() =
+  iterator generatePostContextsAsyncIter(): Future {.closure.} =
+    for filePath in paths():
+      var temp = await Future()
+
+  # need this line
+  var nameIterVar = generatePostContextsAsyncIter
+
+generatePostContextsAsync()
\ No newline at end of file
diff --git a/tests/async/t20111.nim b/tests/async/t20111.nim
new file mode 100644
index 000000000..0aaa7d886
--- /dev/null
+++ b/tests/async/t20111.nim
@@ -0,0 +1,19 @@
+discard """
+  action: "run"
+"""
+import asyncdispatch
+type
+    Sync = object
+    Async = object
+    SyncRes = (Sync, string)
+    AsyncRes = (Async, string)
+
+proc foo(val: Sync | Async): Future[(Async, string) | (Sync, string)] {.multisync.} =
+    return (val, "hello")
+
+let
+  myAsync = Async()
+  mySync = Sync()
+
+doAssert typeof(waitFor foo(myAsync)) is AsyncRes
+doAssert typeof(foo(mySync)) is SyncRes
diff --git a/tests/async/t21447.nim b/tests/async/t21447.nim
new file mode 100644
index 000000000..e4f7ae31f
--- /dev/null
+++ b/tests/async/t21447.nim
@@ -0,0 +1,6 @@
+discard """
+  action: "compile"
+  cmd: "nim c -d:release -d:futureLogging $file"
+"""
+
+import std/asyncdispatch
diff --git a/tests/async/t21893.nim b/tests/async/t21893.nim
new file mode 100644
index 000000000..658cb02eb
--- /dev/null
+++ b/tests/async/t21893.nim
@@ -0,0 +1,13 @@
+discard """
+output: "@[97]\ntrue"
+"""
+
+import asyncdispatch
+
+proc test(): Future[bool] {.async.} =
+  const S4 = @[byte('a')]
+  echo S4
+  return true
+
+echo waitFor test()
+
diff --git a/tests/async/t22210.nim b/tests/async/t22210.nim
new file mode 100644
index 000000000..fcf939472
--- /dev/null
+++ b/tests/async/t22210.nim
@@ -0,0 +1,41 @@
+discard """
+output: '''
+stage 1
+stage 2
+stage 3
+(status: 200, data: "SOMEDATA")
+'''
+"""
+
+import std/asyncdispatch
+
+
+# bug #22210
+type
+  ClientResponse = object
+    status*: int
+    data*: string
+
+proc subFoo1(): Future[int] {.async.} =
+  await sleepAsync(100)
+  return 200
+
+proc subFoo2(): Future[string] {.async.} =
+  await sleepAsync(100)
+  return "SOMEDATA"
+
+proc testFoo(): Future[ClientResponse] {.async.} =
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    return ClientResponse(status: status, data: data)
+  finally:
+    echo "stage 1"
+    await sleepAsync(100)
+    echo "stage 2"
+    await sleepAsync(200)
+    echo "stage 3"
+
+when isMainModule:
+  echo waitFor testFoo()
\ No newline at end of file
diff --git a/tests/async/t22210_2.nim b/tests/async/t22210_2.nim
new file mode 100644
index 000000000..9db664a32
--- /dev/null
+++ b/tests/async/t22210_2.nim
@@ -0,0 +1,73 @@
+import std/asyncdispatch
+
+
+# bug #22210
+type
+  ClientResponse = object
+    status*: int
+    data*: string
+
+proc subFoo1(): Future[int] {.async.} =
+  await sleepAsync(100)
+  return 200
+
+proc subFoo2(): Future[string] {.async.} =
+  await sleepAsync(100)
+  return "SOMEDATA"
+
+
+proc testFoo2(): Future[ClientResponse] {.async.} =
+  var flag = 0
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    result = ClientResponse(status: status, data: data)
+  finally:
+    inc flag
+    await sleepAsync(100)
+    inc flag
+    await sleepAsync(200)
+    inc flag
+  doAssert flag == 3
+
+discard waitFor testFoo2()
+
+proc testFoo3(): Future[ClientResponse] {.async.} =
+  var flag = 0
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    if false:
+      return ClientResponse(status: status, data: data)
+  finally:
+    inc flag
+    await sleepAsync(100)
+    inc flag
+    await sleepAsync(200)
+    inc flag
+  doAssert flag == 3
+
+discard waitFor testFoo3()
+
+
+proc testFoo4(): Future[ClientResponse] {.async.} =
+  var flag = 0
+  try:
+    let status = await subFoo1()
+    doAssert(status == 200)
+    let data = await subFoo2()
+    if status == 200:
+      return ClientResponse(status: status, data: data)
+    else:
+      return ClientResponse()
+  finally:
+    inc flag
+    await sleepAsync(100)
+    inc flag
+    await sleepAsync(200)
+    inc flag
+  doAssert flag == 3
+
+discard waitFor testFoo4()
diff --git a/tests/async/t3075.nim b/tests/async/t3075.nim
new file mode 100644
index 000000000..d26aa0a36
--- /dev/null
+++ b/tests/async/t3075.nim
@@ -0,0 +1,29 @@
+import asyncnet, asyncdispatch, strtabs
+
+type
+  WebSocketCallback = proc (client: WebSocket, message: WebSocketMessage) {.closure, gcsafe.}
+  WebSocketRecvClosure = proc (ws: WebSocket): Future[string] {.gcsafe.}
+
+  WebSocketMessage = ref object
+    msg: string
+
+  WebSocket = ref object
+    socket:     AsyncSocket
+    header:     StringTableRef
+    onOpen:     WebSocketCallback
+    onMessage:  WebSocketCallback
+    onClose:    WebSocketCallback
+
+proc recv(ws: WebSocket, p: WebSocketRecvClosure): Future[string] {.async.}=
+  if not ws.socket.isClosed():
+    result = await ws.p()
+    if result == "":
+      ws.socket.close()
+      if ws.onClose != nil:
+        ws.onClose(ws, nil)
+  return result
+
+proc reÑvSize(ws: WebSocket, size: int): Future[string] {.async.} =
+  proc recvSizeClosure(ws: WebSocket): Future[string] {.async.} =
+    return await ws.socket.recv(size)
+  return await ws.recv(recvSizeClosure)
diff --git a/tests/async/t6846.nim b/tests/async/t6846.nim
new file mode 100644
index 000000000..7fe38f3b3
--- /dev/null
+++ b/tests/async/t6846.nim
@@ -0,0 +1,15 @@
+discard """
+  exitcode: 0
+  output: "hello world"
+  disabled: windows
+"""
+
+import asyncdispatch
+import asyncfile
+
+var asyncStdout = 1.AsyncFD.newAsyncFile()
+proc doStuff: Future[void] {.async.} =
+  await asyncStdout.write "hello world\n"
+
+let fut = doStuff()
+doAssert fut.finished, "Poll is needed unnecessarily. See #6846."
diff --git a/tests/async/t7192.nim b/tests/async/t7192.nim
new file mode 100644
index 000000000..9ac0e07c0
--- /dev/null
+++ b/tests/async/t7192.nim
@@ -0,0 +1,14 @@
+discard """
+output: '''
+testCallback()
+'''
+"""
+
+import asyncdispatch
+
+proc testCallback() =
+  echo "testCallback()"
+
+when true:
+  callSoon(testCallback)
+  poll()
diff --git a/tests/async/t7758.nim b/tests/async/t7758.nim
new file mode 100644
index 000000000..fe6d32ad3
--- /dev/null
+++ b/tests/async/t7758.nim
@@ -0,0 +1,21 @@
+import asyncdispatch
+import std/unittest
+
+proc task() {.async.} =
+  const tSleep = 40
+  await sleepAsync(tSleep)
+
+proc main() =
+  var counter = 0
+  var f = task()
+  while not f.finished:
+    inc(counter)
+    poll(10)
+
+  const slack = 1
+    # because there is overhead in `async` + `sleepAsync`
+    # as can be seen by increasing `tSleep` from 40 to 49, which increases the number
+    # of failures.
+  check counter <= 4 + slack
+
+for i in 0 .. 10: main()
diff --git a/tests/async/t8982.nim b/tests/async/t8982.nim
new file mode 100644
index 000000000..5face7edf
--- /dev/null
+++ b/tests/async/t8982.nim
@@ -0,0 +1,33 @@
+discard """
+output: '''
+timeout
+runForever should throw ValueError, this is expected
+'''
+"""
+
+
+import asyncdispatch
+
+proc failingAwaitable(p: int) {.async.} =
+  await sleepAsync(500)
+  if p > 0:
+    raise newException(Exception, "my exception")
+
+proc main() {.async.} =
+  let fut = failingAwaitable(1)
+  try:
+    await fut or sleepAsync(100)
+    if fut.finished:
+      echo "finished"
+    else:
+      echo "timeout"
+  except:
+    echo "failed"
+
+
+# Previously this would raise "An attempt was made to complete a Future more than once."
+try:
+  asyncCheck main()
+  runForever()
+except ValueError:
+  echo "runForever should throw ValueError, this is expected"
diff --git a/tests/async/t9201.nim b/tests/async/t9201.nim
new file mode 100644
index 000000000..5aaba7063
--- /dev/null
+++ b/tests/async/t9201.nim
@@ -0,0 +1,14 @@
+discard """
+  exitcode: 0
+"""
+
+# Derived from issue #9201
+import asyncdispatch, macros
+
+macro newAsyncProc(name: untyped): untyped =
+  expectKind name, nnkStrLit
+  let pName = genSym(nskProc, name.strVal)
+  result = getAst async quote do:
+    proc `pName`() = discard
+
+newAsyncProc("hello")
diff --git a/tests/async/tacceptcloserace.nim b/tests/async/tacceptcloserace.nim
new file mode 100644
index 000000000..fee6537d2
--- /dev/null
+++ b/tests/async/tacceptcloserace.nim
@@ -0,0 +1,36 @@
+discard """
+  exitcode: 0
+  output: ""
+"""
+
+import asyncdispatch, net, os, nativesockets
+
+# bug: https://github.com/nim-lang/Nim/issues/5279
+
+proc setupServerSocket(hostname: string, port: Port): AsyncFD =
+  let fd = createNativeSocket()
+  if fd == osInvalidSocket:
+    raiseOSError(osLastError())
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+  result = fd.AsyncFD
+  register(result)
+
+const port = Port(5614)
+for i in 0..100:
+  let serverFd = setupServerSocket("localhost", port)
+  serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
+    if not fut.failed:
+      fut.read().closeSocket()
+
+  var fd = createAsyncNativeSocket()
+  waitFor fd.connect("localhost", port)
+  serverFd.closeSocket()
+  fd.closeSocket()
diff --git a/tests/async/tasyncRecvLine.nim b/tests/async/tasyncRecvLine.nim
new file mode 100644
index 000000000..a13a171c3
--- /dev/null
+++ b/tests/async/tasyncRecvLine.nim
@@ -0,0 +1,53 @@
+discard """
+output: '''
+Hello World
+Hello World
+'''
+"""
+
+import asyncdispatch, asyncnet
+
+const recvLinePort = Port(6047)
+
+proc setupTestServer(): AsyncSocket =
+  result = newAsyncSocket()
+  result.setSockOpt(OptReuseAddr, true)
+  result.bindAddr(recvLinePort)
+  result.listen()
+
+proc testUnbuffered(): Future[void] {.async.} =
+  let serverSock = setupTestServer()
+  let serverAcceptClientFut = serverSock.accept()
+
+  let clientSock = newAsyncSocket(buffered = false)
+  let clientConnectFut = clientSock.connect("localhost", recvLinePort)
+
+  let serverAcceptedClient = await serverAcceptClientFut
+  await clientConnectFut
+
+  await serverAcceptedClient.send("Hello World\c\L")
+
+  echo await clientSock.recvLine()
+
+  clientSock.close()
+  serverSock.close()
+
+proc testBuffered(): Future[void] {.async.} =
+  let serverSock = setupTestServer()
+  let serverAcceptClientFut = serverSock.accept()
+
+  let clientSock = newAsyncSocket(buffered = true)
+  let clientConnectFut = clientSock.connect("localhost", recvLinePort)
+
+  let serverAcceptedClient = await serverAcceptClientFut
+  await clientConnectFut
+
+  await serverAcceptedClient.send("Hello World\c\L")
+
+  echo await clientSock.recvLine()
+
+  clientSock.close()
+  serverSock.close()
+
+waitFor testUnbuffered()
+waitFor testBuffered()
diff --git a/tests/async/tasync_forward.nim b/tests/async/tasync_forward.nim
new file mode 100644
index 000000000..99527032f
--- /dev/null
+++ b/tests/async/tasync_forward.nim
@@ -0,0 +1,18 @@
+
+import asyncdispatch
+
+# bug #1970
+
+proc foo {.async.}
+
+proc foo {.async.} =
+  discard
+
+# With additional pragmas:
+proc bar {.async, cdecl.}
+
+proc bar {.async.} =
+  discard
+
+proc verifyCdeclPresent(p: proc : Future[void] {.cdecl.}) = discard
+verifyCdeclPresent(bar)
diff --git a/tests/async/tasync_gcsafe.nim b/tests/async/tasync_gcsafe.nim
new file mode 100644
index 000000000..bc0eb4271
--- /dev/null
+++ b/tests/async/tasync_gcsafe.nim
@@ -0,0 +1,36 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  output: '''
+1
+2
+3
+'''
+"""
+
+doAssert compileOption("threads"), "this test will not do anything useful without --threads:on"
+
+import asyncdispatch
+
+var globalDummy: ref int
+proc gcUnsafeProc() =
+    if not globalDummy.isNil:
+        echo globalDummy[]
+    echo "1"
+
+proc gcSafeAsyncProcWithNoAnnotation() {.async.} =
+    echo "2"
+
+proc gcSafeAsyncProcWithAnnotation() {.gcsafe, async.} =
+    echo "3"
+
+proc gcUnsafeAsyncProc() {.async.} =
+    # We should be able to call gcUnsafe
+    gcUnsafeProc()
+
+    # We should be able to call async implicitly gcsafe
+    await gcSafeAsyncProcWithNoAnnotation()
+
+    # We should be able to call async explicitly gcsafe
+    await gcSafeAsyncProcWithAnnotation()
+
+waitFor gcUnsafeAsyncProc()
diff --git a/tests/async/tasync_gcunsafe.nim b/tests/async/tasync_gcunsafe.nim
new file mode 100644
index 000000000..f3e6bc691
--- /dev/null
+++ b/tests/async/tasync_gcunsafe.nim
@@ -0,0 +1,30 @@
+discard """
+  errormsg: "'anotherGCSafeAsyncProc (Async)' is not GC-safe as it calls 'asyncGCUnsafeProc'"
+  cmd: "nim c --threads:on $file"
+  file: "asyncmacro.nim"
+"""
+
+doAssert compileOption("threads"), "this test will not do anything useful without --threads:on"
+
+import asyncdispatch
+
+var globalDummy: ref int
+proc gcUnsafeProc() =
+    if not globalDummy.isNil:
+        echo globalDummy[]
+
+proc asyncExplicitlyGCSafeProc() {.gcsafe, async.} =
+    echo "hi"
+
+proc asyncImplicitlyGCSafeProc() {.async.} =
+    echo "hi"
+
+proc asyncGCUnsafeProc() {.async.} =
+    gcUnsafeProc()
+
+proc anotherGCSafeAsyncProc() {.async, gcsafe.} =
+    # We should be able to call other gcsafe procs
+    await asyncExplicitlyGCSafeProc()
+    await asyncImplicitlyGCSafeProc()
+    # But we can't call gcunsafe procs
+    await asyncGCUnsafeProc()
diff --git a/tests/async/tasync_in_seq_constr.nim b/tests/async/tasync_in_seq_constr.nim
new file mode 100644
index 000000000..3d6dae245
--- /dev/null
+++ b/tests/async/tasync_in_seq_constr.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+@[1, 2, 3, 4]
+123
+'''
+"""
+
+# bug #5314, bug #6626
+
+import asyncdispatch
+
+proc bar(i: int): Future[int] {.async.} =
+    await sleepAsync(2)
+    result = i
+
+proc foo(): Future[seq[int]] {.async.} =
+    await sleepAsync(2)
+    result = @[1, 2, await bar(3), 4] # <--- The bug is here
+
+proc foo2() {.async.} =
+    await sleepAsync(2)
+    echo(await bar(1), await bar(2), await bar(3))
+
+echo waitFor foo()
+waitFor foo2()
diff --git a/tests/async/tasync_misc.nim b/tests/async/tasync_misc.nim
new file mode 100644
index 000000000..ec1418e8c
--- /dev/null
+++ b/tests/async/tasync_misc.nim
@@ -0,0 +1,83 @@
+import json, asyncdispatch
+block: #6100
+  let done = newFuture[int]()
+  done.complete(1)
+
+  proc asyncSum: Future[int] {.async.} =
+    for _ in 1..1_000_000:
+      result += await done
+
+  let res = waitFor asyncSum()
+  doAssert(res == 1_000_000)
+
+block: #7985
+  proc getData(): Future[JsonNode] {.async.} =
+    result = %*{"value": 1}
+
+  type
+    MyData = object
+      value: BiggestInt
+
+  proc main() {.async.} =
+    let data = to(await(getData()), MyData)
+    doAssert($data == "(value: 1)")
+
+  waitFor(main())
+
+block: #8399
+  proc bar(): Future[string] {.async.} = discard
+
+  proc foo(line: string) {.async.} =
+    var res =
+      case line[0]
+      of '+', '-': @[]
+      of '$': (let x = await bar(); @[""])
+      else: @[]
+
+    doAssert(res == @[""])
+
+  waitFor foo("$asd")
+
+block: # nkCheckedFieldExpr
+  proc bar(): Future[JsonNode] {.async.} =
+    return newJInt(5)
+
+  proc foo() {.async.} =
+    let n = 10 + (await bar()).num
+    doAssert(n == 15)
+
+  waitFor foo()
+
+block: # 12743
+
+  template templ = await sleepAsync 0
+
+  proc prc {.async.} = templ
+
+  waitFor prc()
+
+block: # issue #13899
+  proc someConnect() {.async.} =
+    await sleepAsync(1)
+  proc someClose() {.async.} =
+    await sleepAsync(2)
+  proc testFooFails(): Future[bool] {.async.} =
+    await someConnect()
+    defer:
+      await someClose()
+      result = true
+  proc testFooSucceed(): Future[bool] {.async.} =
+    try:
+      await someConnect()
+    finally:
+      await someClose()
+      result = true
+  doAssert waitFor testFooSucceed()
+  doAssert waitFor testFooFails()
+
+block: # issue #9313
+  doAssert compiles(block:
+    proc a() {.async.} =
+      echo "Hi"
+      quit(0)
+  )
diff --git a/tests/async/tasync_noasync.nim b/tests/async/tasync_noasync.nim
new file mode 100644
index 000000000..0927148bf
--- /dev/null
+++ b/tests/async/tasync_noasync.nim
@@ -0,0 +1,44 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  action: "reject"
+  nimout: '''
+tasync_noasync.nim(21, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(25, 12) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(28, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(31, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(35, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(38, 10) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+tasync_noasync.nim(40, 8) Error: Can only 'await' inside a proc marked as 'async'. Use 'waitFor' when calling an 'async' proc in a non-async scope instead
+'''
+"""
+import async
+
+proc a {.async.} =
+  discard
+
+# Bad await usage
+proc nonAsyncProc =
+  await a()
+
+proc nestedNonAsyncProc {.async.} =
+  proc nested =
+    await a()
+
+iterator customIterator: int =
+  await a()
+
+macro awaitInMacro =
+  await a()
+
+type DummyRef = ref object of RootObj
+method awaitInMethod(_: DummyRef) {.base.} =
+  await a()
+
+proc improperMultisync {.multisync.} =
+  await a()
+
+await a()
+
+# if we overload a fallback handler to get
+# await only available within {.async.}
+# we would need `{.dirty.}` templates for await
diff --git a/tests/async/tasync_nofuture.nim b/tests/async/tasync_nofuture.nim
new file mode 100644
index 000000000..16155601a
--- /dev/null
+++ b/tests/async/tasync_nofuture.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "await expects Future[T], got int"
+  cmd: "nim c $file"
+  file: "asyncmacro.nim"
+"""
+import async
+
+proc a {.async.} =
+  await 0
+
+waitFor a()
diff --git a/tests/async/tasync_traceback.nim b/tests/async/tasync_traceback.nim
new file mode 100644
index 000000000..98f71b192
--- /dev/null
+++ b/tests/async/tasync_traceback.nim
@@ -0,0 +1,122 @@
+discard """
+  exitcode: 0
+  output: "Matched"
+"""
+import asyncdispatch, strutils
+
+# Tests to ensure our exception trace backs are friendly.
+
+# --- Simple test. ---
+#
+# What does this look like when it's synchronous?
+#
+# tasync_traceback.nim(23) tasync_traceback
+# tasync_traceback.nim(21) a
+# tasync_traceback.nim(18) b
+# Error: unhandled exception: b failure [OSError]
+#
+# Good (not quite ideal, but gotta work within constraints) traceback,
+# when exception is unhandled:
+#
+# <traceback for the unhandled exception>
+# <very much a bunch of noise>
+# <would be ideal to customise this>
+# <(the code responsible is in excpt:raiseExceptionAux)>
+# Error: unhandled exception: b failure
+# ===============
+# Async traceback
+# ===============
+#
+# tasync_traceback.nim(23) tasync_traceback
+#
+# tasync_traceback.nim(21) a
+# tasync_traceback.nim(18) b
+
+var result = ""
+
+proc b(): Future[int] {.async.} =
+  if true:
+    raise newException(OSError, "b failure")
+
+proc a(): Future[int] {.async.} =
+  return await b()
+
+let aFut = a()
+try:
+  discard waitFor aFut
+except Exception as exc:
+  result.add(exc.msg & "\n")
+result.add("\n")
+
+# From #6803
+proc bar(): Future[string] {.async.} =
+  await sleepAsync(100)
+  if true:
+    raise newException(OSError, "bar failure")
+
+proc foo(): Future[string] {.async.} = return await bar()
+
+try:
+  result.add(waitFor(foo()) & "\n")
+except Exception as exc:
+  result.add(exc.msg & "\n")
+result.add("\n")
+
+# Use re to parse the result
+import re
+const expected = """
+b failure
+Async traceback:
+  tasync_traceback\.nim\(\d+?\) tasync_traceback
+  tasync_traceback\.nim\(\d+?\) a \(Async\)
+  tasync_traceback\.nim\(\d+?\) b \(Async\)
+Exception message: b failure
+
+
+bar failure
+Async traceback:
+  tasync_traceback\.nim\(\d+?\) tasync_traceback
+  asyncdispatch\.nim\(\d+?\) waitFor
+  asyncdispatch\.nim\(\d+?\) poll
+    ## Processes asynchronous completion events
+  asyncdispatch\.nim\(\d+?\) runOnce
+  asyncdispatch\.nim\(\d+?\) processPendingCallbacks
+    ## Executes pending callbacks
+  tasync_traceback\.nim\(\d+?\) bar \(Async\)
+Exception message: bar failure
+
+"""
+
+# TODO: is asyncmacro good enough location for fooIter traceback/debugging? just put the callsite info for all?
+
+let resLines = splitLines(result.strip)
+let expLines = splitLines(expected.strip)
+
+when not defined(cpp): # todo fixme
+  if resLines.len != expLines.len:
+    echo("Not matched! Wrong number of lines!")
+    echo expLines.len
+    echo resLines.len
+    echo("Expected: -----------")
+    echo expected
+    echo("Gotten: -------------")
+    echo result
+    echo("---------------------")
+    quit(QuitFailure)
+
+  var ok = true
+  for i in 0 ..< resLines.len:
+    if not resLines[i].match(re(expLines[i])):
+      echo "Not matched! Line ", i + 1
+      echo "Expected:"
+      echo expLines[i]
+      echo "Actual:"
+      echo resLines[i]
+      ok = false
+
+  if ok:
+    echo("Matched")
+  else:
+    quit(QuitFailure)
+else:
+  echo("Matched")
diff --git a/tests/async/tasyncall.nim b/tests/async/tasyncall.nim
new file mode 100644
index 000000000..3c318dbf7
--- /dev/null
+++ b/tests/async/tasyncall.nim
@@ -0,0 +1,93 @@
+discard """
+  exitcode: 0
+"""
+import times, sequtils
+import asyncdispatch
+
+const
+  taskCount = 10
+  sleepDuration = 50
+
+proc futureWithValue(x: int): Future[int] {.async.} =
+  await sleepAsync(sleepDuration)
+  return x
+
+proc futureWithoutValue() {.async.} =
+  await sleepAsync(sleepDuration)
+
+proc testFuturesWithValue(x: int): seq[int] =
+  var tasks = newSeq[Future[int]](taskCount)
+
+  for i in 0..<taskCount:
+    tasks[i] = futureWithValue(x)
+
+  result = waitFor all(tasks)
+
+proc testFuturesWithoutValues() =
+  var tasks = newSeq[Future[void]](taskCount)
+
+  for i in 0..<taskCount:
+    tasks[i] = futureWithoutValue()
+
+  waitFor all(tasks)
+
+proc testVarargs(x, y, z: int): seq[int] =
+  let
+    a = futureWithValue(x)
+    b = futureWithValue(y)
+    c = futureWithValue(z)
+
+  result = waitFor all(a, b, c)
+
+proc testWithDupes() =
+  var
+    tasks = newSeq[Future[void]](taskCount)
+    fut = futureWithoutValue()
+
+  for i in 0..<taskCount:
+    tasks[i] = fut
+
+  waitFor all(tasks)
+
+block:
+    let
+      startTime = cpuTime()
+      results = testFuturesWithValue(42)
+      expected = repeat(42, taskCount)
+      execTime = cpuTime() - startTime
+
+    doAssert execTime * 1000 < taskCount * sleepDuration
+    doAssert results == expected
+
+block:
+    let startTime = cpuTime()
+    testFuturesWithoutValues()
+    let execTime = cpuTime() - startTime
+
+    doAssert execTime * 1000 < taskCount * sleepDuration
+
+block:
+    let startTime = cpuTime()
+    testWithDupes()
+    let execTime = cpuTime() - startTime
+
+    doAssert execTime * 1000 < taskCount * sleepDuration
+
+block:
+    let
+      startTime = cpuTime()
+      results = testVarargs(1, 2, 3)
+      expected = @[1, 2, 3]
+      execTime = cpuTime() - startTime
+
+    doAssert execTime * 100 < taskCount * sleepDuration
+    doAssert results == expected
+
+block:
+    let
+      noIntFuturesFut = all(newSeq[Future[int]]())
+      noVoidFuturesFut = all(newSeq[Future[void]]())
+
+    doAssert noIntFuturesFut.finished and not noIntFuturesFut.failed
+    doAssert noVoidFuturesFut.finished and not noVoidFuturesFut.failed
+    doAssert noIntFuturesFut.read() == @[]
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
new file mode 100644
index 000000000..e86542b2d
--- /dev/null
+++ b/tests/async/tasyncawait.nim
@@ -0,0 +1,56 @@
+import asyncdispatch, asyncnet, nativesockets, net, strutils
+from stdtest/netutils import bindAvailablePort
+var msgCount = 0
+
+const
+  swarmSize = 40
+  messagesToSend = 50
+
+var clientCount = 0
+
+proc sendMessages(client: AsyncFD) {.async.} =
+  for i in 0 ..< messagesToSend:
+    await send(client, "Message " & $i & "\c\L")
+
+proc launchSwarm(port: Port) {.async.} =
+  for i in 0 ..< swarmSize:
+    var sock = createAsyncNativeSocket()
+
+    await connect(sock, "localhost", port)
+    await sendMessages(sock)
+    closeSocket(sock)
+
+proc readMessages(client: AsyncFD) {.async.} =
+  # wrapping the AsyncFd into a AsyncSocket object
+  var sockObj = newAsyncSocket(client)
+  var (ipaddr, port) = sockObj.getPeerAddr()
+  doAssert ipaddr == "127.0.0.1"
+  (ipaddr, port) = sockObj.getLocalAddr()
+  doAssert ipaddr == "127.0.0.1"
+  while true:
+    var line = await recvLine(sockObj)
+    if line == "":
+      closeSocket(client)
+      clientCount.inc
+      break
+    else:
+      if line.startsWith("Message "):
+        msgCount.inc
+      else:
+        doAssert false
+
+proc createServer(server: AsyncFD) {.async.} =
+  discard server.SocketHandle.listen()
+  while true:
+    asyncCheck readMessages(await accept(server))
+
+let server = createAsyncNativeSocket()
+let port = bindAvailablePort(server.SocketHandle)
+asyncCheck createServer(server)
+asyncCheck launchSwarm(port)
+while true:
+  poll()
+  if clientCount == swarmSize: break
+
+doAssert msgCount == swarmSize * messagesToSend
+doAssert msgCount == 2000
diff --git a/tests/async/tasyncclosestall.nim b/tests/async/tasyncclosestall.nim
new file mode 100644
index 000000000..d1c7a5fba
--- /dev/null
+++ b/tests/async/tasyncclosestall.nim
@@ -0,0 +1,101 @@
+discard """
+  disabled: "windows"
+  outputsub: "send has errored. As expected. All good!"
+  exitcode: 0
+"""
+import asyncdispatch, asyncnet
+
+when defined(windows):
+  from winlean import ERROR_NETNAME_DELETED
+else:
+  from posix import EBADF
+
+# This reproduces a case where a socket remains stuck waiting for writes
+# even when the socket is closed.
+const
+  timeout = 8000
+var port = Port(0)
+
+var sent = 0
+
+proc keepSendingTo(c: AsyncSocket) {.async.} =
+  while true:
+    # This write will eventually get stuck because the client is not reading
+    # its messages.
+    let sendFut = c.send("Foobar" & $sent & "\n", flags = {})
+    if not await withTimeout(sendFut, timeout):
+      # The write is stuck. Let's simulate a scenario where the socket
+      # does not respond to PING messages, and we close it. The above future
+      # should complete after the socket is closed, not continue stalling.
+      echo("Socket has stalled, closing it")
+      c.close()
+
+      let timeoutFut = withTimeout(sendFut, timeout)
+      yield timeoutFut
+      if timeoutFut.failed:
+        let errCode = ((ref OSError)(timeoutFut.error)).errorCode
+        # The behaviour differs across platforms. On Windows ERROR_NETNAME_DELETED
+        # is raised which we classif as a "diconnection error", hence we overwrite
+        # the flags above in the `send` call so that this error is raised.
+        #
+        # On Linux the EBADF error code is raised, this is because the socket
+        # is closed.
+        #
+        # This means that by default the behaviours will differ between Windows
+        # and Linux. I think this is fine though, it makes sense mainly because
+        # Windows doesn't use a IO readiness model. We can fix this later if
+        # necessary to reclassify ERROR_NETNAME_DELETED as not a "disconnection
+        # error" (TODO)
+        when defined(windows):
+          if errCode == ERROR_NETNAME_DELETED:
+            echo("send has errored. As expected. All good!")
+            quit(QuitSuccess)
+          else:
+            raise newException(ValueError, "Test failed. Send failed with code " & $errCode)
+        else:
+          if errCode == EBADF:
+            echo("send has errored. As expected. All good!")
+            quit(QuitSuccess)
+          else:
+            raise newException(ValueError, "Test failed. Send failed with code " & $errCode)
+
+      # The write shouldn't succeed and also shouldn't be stalled.
+      if timeoutFut.read():
+        raise newException(ValueError, "Test failed. Send was expected to fail.")
+      else:
+        raise newException(ValueError, "Test failed. Send future is still stalled.")
+    sent.inc(1)
+
+proc startClient() {.async.} =
+  let client = newAsyncSocket()
+  await client.connect("localhost", port)
+  echo("Connected")
+
+  let firstLine = await client.recvLine()
+  echo("Received first line as a client: ", firstLine)
+  echo("Now not reading anymore")
+  while true: await sleepAsync(1000)
+
+proc debug() {.async.} =
+  while true:
+    echo("Sent ", sent)
+    await sleepAsync(1000)
+
+proc server() {.async.} =
+  var s = newAsyncSocket()
+  s.setSockOpt(OptReuseAddr, true)
+  s.bindAddr(port)
+  s.listen()
+  let (addr2, port2) = s.getLocalAddr
+  port = port2
+
+  # We're now ready to accept connections, so start the client
+  asyncCheck startClient()
+  asyncCheck debug()
+
+  while true:
+    let client = await accept(s)
+    asyncCheck keepSendingTo(client)
+
+when isMainModule:
+  waitFor server()
diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim
new file mode 100644
index 000000000..564f6c67c
--- /dev/null
+++ b/tests/async/tasyncconnect.nim
@@ -0,0 +1,33 @@
+discard """
+  outputsub: "Error: unhandled exception: Connection refused"
+  exitcode: 1
+"""
+
+import
+    asyncdispatch,
+    posix
+
+
+const
+    testHost = "127.0.0.1"
+    testPort = Port(17357)
+
+
+when defined(windows) or defined(nimdoc):
+    # TODO: just make it work on Windows for now.
+    quit("Error: unhandled exception: Connection refused")
+else:
+    proc testAsyncConnect() {.async.} =
+        var s = createAsyncNativeSocket()
+
+        await s.connect(testHost, testPort)
+
+        var peerAddr: SockAddr
+        var addrSize = Socklen(sizeof(peerAddr))
+        var ret = SocketHandle(s).getpeername(addr(peerAddr), addr(addrSize))
+
+        if ret < 0:
+            echo("`connect(...)` failed but no exception was raised.")
+            quit(2)
+
+    waitFor(testAsyncConnect())
diff --git a/tests/async/tasyncdial.nim b/tests/async/tasyncdial.nim
new file mode 100644
index 000000000..f0377dfd5
--- /dev/null
+++ b/tests/async/tasyncdial.nim
@@ -0,0 +1,52 @@
+discard """
+  output: '''
+OK AF_INET
+OK AF_INET6
+'''
+"""
+
+import
+  nativesockets, os, asyncdispatch
+
+proc setupServerSocket(hostname: string, port: Port, domain: Domain): AsyncFD =
+  ## Creates a socket, binds it to the specified address, and starts listening for connections.
+  ## Registers the descriptor with the dispatcher of the current thread
+  ## Raises OSError in case of an error.
+  let fd = createNativeSocket(domain)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, domain)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.Socklen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+  result = fd.AsyncFD
+  register(result)
+
+proc doTest(domain: static[Domain]) {.async.} =
+  const
+    testHost = when domain == Domain.AF_INET6: "::1" else: "127.0.0.1"
+    testPort = Port(17384)
+  let serverFd = setupServerSocket(testHost, testPort, domain)
+  let acceptFut = serverFd.accept()
+  let clientFdFut = dial(testHost, testPort)
+
+  let serverClientFd = await acceptFut
+  serverFd.closeSocket()
+
+  let clientFd = await clientFdFut
+
+  let recvFut = serverClientFd.recv(2)
+  await clientFd.send("Hi")
+  let msg = await recvFut
+
+  serverClientFd.closeSocket()
+  clientFd.closeSocket()
+
+  if msg == "Hi":
+    echo "OK ", domain
+
+waitFor(doTest(Domain.AF_INET))
+waitFor(doTest(Domain.AF_INET6))
diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim
new file mode 100644
index 000000000..64e6021c3
--- /dev/null
+++ b/tests/async/tasyncdiscard.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+1
+2
+3
+4
+1
+2
+1
+6
+'''
+"""
+import asyncdispatch, asyncnet
+
+proc main {.async.} =
+  proc f: Future[int] {.async.} =
+    discard
+    echo 1
+    discard
+    result = 2
+    discard
+
+  let x = await f()
+  echo x
+  echo 3
+
+  proc g: Future[int] {.async.} =
+    discard
+    echo 4
+    discard
+    result = 6
+    discard
+    echo await f()
+    discard await f()
+
+  discard await g()
+  echo 6
+
+waitFor(main())
diff --git a/tests/async/tasynceagain.nim b/tests/async/tasynceagain.nim
new file mode 100644
index 000000000..94c3645dc
--- /dev/null
+++ b/tests/async/tasynceagain.nim
@@ -0,0 +1,67 @@
+discard """
+  disabled: "windows"
+  exitcode: 0
+"""
+# AsyncSocketBug.nim
+# Jens Alfke (@snej) -- 16 July 2020
+# Demonstrates data loss by Nim's AsyncSocket.
+# Just run it, and it will raise an assertion failure within a minute.
+
+import asyncdispatch, asyncnet, strformat, strutils, sugar
+
+const FrameSize = 9999   # Exact size not important, but larger sizes fail quicker
+
+proc runServer() {.async.} =
+  # Server side:
+  var server = newAsyncSocket()
+  server.bindAddr(Port(9001))
+  server.listen()
+  let client = await server.accept()
+  echo "Server got client connection"
+  var lastN = 0
+  while true:
+    let frame = await client.recv(FrameSize)
+    doAssert frame.len == FrameSize
+    let n = frame[0..<6].parseInt()
+    echo "RCVD #", n, ":  ", frame[0..80], "..."
+    if n != lastN + 1:
+      echo &"******** ERROR: Server received #{n}, but last was #{lastN}!"
+    doAssert n == lastN + 1
+    lastN = n
+    await sleepAsync 100
+
+
+proc main() {.async.} =
+  asyncCheck runServer()
+
+  # Client side:
+  let socket = newAsyncSocket(buffered = false)
+  await socket.connect("localhost", Port(9001))
+  echo "Client socket connected"
+
+  var sentCount = 0
+  var completedCount = 0
+
+  while sentCount < 2000:
+    sentCount += 1
+    let n = sentCount
+
+    var message = &"{n:06} This is message #{n} of ∞. Please stay tuned for more. "
+    #echo ">>> ", message
+    while message.len < FrameSize:
+      message = message & message
+    let frame = message[0..<FrameSize]
+
+    capture n:
+      socket.send(frame).addCallback proc(f: Future[void]) =
+        # Callback when the send completes:
+        assert not f.failed
+        echo "SENT #", n
+        if n != completedCount + 1:
+          echo &"******** ERROR: Client completed #{n}, but last completed was #{completedCount}!"
+        # If this assert is enabled, it will trigger earlier than the server-side assert above:
+        assert n == completedCount + 1
+        completedCount = n
+    await sleepAsync 1
+
+waitFor main()
\ No newline at end of file
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
new file mode 100644
index 000000000..de61c099d
--- /dev/null
+++ b/tests/async/tasyncexceptions.nim
@@ -0,0 +1,40 @@
+discard """
+  outputsub: "Error: unhandled exception: foobar"
+  exitcode: 1
+"""
+import asyncdispatch
+
+# Note: This is a test case for a bug.
+
+proc accept(): Future[int] {.async.} =
+  await sleepAsync(100)
+  result = 4
+
+proc recvLine(fd: int): Future[string] {.async.} =
+  await sleepAsync(100)
+  return "get"
+
+proc processClient(fd: int) {.async.} =
+  # these finish synchronously, we need some async delay to emulate this bug.
+  var line = await recvLine(fd)
+  var foo = line[0]
+  if foo == 'g':
+    raise newException(Exception, "foobar")
+
+proc serve() {.async.} =
+
+  while true:
+    var fut = await accept()
+    await processClient(fut)
+
+when true:
+  proc main =
+    var fut = serve()
+    fut.callback =
+      proc () =
+        if fut.failed:
+          # This test ensures that this exception crashes the application
+          # as it is not handled.
+          raise fut.error
+    runForever()
+  main()
diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim
new file mode 100644
index 000000000..d95850c31
--- /dev/null
+++ b/tests/async/tasyncfile.nim
@@ -0,0 +1,61 @@
+discard """
+output: '''
+13
+hello humans!
+13
+'''
+"""
+import asyncfile, asyncdispatch, os
+
+proc main() {.async.} =
+  let fn = getTempDir() / "foobar.txt"
+  removeFile(fn)
+
+  # Simple write/read test.
+  block:
+    var file = openAsync(fn, fmReadWrite)
+    await file.write("testing")
+    file.setFilePos(0)
+    await file.write("foo")
+    file.setFileSize(4)
+    file.setFilePos(0)
+    let data = await file.readAll()
+    doAssert data == "foot"
+    file.close()
+
+  # Append test
+  block:
+    var file = openAsync(fn, fmAppend)
+    await file.write("\ntest2")
+    let errorTest = file.readAll()
+    yield errorTest
+    doAssert errorTest.failed
+    file.close()
+    file = openAsync(fn, fmRead)
+    let data = await file.readAll()
+
+    doAssert data == "foot\ntest2"
+    file.close()
+
+  # Issue #5531
+  block:
+    removeFile(fn)
+    var file = openAsync(fn, fmWrite)
+    await file.write("test2")
+    file.close()
+    file = openAsync(fn, fmWrite)
+    await file.write("t3")
+    file.close()
+    file = openAsync(fn, fmRead)
+    let data = await file.readAll()
+    doAssert data == "t3"
+    file.close()
+
+  # Issue #7347
+  block:
+    var file = openAsync( parentDir(currentSourcePath) / "hello.txt")
+    echo file.getFileSize()
+    echo await file.readAll()
+    echo file.getFilePos()
+
+waitFor main()
diff --git a/tests/async/tasyncfilewrite.nim b/tests/async/tasyncfilewrite.nim
new file mode 100644
index 000000000..72a2df0b0
--- /dev/null
+++ b/tests/async/tasyncfilewrite.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''string 1
+string 2
+string 3
+'''
+"""
+# bug #5532
+import os, asyncfile, asyncdispatch
+
+const F = "test_async.txt"
+
+removeFile(F)
+let f = openAsync(F, fmWrite)
+var futs = newSeq[Future[void]]()
+for i in 1..3:
+  futs.add(f.write("string " & $i & "\n"))
+waitFor(all(futs))
+f.close()
+echo readFile(F)
+removeFile(F)
diff --git a/tests/async/tasyncintemplate.nim b/tests/async/tasyncintemplate.nim
new file mode 100644
index 000000000..4bddb1d18
--- /dev/null
+++ b/tests/async/tasyncintemplate.nim
@@ -0,0 +1,62 @@
+discard """
+  output: '''
+42
+43
+43
+1
+2
+3
+4
+'''
+"""
+
+# xxx move to tests/async/tasyncintemplate.nim
+import asyncdispatch
+
+block: # bug #16159
+  template foo() =
+    proc temp(): Future[int] {.async.} = return 42
+    proc tempVoid(): Future[void] {.async.} = echo await temp()
+  foo()
+  waitFor tempVoid()
+
+block: # aliasing `void`
+  template foo() =
+    type Foo = void
+    proc temp(): Future[int] {.async.} = return 43
+    proc tempVoid(): Future[Foo] {.async.} = echo await temp()
+    proc tempVoid2() {.async.} = echo await temp()
+  foo()
+  waitFor tempVoid()
+  waitFor tempVoid2()
+
+block: # sanity check
+  template foo() =
+    proc bad(): int {.async.} = discard
+  doAssert not compiles(bad())
+
+block: # bug #16786
+  block:
+    proc main(a: int|string)=
+      proc bar(b: int|string) = echo b
+      bar(a)
+    main(1)
+
+  block:
+    proc main(a: int) : Future[void] {.async.} =
+      proc bar(b: int): Future[void] {.async.} = echo b
+      await bar(a)
+    waitFor main(2)
+
+  block:
+    proc main(a: int) : Future[void] {.async.} =
+      proc bar(b: int | string): Future[void] {.async.} = echo b
+      await bar(a)
+    waitFor main(3)
+
+  block:
+    # bug
+    proc main(a: int|string) =
+      proc bar(b: int): Future[void] {.async.} = echo b
+      waitFor bar(a)
+    main(4)
diff --git a/tests/async/tasyncnetudp.nim b/tests/async/tasyncnetudp.nim
new file mode 100644
index 000000000..dade96fb2
--- /dev/null
+++ b/tests/async/tasyncnetudp.nim
@@ -0,0 +1,90 @@
+# It is a reproduction of the 'tnewasyncudp' test code, but using a high level
+# of asynchronous procedures. Output: "5000"
+import asyncdispatch, asyncnet, nativesockets, net, strutils
+
+var msgCount = 0
+var recvCount = 0
+
+const
+  messagesToSend = 100
+  swarmSize = 50
+  serverPort = 10333
+
+var
+  sendports = 0
+  recvports = 0
+
+proc saveSendingPort(port: Port) =
+  sendports = sendports + int(port)
+
+proc saveReceivedPort(port: Port) =
+  recvports = recvports + int(port)
+
+proc launchSwarm(serverIp: string, serverPort: Port) {.async.} =
+  var i = 0
+
+  while i < swarmSize:
+    var sock = newAsyncSocket(nativesockets.AF_INET, nativesockets.SOCK_DGRAM,
+                              Protocol.IPPROTO_UDP, false)
+
+    bindAddr(sock, address = "127.0.0.1")
+
+    let (null, localPort) = getLocalAddr(sock)
+
+    var k = 0
+    
+    while k < messagesToSend:
+      let message = "Message " & $(i * messagesToSend + k)
+
+      await asyncnet.sendTo(sock, serverIp, serverPort, message)
+
+      let (data, fromIp, fromPort) = await recvFrom(sock, 16384)
+
+      if data == message:
+        saveSendingPort(localPort)
+
+        inc(recvCount)
+
+      inc(k)
+    
+    close(sock)
+
+    inc(i)
+
+proc readMessages(server: AsyncSocket) {.async.} =
+  let maxResponses = (swarmSize * messagesToSend)
+
+  var i = 0
+  
+  while i < maxResponses:
+    let (data, fromIp, fromPort) = await recvFrom(server, 16384)
+
+    if data.startsWith("Message ") and fromIp == "127.0.0.1":
+      await sendTo(server, fromIp, fromPort, data)
+
+      inc(msgCount)
+
+      saveReceivedPort(fromPort)
+
+    inc(i)
+
+proc createServer() {.async.} =
+  var server = newAsyncSocket(nativesockets.AF_INET, nativesockets.SOCK_DGRAM, Protocol.IPPROTO_UDP, false)
+  
+  bindAddr(server, Port(serverPort), "127.0.0.1")
+
+  asyncCheck readMessages(server)
+
+asyncCheck createServer()
+asyncCheck launchSwarm("127.0.0.1", Port(serverPort))
+
+while true:
+  poll()
+
+  if recvCount == swarmSize * messagesToSend:
+    break
+
+doAssert msgCount == swarmSize * messagesToSend
+doAssert sendports == recvports
+
+echo msgCount
\ No newline at end of file
diff --git a/tests/async/tasyncrecursion.nim b/tests/async/tasyncrecursion.nim
new file mode 100644
index 000000000..7c12dbb0e
--- /dev/null
+++ b/tests/async/tasyncrecursion.nim
@@ -0,0 +1,21 @@
+discard """
+output: "50005000"
+"""
+import asyncdispatch
+
+proc asyncRecursionCycle*(counter: int): Future[int] =
+  var retFuture = newFuture[int]("asyncRecursionTest")
+  retFuture.complete(counter + 1)
+  return retFuture
+
+proc asyncRecursionTest*(): Future[int] {.async.} =
+  var i = 0
+  result = 0
+  while i < 10_000:
+    inc(result, await asyncRecursionCycle(i))
+    inc(i)
+
+when true:
+  setGlobalDispatcher(newDispatcher())
+  var i = waitFor asyncRecursionTest()
+  echo i
diff --git a/tests/async/tasyncsend4757.nim b/tests/async/tasyncsend4757.nim
new file mode 100644
index 000000000..29873a905
--- /dev/null
+++ b/tests/async/tasyncsend4757.nim
@@ -0,0 +1,24 @@
+import asyncdispatch, asyncnet
+
+var port: Port
+proc createServer() {.async.} =
+  var server = newAsyncSocket()
+  server.setSockOpt(OptReuseAddr, true)
+  bindAddr(server)
+  port = getLocalAddr(server)[1]
+  server.listen()
+  while true:
+    let client = await server.accept()
+    discard await client.recvLine()
+
+asyncCheck createServer()
+
+var done = false
+proc f(): Future[void] {.async.} =
+  let s = createAsyncNativeSocket()
+  await s.connect("localhost", port)
+  await s.send("123")
+  done = true
+
+waitFor f()
+doAssert done
diff --git a/tests/async/tasyncssl.nim b/tests/async/tasyncssl.nim
new file mode 100644
index 000000000..57de3271d
--- /dev/null
+++ b/tests/async/tasyncssl.nim
@@ -0,0 +1,74 @@
+discard """
+  cmd: "nim $target --hints:on --define:ssl $options $file"
+  disabled: osx
+"""
+
+import asyncdispatch, asyncnet, net, strutils
+import stdtest/testutils
+
+when defined(ssl):
+  var port0: Port
+  var msgCount = 0
+
+  const
+    swarmSize = 10
+    messagesToSend = 50
+
+  var clientCount = 0
+
+  proc sendMessages(client: AsyncSocket) {.async.} =
+    for i in 0 ..< messagesToSend:
+      await send(client, "Message " & $i & "\c\L")
+
+  proc launchSwarm(port: Port) {.async.} =
+    for i in 0 ..< swarmSize:
+      var sock = newAsyncSocket()
+      var clientContext = newContext(verifyMode = CVerifyNone)
+      clientContext.wrapSocket(sock)
+      await connect(sock, "localhost", port)
+      await sendMessages(sock)
+      close(sock)
+
+  proc readMessages(client: AsyncSocket) {.async.} =
+    while true:
+      var line = await recvLine(client)
+      if line == "":
+        close(client)
+        inc(clientCount)
+        break
+      else:
+        if line.startsWith("Message "):
+          inc(msgCount)
+        else:
+          doAssert false
+
+  proc createServer() {.async.} =
+    let serverContext = newContext(verifyMode = CVerifyNone,
+                                   certFile = "tests/testdata/mycert.pem",
+                                   keyFile = "tests/testdata/mycert.pem")
+    var server = newAsyncSocket()
+    serverContext.wrapSocket(server)
+    server.setSockOpt(OptReuseAddr, true)
+    bindAddr(server)
+    port0 = getLocalAddr(server)[1]
+    server.listen()
+    while true:
+      let client = await accept(server)
+      serverContext.wrapConnectedSocket(client, handshakeAsServer)
+      asyncCheck readMessages(client)
+
+  asyncCheck createServer()
+  asyncCheck launchSwarm(port0)
+  while true:
+    poll()
+    if clientCount == swarmSize: break
+
+  template cond(): bool = msgCount == swarmSize * messagesToSend
+  when defined(windows):
+    # currently: msgCount == 0
+    flakyAssert cond()
+  elif defined(linux) and int.sizeof == 8:
+    # currently:  msgCount == 10
+    flakyAssert cond()
+    doAssert msgCount > 0
+  else: doAssert cond(), $msgCount
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
new file mode 100644
index 000000000..25eab87fb
--- /dev/null
+++ b/tests/async/tasynctry.nim
@@ -0,0 +1,118 @@
+discard """
+output: '''
+Generic except: Test
+Specific except
+Multiple idents in except
+Multiple except branches
+Multiple except branches 2
+success
+'''
+targets: "c"
+"""
+import asyncdispatch, strutils
+
+# Here we are testing the ability to catch exceptions.
+
+proc foobar() {.async.} =
+  if 5 == 5:
+    raise newException(IndexDefect, "Test")
+
+proc catch() {.async.} =
+  # TODO: Create a test for when exceptions are not caught.
+  try:
+    await foobar()
+  except:
+    echo("Generic except: ", getCurrentExceptionMsg().splitLines[0])
+
+  try:
+    await foobar()
+  except IndexDefect:
+    echo("Specific except")
+
+  try:
+    await foobar()
+  except OSError, FieldDefect, IndexDefect:
+    echo("Multiple idents in except")
+
+  try:
+    await foobar()
+  except OSError, FieldDefect:
+    assert false
+  except IndexDefect:
+    echo("Multiple except branches")
+
+  try:
+    await foobar()
+  except IndexDefect:
+    echo("Multiple except branches 2")
+  except OSError, FieldDefect:
+    assert false
+
+waitFor catch()
+
+proc test(): Future[bool] {.async.} =
+  result = false
+  try:
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc foo(): Future[bool] {.async.} = discard
+
+proc test2(): Future[bool] {.async.} =
+  result = false
+  try:
+    discard await foo()
+    raise newException(OSError, "Foobar")
+  except:
+    result = true
+    return
+
+proc test3(): Future[int] {.async.} =
+  result = 0
+  try:
+    try:
+      discard await foo()
+      raise newException(OSError, "Hello")
+    except:
+      result = 1
+      raise
+  except:
+    result = 2
+    return
+
+proc test4(): Future[int] {.async.} =
+  try:
+    discard await foo()
+    raise newException(ValueError, "Test4")
+  except OSError:
+    result = 1
+  except:
+    result = 2
+
+var x = test()
+assert x.waitFor()
+
+x = test2()
+assert x.waitFor()
+
+var y = test3()
+assert y.waitFor() == 2
+
+y = test4()
+assert y.waitFor() == 2
+
+# bug #14279
+
+proc expandValue: Future[int] {.async.} =
+  return 0
+
+proc a(b: int): Future[void] {.async.} =
+  return
+
+proc b: Future[void] {.async.} =
+  await a(await expandValue())
+  echo "success"
+
+waitFor(b())
diff --git a/tests/async/tawaitsemantics.nim b/tests/async/tawaitsemantics.nim
new file mode 100644
index 000000000..67903cc5e
--- /dev/null
+++ b/tests/async/tawaitsemantics.nim
@@ -0,0 +1,95 @@
+discard """
+output: '''
+Error can be caught using yield
+Infix `or` raises
+Infix `and` raises
+All() raises
+Awaiting a async procedure call raises
+Awaiting a future raises
+'''
+"""
+
+import asyncdispatch
+
+# This tests the behaviour of 'await' under different circumstances.
+# Specifically, when an awaited future raises an exception then `await` should
+# also raise that exception by `read`'ing that future. In cases where you don't
+# want this behaviour, you can use `yield`.
+# https://github.com/nim-lang/Nim/issues/4170
+
+proc thrower(): Future[void] =
+  result = newFuture[void]()
+  result.fail(newException(Exception, "Test"))
+
+proc dummy: Future[void] =
+  result = newFuture[void]()
+  result.complete()
+
+proc testInfixOr() {.async.} =
+  # Test the infix `or` operator semantics.
+  var fut = thrower()
+  var fut2 = dummy()
+  await fut or fut2 # Should raise!
+
+proc testInfixAnd() {.async.} =
+  # Test the infix `and` operator semantics.
+  var fut = thrower()
+  var fut2 = dummy()
+  await fut and fut2 # Should raise!
+
+proc testAll() {.async.} =
+  # Test the `all` semantics.
+  var fut = thrower()
+  var fut2 = dummy()
+  await all(fut, fut2) # Should raise!
+
+proc testCall() {.async.} =
+  await thrower()
+
+proc testAwaitFut() {.async.} =
+  var fut = thrower()
+  await fut # This should raise.
+
+proc tester() {.async.} =
+  # Test that we can handle exceptions without 'try'
+  var fut = thrower()
+  doAssert fut.finished
+  doAssert fut.failed
+  doAssert fut.error.msg == "Test"
+  yield fut # We are yielding a 'Future', so no `read` occurs.
+  doAssert fut.finished
+  doAssert fut.failed
+  doAssert fut.error.msg == "Test"
+  echo("Error can be caught using yield")
+
+  fut = testInfixOr()
+  yield fut
+  doAssert fut.finished
+  doAssert fut.failed
+  echo("Infix `or` raises")
+
+  fut = testInfixAnd()
+  yield fut
+  doAssert fut.finished
+  doAssert fut.failed
+  echo("Infix `and` raises")
+
+  fut = testAll()
+  yield fut
+  doAssert fut.finished
+  doAssert fut.failed
+  echo("All() raises")
+
+  fut = testCall()
+  yield fut
+  doAssert fut.failed
+  echo("Awaiting a async procedure call raises")
+
+  # Test that await will read the future and raise an exception.
+  fut = testAwaitFut()
+  yield fut
+  doAssert fut.failed
+  echo("Awaiting a future raises")
+
+
+waitFor(tester())
diff --git a/tests/async/tbreak_must_exec_finally.nim b/tests/async/tbreak_must_exec_finally.nim
new file mode 100644
index 000000000..8780e6149
--- /dev/null
+++ b/tests/async/tbreak_must_exec_finally.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+finally handler 8
+do not duplicate this one
+'''
+"""
+
+# bug #15243
+
+import asyncdispatch
+
+proc f() {.async.} =
+  try:
+    while true:
+      try:
+        await sleepAsync(400)
+        break
+      finally:
+        var localHere = 8
+        echo "finally handler ", localHere
+  finally:
+    echo "do not duplicate this one"
+
+when isMainModule:
+  waitFor f()
diff --git a/tests/async/tcallbacks.nim b/tests/async/tcallbacks.nim
new file mode 100644
index 000000000..bd82d5824
--- /dev/null
+++ b/tests/async/tcallbacks.nim
@@ -0,0 +1,21 @@
+discard """
+  exitcode: 0
+  output: '''
+1
+2
+3
+5
+'''
+"""
+import asyncfutures
+
+let f1: Future[int] = newFuture[int]()
+f1.addCallback(proc() = echo 1)
+f1.addCallback(proc() = echo 2)
+f1.addCallback(proc() = echo 3)
+f1.complete(10)
+
+let f2: Future[int] = newFuture[int]()
+f2.addCallback(proc() = echo 4)
+f2.callback = proc() = echo 5
+f2.complete(10)
diff --git a/tests/async/tdiscardableproc.nim b/tests/async/tdiscardableproc.nim
new file mode 100644
index 000000000..93cd83be9
--- /dev/null
+++ b/tests/async/tdiscardableproc.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "Cannot make async proc discardable. Futures have to be checked with `asyncCheck` instead of discarded"
+"""
+
+import async
+
+proc foo {.async, discardable.} = discard
+
+foo()
diff --git a/tests/async/testmanyasyncevents.nim b/tests/async/testmanyasyncevents.nim
new file mode 100644
index 000000000..9fdd01b4f
--- /dev/null
+++ b/tests/async/testmanyasyncevents.nim
@@ -0,0 +1,24 @@
+discard """
+output: '''
+hasPendingOperations: false
+triggerCount: 100
+'''
+disabled: "windows"
+"""
+
+import asyncDispatch
+
+var triggerCount = 0
+var evs = newSeq[AsyncEvent]()
+
+for i in 0 ..< 100: # has to be lower than the typical physical fd limit
+  var ev = newAsyncEvent()
+  evs.add(ev)
+  addEvent(ev, proc(fd: AsyncFD): bool {.gcsafe,closure.} = triggerCount += 1; true)
+
+for ev in evs:
+  ev.trigger()
+
+drain()
+echo "hasPendingOperations: ", hasPendingOperations()
+echo "triggerCount: ", triggerCount
diff --git a/tests/async/tfuturestream.nim b/tests/async/tfuturestream.nim
new file mode 100644
index 000000000..a019df400
--- /dev/null
+++ b/tests/async/tfuturestream.nim
@@ -0,0 +1,71 @@
+discard """
+output: '''
+0
+1
+2
+3
+4
+5
+Done
+Finished
+'''
+"""
+import asyncdispatch
+
+var fs = newFutureStream[int]()
+
+proc alpha() {.async.} =
+  for i in 0 .. 5:
+    await fs.write(i)
+    await sleepAsync(100)
+
+  echo("Done")
+  fs.complete()
+
+proc beta() {.async.} =
+  while not fs.finished:
+    let (hasValue, value) = await fs.read()
+    if hasValue:
+      echo(value)
+
+  echo("Finished")
+
+asyncCheck alpha()
+waitFor beta()
+
+template ensureCallbacksAreScheduled =
+  # callbacks are called directly if the dispatcher is not running
+  discard getGlobalDispatcher()
+
+proc testCompletion() {.async.} =
+  ensureCallbacksAreScheduled
+
+  var stream = newFutureStream[string]()
+
+  for i in 1..5:
+    await stream.write($i)
+
+  var readFuture = stream.readAll()
+  stream.complete()
+  yield readFuture
+  let data = readFuture.read()
+  doAssert(data.len == 5, "actual data len = " & $data.len)
+
+waitFor testCompletion()
+
+# TODO: Something like this should work eventually.
+# proc delta(): FutureStream[string] {.async.} =
+#   for i in 0 .. 5:
+#     await sleepAsync(1000)
+#     result.put($i)
+
+#   return ""
+
+# proc omega() {.async.} =
+#   let fut = delta()
+#   while not fut.finished():
+#     echo(await fs.takeAsync())
+
+#   echo("Finished")
+
+# waitFor omega()
diff --git a/tests/async/tfuturevar.nim b/tests/async/tfuturevar.nim
new file mode 100644
index 000000000..b70f1d166
--- /dev/null
+++ b/tests/async/tfuturevar.nim
@@ -0,0 +1,46 @@
+import asyncdispatch
+
+proc completeOnReturn(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    fut.mget() = ""
+    fut.mget.add("foobar")
+    return
+
+proc completeOnImplicitReturn(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    fut.mget() = ""
+    fut.mget.add("foobar")
+
+proc failureTest(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    raise newException(Exception, "Test")
+
+proc manualComplete(fut: FutureVar[string], x: bool) {.async.} =
+  if x:
+    fut.mget() = "Hello World"
+    fut.complete()
+    return
+
+proc main() {.async.} =
+  var fut: FutureVar[string]
+
+  fut = newFutureVar[string]()
+  await completeOnReturn(fut, true)
+  doAssert(fut.read() == "foobar")
+
+  fut = newFutureVar[string]()
+  await completeOnImplicitReturn(fut, true)
+  doAssert(fut.read() == "foobar")
+
+  fut = newFutureVar[string]()
+  let retFut = failureTest(fut, true)
+  yield retFut
+  doAssert(fut.read().len == 0)
+  doAssert(fut.finished)
+
+  fut = newFutureVar[string]()
+  await manualComplete(fut, true)
+  doAssert(fut.read() == "Hello World")
+
+
+waitFor main()
diff --git a/tests/async/tgeneric_async.nim b/tests/async/tgeneric_async.nim
new file mode 100644
index 000000000..bab2d1a31
--- /dev/null
+++ b/tests/async/tgeneric_async.nim
@@ -0,0 +1,40 @@
+discard """
+output: "1\nmessa"
+"""
+
+import async
+
+# bug #2377
+proc test[T](v: T) {.async.} =
+  echo $v
+
+asyncCheck test[int](1)
+
+# More complex case involving typedesc and static params
+type
+  SomeMsg = object
+    data: string
+
+template msgId(M: type SomeMsg): int = 1
+
+proc recvMsg(): Future[tuple[msgId: int, msgData: string]] {.async.} =
+  return (1, "message")
+
+proc read(data: string, T: type SomeMsg, maxBytes: int): T =
+  result.data = data[0 ..< min(data.len, maxBytes)]
+
+proc nextMsg*(MsgType: typedesc,
+              maxBytes: static[int]): Future[MsgType] {.async.} =
+  const wantedId = MsgType.msgId
+
+  while true:
+    var (nextMsgId, nextMsgData) = await recvMsg()
+    if nextMsgId == wantedId:
+      return nextMsgData.read(MsgType, maxBytes)
+
+proc main {.async.} =
+  let msg = await nextMsg(SomeMsg, 5)
+  echo msg.data
+
+asyncCheck main()
+
diff --git a/tests/async/tgenericasync.nim b/tests/async/tgenericasync.nim
new file mode 100644
index 000000000..ab704238a
--- /dev/null
+++ b/tests/async/tgenericasync.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''123
+abc'''
+"""
+
+# bug #4856
+
+import asyncdispatch
+
+proc say[T](t: T): Future[void] {.async.} =
+  echo $t
+
+waitFor(say(123))
+waitFor(say("abc"))
diff --git a/tests/async/tioselectors.nim b/tests/async/tioselectors.nim
new file mode 100644
index 000000000..f53767408
--- /dev/null
+++ b/tests/async/tioselectors.nim
@@ -0,0 +1,643 @@
+discard """
+  output: "All tests passed!"
+"""
+import selectors
+
+const hasThreadSupport = compileOption("threads")
+
+template processTest(t, x: untyped) =
+  #stdout.write(t)
+  #stdout.flushFile()
+  if not x: echo(t & " FAILED\r\n")
+
+when not defined(windows):
+  import os, posix, nativesockets
+
+  when ioselSupportedPlatform:
+    import osproc
+
+  proc socket_notification_test(): bool =
+    proc create_test_socket(): SocketHandle =
+      var sock = posix.socket(posix.AF_INET, posix.SOCK_STREAM,
+                              posix.IPPROTO_TCP)
+      var x: int = fcntl(sock, F_GETFL, 0)
+      if x == -1: raiseOSError(osLastError())
+      else:
+        var mode = x or O_NONBLOCK
+        if fcntl(sock, F_SETFL, mode) == -1:
+          raiseOSError(osLastError())
+      result = sock
+
+    var client_message = "SERVER HELLO =>"
+    var server_message = "CLIENT HELLO"
+    var buffer : array[128, char]
+
+    var selector = newSelector[int]()
+    var client_socket = create_test_socket()
+    var server_socket = create_test_socket()
+
+    var option : int32 = 1
+    if setsockopt(server_socket, cint(SOL_SOCKET), cint(SO_REUSEADDR),
+                  addr(option), sizeof(option).SockLen) < 0:
+      raiseOSError(osLastError())
+
+    var aiList = getAddrInfo("0.0.0.0", Port(13337))
+    if bindAddr(server_socket, aiList.ai_addr,
+                aiList.ai_addrlen.Socklen) < 0'i32:
+      freeAddrInfo(aiList)
+      raiseOSError(osLastError())
+    if server_socket.listen() == -1:
+      raiseOSError(osLastError())
+    freeAddrInfo(aiList)
+
+    aiList = getAddrInfo("127.0.0.1", Port(13337))
+    discard posix.connect(client_socket, aiList.ai_addr,
+                          aiList.ai_addrlen.Socklen)
+
+    registerHandle(selector, server_socket, {Event.Read}, 0)
+    registerHandle(selector, client_socket, {Event.Write}, 0)
+
+    freeAddrInfo(aiList)
+
+    # 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
+    var server2_socket = accept(server_socket,
+                                cast[ptr SockAddr](addr(sockAddress)),
+                                addr(addrLen))
+    assert(server2_socket != osInvalidSocket)
+    selector.registerHandle(server2_socket, {Event.Read}, 0)
+
+    if posix.send(client_socket, addr(client_message[0]),
+                  len(client_message), 0) == -1:
+      raiseOSError(osLastError())
+
+    selector.updateHandle(client_socket, {Event.Read})
+
+    var rc2 = selector.select(100)
+    assert(len(rc2) == 1)
+
+    var read_count = posix.recv(server2_socket, addr buffer[0], 128, 0)
+    if read_count == -1:
+      raiseOSError(osLastError())
+
+    assert(read_count == len(client_message))
+    var test1 = true
+    for i in 0..<read_count:
+      if client_message[i] != buffer[i]:
+        test1 = false
+        break
+    assert(test1)
+
+    selector.updateHandle(server2_socket, {Event.Write})
+    var rc3 = selector.select(0)
+    assert(len(rc3) == 1)
+    if posix.send(server2_socket, addr(server_message[0]),
+                  len(server_message), 0) == -1:
+      raiseOSError(osLastError())
+    selector.updateHandle(server2_socket, {Event.Read})
+
+    var rc4 = selector.select(100)
+    assert(len(rc4) == 1)
+    read_count = posix.recv(client_socket, addr(buffer[0]), 128, 0)
+    if read_count == -1:
+      raiseOSError(osLastError())
+
+    assert(read_count == len(server_message))
+    var test2 = true
+    for i in 0..<read_count:
+      if server_message[i] != buffer[i]:
+        test2 = false
+        break
+    assert(test2)
+
+    selector.unregister(server_socket)
+    selector.unregister(server2_socket)
+    selector.unregister(client_socket)
+    discard posix.close(server_socket)
+    discard posix.close(server2_socket)
+    discard posix.close(client_socket)
+    assert(selector.isEmpty())
+    close(selector)
+    result = true
+
+  proc event_notification_test(): bool =
+    var selector = newSelector[int]()
+    var event = newSelectEvent()
+    selector.registerEvent(event, 1)
+    var rc0 = selector.select(0)
+    event.trigger()
+    var rc1 = selector.select(0)
+    event.trigger()
+    var rc2 = selector.select(0)
+    var rc3 = selector.select(0)
+    assert(len(rc0) == 0 and len(rc1) == 1 and len(rc2) == 1 and len(rc3) == 0)
+    var ev1 = selector.getData(rc1[0].fd)
+    var ev2 = selector.getData(rc2[0].fd)
+    assert(ev1 == 1 and ev2 == 1)
+    selector.unregister(event)
+    event.close()
+    assert(selector.isEmpty())
+    selector.close()
+    result = true
+
+  when ioselSupportedPlatform:
+    proc timer_notification_test(): bool =
+      var selector = newSelector[int]()
+      var timer = selector.registerTimer(100, false, 0)
+      var rc1 = selector.select(10000)
+      var rc2 = selector.select(10000)
+      # if this flakes, see tests/m14634.nim
+      assert len(rc1) == 1 and len(rc2) == 1, $(len(rc1), len(rc2))
+      selector.unregister(timer)
+      discard selector.select(0)
+      selector.registerTimer(100, true, 0)
+      var rc4 = selector.select(10000)
+      var rc5 = selector.select(1000) # this will be an actual wait, keep it small
+      assert len(rc4) == 1 and len(rc5) == 0, $(len(rc4), len(rc5))
+      assert(selector.isEmpty())
+      selector.close()
+      result = true
+
+    proc process_notification_test(): bool =
+      var selector = newSelector[int]()
+      var process2 = startProcess("sleep", "", ["2"], nil,
+                           {poStdErrToStdOut, poUsePath})
+      discard startProcess("sleep", "", ["1"], nil,
+                           {poStdErrToStdOut, poUsePath})
+
+      selector.registerProcess(process2.processID, 0)
+      var rc1 = selector.select(1500)
+      var rc2 = selector.select(1500)
+      var r = len(rc1) + len(rc2)
+      assert(r == 1)
+      result = true
+
+    proc signal_notification_test(): bool =
+      var sigset1n, sigset1o, sigset2n, sigset2o: Sigset
+      var pid = posix.getpid()
+
+      discard sigemptyset(sigset1n)
+      discard sigemptyset(sigset1o)
+      discard sigemptyset(sigset2n)
+      discard sigemptyset(sigset2o)
+
+      when hasThreadSupport:
+        if pthread_sigmask(SIG_BLOCK, sigset1n, sigset1o) == -1:
+          raiseOSError(osLastError())
+      else:
+        if sigprocmask(SIG_BLOCK, sigset1n, sigset1o) == -1:
+          raiseOSError(osLastError())
+
+      var selector = newSelector[int]()
+      var s1 = selector.registerSignal(SIGUSR1, 1)
+      var s2 = selector.registerSignal(SIGUSR2, 2)
+      var s3 = selector.registerSignal(SIGTERM, 3)
+      discard selector.select(0)
+      discard posix.kill(pid, SIGUSR1)
+      discard posix.kill(pid, SIGUSR2)
+      discard posix.kill(pid, SIGTERM)
+      var rc = selector.select(0)
+      var cd0 = selector.getData(rc[0].fd)
+      var cd1 = selector.getData(rc[1].fd)
+      var cd2 = selector.getData(rc[2].fd)
+      selector.unregister(s1)
+      selector.unregister(s2)
+      selector.unregister(s3)
+
+      when hasThreadSupport:
+        if pthread_sigmask(SIG_BLOCK, sigset2n, sigset2o) == -1:
+          raiseOSError(osLastError())
+      else:
+        if sigprocmask(SIG_BLOCK, sigset2n, sigset2o) == -1:
+          raiseOSError(osLastError())
+
+      assert(len(rc) == 3)
+      assert(cd0 + cd1 + cd2 == 6, $(cd0 + cd1 + cd2)) # 1 + 2 + 3
+      assert(equalMem(addr sigset1o, addr sigset2o, sizeof(Sigset)))
+      assert(selector.isEmpty())
+      result = true
+
+  when defined(macosx) or defined(freebsd) or defined(openbsd) or
+       defined(netbsd):
+
+    proc rename(frompath: cstring, topath: cstring): cint
+       {.importc: "rename", header: "<stdio.h>".}
+
+    proc createFile(name: string): cint =
+      result = posix.open(cstring(name), posix.O_CREAT or posix.O_RDWR)
+      if result == -1:
+        raiseOsError(osLastError())
+
+    proc writeFile(name: string, data: string) =
+      let fd = posix.open(cstring(name), posix.O_APPEND or posix.O_RDWR)
+      if fd == -1:
+        raiseOsError(osLastError())
+      let length = len(data).cint
+      if posix.write(fd, cast[pointer](addr data[0]),
+                     len(data).cint) != length:
+        raiseOsError(osLastError())
+      if posix.close(fd) == -1:
+        raiseOsError(osLastError())
+
+    proc closeFile(fd: cint) =
+      if posix.close(fd) == -1:
+        raiseOsError(osLastError())
+
+    proc removeFile(name: string) =
+      let err = posix.unlink(cstring(name))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc createDir(name: string) =
+      let err = posix.mkdir(cstring(name), 0x1FF)
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc removeDir(name: string) =
+      let err = posix.rmdir(cstring(name))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc chmodPath(name: string, mode: cint) =
+      let err = posix.chmod(cstring(name), Mode(mode))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc renameFile(names: string, named: string) =
+      let err = rename(cstring(names), cstring(named))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc symlink(names: string, named: string) =
+      let err = posix.symlink(cstring(names), cstring(named))
+      if err == -1:
+        raiseOsError(osLastError())
+
+    proc openWatch(name: string): cint =
+      result = posix.open(cstring(name), posix.O_RDONLY)
+      if result == -1:
+        raiseOsError(osLastError())
+
+    const
+      testDirectory = "/tmp/kqtest"
+
+    type
+      valType = object
+        fd: cint
+        events: set[Event]
+
+    proc vnode_test(): bool =
+      proc validate(test: openArray[ReadyKey],
+                    check: openArray[valType]): bool =
+        result = false
+        if len(test) == len(check):
+          for checkItem in check:
+            result = false
+            for testItem in test:
+              if testItem.fd == checkItem.fd and
+                 checkItem.events <= testItem.events:
+                result = true
+                break
+            if not result:
+              break
+
+      var res: seq[ReadyKey]
+      var selector = newSelector[int]()
+      var events = {Event.VnodeWrite, Event.VnodeDelete, Event.VnodeExtend,
+                    Event.VnodeAttrib, Event.VnodeLink, Event.VnodeRename,
+                    Event.VnodeRevoke}
+
+      result = true
+      discard posix.unlink(testDirectory)
+
+      createDir(testDirectory)
+      var dirfd = posix.open(cstring(testDirectory), posix.O_RDONLY)
+      if dirfd == -1:
+        raiseOsError(osLastError())
+
+      selector.registerVnode(dirfd, events, 1)
+      discard selector.select(0)
+
+      # chmod testDirectory to 0777
+      chmodPath(testDirectory, 0x1FF)
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeAttrib} <= res[0].events)
+
+      # create subdirectory
+      createDir(testDirectory & "/test")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite,
+                Event.VnodeLink} <= res[0].events)
+
+      # open test directory for watching
+      var testfd = openWatch(testDirectory & "/test")
+      selector.registerVnode(testfd, events, 2)
+      doAssert(len(selector.select(0)) == 0)
+
+      # rename test directory
+      renameFile(testDirectory & "/test", testDirectory & "/renamed")
+      res = selector.select(0)
+      doAssert(len(res) == 2)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(validate(res,
+                 [valType(fd: dirfd, events: {Event.Vnode, Event.VnodeWrite}),
+                  valType(fd: testfd,
+                          events: {Event.Vnode, Event.VnodeRename})])
+              )
+
+      # remove test directory
+      removeDir(testDirectory & "/renamed")
+      res = selector.select(0)
+      doAssert(len(res) == 2)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(validate(res,
+                 [valType(fd: dirfd, events: {Event.Vnode, Event.VnodeWrite,
+                                              Event.VnodeLink}),
+                  valType(fd: testfd,
+                          events: {Event.Vnode, Event.VnodeDelete})])
+              )
+      # create file new test file
+      testfd = createFile(testDirectory & "/testfile")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite} <= res[0].events)
+
+      # close new test file
+      closeFile(testfd)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(len(selector.select(0)) == 0)
+
+      # chmod test file with 0666
+      chmodPath(testDirectory & "/testfile", 0x1B6)
+      doAssert(len(selector.select(0)) == 0)
+
+      testfd = openWatch(testDirectory & "/testfile")
+      selector.registerVnode(testfd, events, 1)
+      discard selector.select(0)
+
+      # write data to test file
+      writeFile(testDirectory & "/testfile", "TESTDATA")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == testfd and
+              {Event.Vnode, Event.VnodeWrite,
+               Event.VnodeExtend} <= res[0].events)
+
+      # symlink test file
+      symlink(testDirectory & "/testfile", testDirectory & "/testlink")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite} <= res[0].events)
+
+      # remove test file
+      removeFile(testDirectory & "/testfile")
+      res = selector.select(0)
+      doAssert(len(res) == 2)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(validate(res,
+                [valType(fd: testfd, events: {Event.Vnode, Event.VnodeDelete}),
+                 valType(fd: dirfd, events: {Event.Vnode, Event.VnodeWrite})])
+              )
+
+      # remove symlink
+      removeFile(testDirectory & "/testlink")
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      doAssert(res[0].fd == dirfd and
+               {Event.Vnode, Event.VnodeWrite} <= res[0].events)
+
+      # remove testDirectory
+      removeDir(testDirectory)
+      res = selector.select(0)
+      doAssert(len(res) == 1)
+      doAssert(len(selector.select(0)) == 0)
+      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
+
+    proc event_wait_thread(event: SelectEvent) {.thread.} =
+      var selector = newSelector[int]()
+      selector.registerEvent(event, 1)
+      var rc = selector.select(1000)
+      if len(rc) == 1:
+        inc(counter)
+      selector.unregister(event)
+      assert(selector.isEmpty())
+
+    proc mt_event_test(): bool =
+      var
+        thr: array[0..7, Thread[SelectEvent]]
+      var selector = newSelector[int]()
+      var sock = createNativeSocket()
+      var event = newSelectEvent()
+      for i in 0..high(thr):
+        createThread(thr[i], event_wait_thread, event)
+      selector.registerHandle(sock, {Event.Read}, 1)
+      discard selector.select(500)
+      selector.unregister(sock)
+      event.trigger()
+      joinThreads(thr)
+      assert(counter == 1)
+      result = true
+
+  processTest("Socket notification test...", socket_notification_test())
+  processTest("User event notification test...", event_notification_test())
+  when hasThreadSupport:
+    processTest("Multithreaded user event notification test...",
+                mt_event_test())
+  when ioselSupportedPlatform:
+    processTest("Timer notification test...", timer_notification_test())
+    processTest("Process notification test...", process_notification_test())
+    processTest("Signal notification test...", signal_notification_test())
+  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
+
+  proc socket_notification_test(): bool =
+    proc create_test_socket(): SocketHandle =
+      var sock = createNativeSocket()
+      setBlocking(sock, false)
+      result = sock
+
+    var client_message = "SERVER HELLO =>"
+    var server_message = "CLIENT HELLO"
+    var buffer : array[128, char]
+
+    var selector = newSelector[int]()
+    var client_socket = create_test_socket()
+    var server_socket = create_test_socket()
+
+    selector.registerHandle(server_socket, {Event.Read}, 0)
+    selector.registerHandle(client_socket, {Event.Write}, 0)
+
+    var option : int32 = 1
+    if setsockopt(server_socket, cint(SOL_SOCKET), cint(SO_REUSEADDR),
+                  addr(option), sizeof(option).SockLen) < 0:
+      raiseOSError(osLastError())
+
+    var aiList = getAddrInfo("0.0.0.0", Port(13337))
+    if bindAddr(server_socket, aiList.ai_addr,
+                aiList.ai_addrlen.Socklen) < 0'i32:
+      freeAddrInfo(aiList)
+      raiseOSError(osLastError())
+    discard server_socket.listen()
+    freeAddrInfo(aiList)
+
+    aiList = getAddrInfo("127.0.0.1", Port(13337))
+    discard connect(client_socket, aiList.ai_addr,
+                    aiList.ai_addrlen.Socklen)
+    freeAddrInfo(aiList)
+    # for some reason Windows select doesn't return both
+    # descriptors from first call, so we need to make 2 calls
+    var n = 0
+    var rcm = selector.select(1000)
+    while n < 10 and len(rcm) < 2:
+      sleep(1000)
+      rcm = selector.select(1000)
+      inc(n)
+
+    assert(len(rcm) == 2)
+
+    var sockAddress = SockAddr()
+    var addrLen = sizeof(sockAddress).Socklen
+    var server2_socket = accept(server_socket,
+                                cast[ptr SockAddr](addr(sockAddress)),
+                                addr(addrLen))
+    assert(server2_socket != osInvalidSocket)
+    selector.registerHandle(server2_socket, {Event.Read}, 0)
+
+    if send(client_socket, cast[pointer](addr(client_message[0])),
+            cint(len(client_message)), 0) == -1:
+      raiseOSError(osLastError())
+
+    selector.updateHandle(client_socket, {Event.Read})
+
+    var rc2 = selector.select(1000)
+    assert(len(rc2) == 1)
+
+    var read_count = recv(server2_socket, addr buffer[0], 128, 0)
+    if read_count == -1:
+      raiseOSError(osLastError())
+
+    assert(read_count == len(client_message))
+    var test1 = true
+    for i in 0..<read_count:
+      if client_message[i] != buffer[i]:
+        test1 = false
+        break
+    assert(test1)
+
+    if send(server2_socket, cast[pointer](addr(server_message[0])),
+                  cint(len(server_message)), 0) == -1:
+      raiseOSError(osLastError())
+
+    var rc3 = selector.select(0)
+    assert(len(rc3) == 1)
+    read_count = recv(client_socket, addr(buffer[0]), 128, 0)
+    if read_count == -1:
+      raiseOSError(osLastError())
+
+    assert(read_count == len(server_message))
+    var test2 = true
+    for i in 0..<read_count:
+      if server_message[i] != buffer[i]:
+        test2 = false
+        break
+    assert(test2)
+
+    selector.unregister(server_socket)
+    selector.unregister(server2_socket)
+    selector.unregister(client_socket)
+    close(server_socket)
+    close(server2_socket)
+    close(client_socket)
+    assert(selector.isEmpty())
+    close(selector)
+    result = true
+
+  proc event_notification_test(): bool =
+    var selector = newSelector[int]()
+    var event = newSelectEvent()
+    selector.registerEvent(event, 1)
+    discard selector.select(0)
+    event.trigger()
+    var rc1 = selector.select(0)
+    event.trigger()
+    var rc2 = selector.select(0)
+    var rc3 = selector.select(0)
+    assert(len(rc1) == 1 and len(rc2) == 1 and len(rc3) == 0)
+    var ev1 = selector.getData(rc1[0].fd)
+    var ev2 = selector.getData(rc2[0].fd)
+    assert(ev1 == 1 and ev2 == 1)
+    selector.unregister(event)
+    event.close()
+    assert(selector.isEmpty())
+    selector.close()
+    result = true
+
+  when hasThreadSupport:
+    var counter = 0
+
+    proc event_wait_thread(event: SelectEvent) {.thread.} =
+      var selector = newSelector[int]()
+      selector.registerEvent(event, 1)
+      var rc = selector.select(1500)
+      if len(rc) == 1:
+        inc(counter)
+      selector.unregister(event)
+      assert(selector.isEmpty())
+
+    proc mt_event_test(): bool =
+      var thr: array[0..7, Thread[SelectEvent]]
+      var event = newSelectEvent()
+      for i in 0..high(thr):
+        createThread(thr[i], event_wait_thread, event)
+      event.trigger()
+      joinThreads(thr)
+      assert(counter == 1)
+      result = true
+
+  processTest("Socket notification test...", socket_notification_test())
+  processTest("User event notification test...", event_notification_test())
+  when hasThreadSupport:
+    processTest("Multithreaded user event notification test...",
+                 mt_event_test())
+  echo("All tests passed!")
diff --git a/tests/async/tioselectors.nim.cfg b/tests/async/tioselectors.nim.cfg
new file mode 100644
index 000000000..b1b896858
--- /dev/null
+++ b/tests/async/tioselectors.nim.cfg
@@ -0,0 +1 @@
+threads:on -d:threadsafe
diff --git a/tests/async/tjsandnativeasync.nim b/tests/async/tjsandnativeasync.nim
new file mode 100644
index 000000000..c4db3bcfb
--- /dev/null
+++ b/tests/async/tjsandnativeasync.nim
@@ -0,0 +1,30 @@
+discard """
+  output: '''hi
+bye'''
+"""
+
+import async, times
+when defined(js):
+    proc sleepAsync(t: int): Future[void] =
+        var promise = newPromise() do(resolve: proc()):
+            {.emit: """
+            setTimeout(function(){
+                `resolve`();
+            }, `t`);
+            """.}
+        result = promise
+else:
+    from asyncdispatch import sleepAsync, waitFor
+
+proc foo() {.async.} =
+    echo "hi"
+    var s = epochTime()
+    await sleepAsync(200)
+    var e = epochTime()
+    doAssert(e - s > 0.1)
+    echo "bye"
+
+when defined(js):
+    discard foo()
+else:
+    waitFor foo()
diff --git a/tests/async/tlambda.nim b/tests/async/tlambda.nim
new file mode 100644
index 000000000..8f570689b
--- /dev/null
+++ b/tests/async/tlambda.nim
@@ -0,0 +1,58 @@
+
+# bug 2007
+
+import asyncdispatch, asyncnet, logging, json, uri, strutils, sugar
+
+type
+  Builder = ref object
+    client: Client
+    build: Build
+
+  ProgressCB* = proc (message: string): Future[void] {.closure, gcsafe.}
+
+  Build* = ref object
+    onProgress*: ProgressCB
+
+  Client = ref ClientObj
+  ClientObj = object
+    onMessage: proc (client: Client, msg: JsonNode): Future[void]
+
+proc newClient*(name: string,
+                onMessage: (Client, JsonNode) -> Future[void]): Client =
+  new result
+  result.onMessage = onMessage
+
+proc newBuild*(onProgress: ProgressCB): Build =
+  new result
+  result.onProgress = onProgress
+
+proc start(build: Build, repo, hash: string) {.async.} =
+  let path = repo.parseUri().path.toLowerAscii()
+
+proc onProgress(builder: Builder, message: string) {.async.} =
+  debug($message)
+
+proc onMessage(builder: Builder, message: JsonNode) {.async.} =
+  debug("onMessage")
+
+proc newBuilder(): Builder =
+  var cres: Builder
+  new cres
+
+  cres.client = newClient("builder", (client, msg) => (onMessage(cres, msg)))
+  cres.build = newBuild(
+      proc (msg: string): Future[void] {.closure, gcsafe.} = onProgress(cres, msg))
+  return cres
+
+proc main() =
+  # Set up logging.
+  var console = newConsoleLogger(fmtStr = verboseFmtStr)
+  addHandler(console)
+
+  var builder = newBuilder()
+
+  # Test {.async.} pragma with do notation: #5995
+  builder.client = newClient("builder") do(client: Client, msg: JsonNode) {.async.}:
+    await onMessage(builder, msg)
+
+main()
diff --git a/tests/async/tmultisync.nim b/tests/async/tmultisync.nim
new file mode 100644
index 000000000..9ef9b105c
--- /dev/null
+++ b/tests/async/tmultisync.nim
@@ -0,0 +1,8 @@
+import asyncdispatch, net, asyncnet
+
+proc recvTwice(socket: Socket | AsyncSocket,
+               size: int): Future[string] {.multisync.} =
+  var x = await socket.recv(size)
+  var y = await socket.recv(size+1)
+  return x & "aboo" & y
+
diff --git a/tests/async/tnestedpfuturetypeparam.nim b/tests/async/tnestedpfuturetypeparam.nim
new file mode 100644
index 000000000..bf346ff8e
--- /dev/null
+++ b/tests/async/tnestedpfuturetypeparam.nim
@@ -0,0 +1,8 @@
+import asyncdispatch, asyncnet
+
+proc main {.async.} =
+  proc f: Future[seq[int]] {.async.} =
+    await newAsyncSocket().connect("www.google.com", Port(80))
+  let x = await f()
+
+asyncCheck main()
diff --git a/tests/async/tnewasyncudp.nim b/tests/async/tnewasyncudp.nim
new file mode 100644
index 000000000..68de796a0
--- /dev/null
+++ b/tests/async/tnewasyncudp.nim
@@ -0,0 +1,111 @@
+discard """
+  output: "5000"
+"""
+import asyncdispatch, nativesockets, net, strutils, os
+
+when defined(windows):
+  import winlean
+else:
+  import posix
+
+var msgCount = 0
+var recvCount = 0
+
+const
+  messagesToSend = 100
+  swarmSize = 50
+  serverPort = 10333
+
+var
+  sendports = 0
+  recvports = 0
+
+proc saveSendingPort(port: int) =
+  sendports = sendports + port
+
+proc saveReceivedPort(port: int) =
+  recvports = recvports + port
+
+proc prepareAddress(intaddr: uint32, intport: uint16): ptr Sockaddr_in =
+  result = cast[ptr Sockaddr_in](alloc0(sizeof(Sockaddr_in)))
+  result.sin_family = typeof(result.sin_family)(toInt(nativesockets.AF_INET))
+  result.sin_port = nativesockets.htons(intport)
+  result.sin_addr.s_addr = nativesockets.htonl(intaddr)
+
+proc launchSwarm(name: ptr SockAddr) {.async.} =
+  var i = 0
+  var k = 0
+  var buffer: array[16384, char]
+  var slen = sizeof(Sockaddr_in).SockLen
+  var saddr = Sockaddr_in()
+  while i < swarmSize:
+    var peeraddr = prepareAddress(INADDR_LOOPBACK, 0)
+    var sock = createAsyncNativeSocket(nativesockets.AF_INET,
+                                       nativesockets.SOCK_DGRAM,
+                                       Protocol.IPPROTO_UDP)
+    if bindAddr(sock.SocketHandle, cast[ptr SockAddr](peeraddr),
+              sizeof(Sockaddr_in).Socklen) < 0'i32:
+      raiseOSError(osLastError())
+    let sockport = getSockName(sock.SocketHandle).int
+    k = 0
+    while k < messagesToSend:
+      zeroMem(addr(buffer[0]), 16384)
+      zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in))
+      var message = "Message " & $(i * messagesToSend + k)
+      await sendTo(sock, addr message[0], len(message),
+                   name, sizeof(Sockaddr_in).SockLen)
+      var size = await recvFromInto(sock, cast[pointer](addr buffer[0]),
+                                    16384, cast[ptr SockAddr](addr saddr),
+                                    addr slen)
+      size = 0
+      var grammString = $cast[cstring](addr buffer)
+      if grammString == message:
+        saveSendingPort(sockport)
+        inc(recvCount)
+      inc(k)
+    closeSocket(sock)
+    inc(i)
+
+proc readMessages(server: AsyncFD) {.async.} =
+  var buffer: array[16384, char]
+  var slen = sizeof(Sockaddr_in).SockLen
+  var saddr = Sockaddr_in()
+  var maxResponses = (swarmSize * messagesToSend)
+
+  var i = 0
+  while i < maxResponses:
+    zeroMem(addr(buffer[0]), 16384)
+    zeroMem(cast[pointer](addr(saddr)), sizeof(Sockaddr_in))
+    var size = await recvFromInto(server, cast[cstring](addr buffer[0]),
+                                  16384, cast[ptr SockAddr](addr(saddr)),
+                                  addr(slen))
+    size = 0
+    var grammString = $cast[cstring](addr buffer)
+    if grammString.startsWith("Message ") and
+       saddr.sin_addr.s_addr == nativesockets.ntohl(INADDR_LOOPBACK.uint32):
+      await sendTo(server, addr grammString[0], len(grammString),
+                   cast[ptr SockAddr](addr saddr), slen)
+      inc(msgCount)
+      saveReceivedPort(nativesockets.ntohs(saddr.sin_port).int)
+    inc(i)
+
+proc createServer() {.async.} =
+  var name = prepareAddress(INADDR_LOOPBACK, serverPort)
+  var server = createAsyncNativeSocket(nativesockets.AF_INET,
+                                       nativesockets.SOCK_DGRAM,
+                                       Protocol.IPPROTO_UDP)
+  if bindAddr(server.SocketHandle, cast[ptr SockAddr](name),
+              sizeof(Sockaddr_in).Socklen) < 0'i32:
+    raiseOSError(osLastError())
+  asyncCheck readMessages(server)
+
+var name = prepareAddress(INADDR_LOOPBACK, serverPort) # 127.0.0.1
+asyncCheck createServer()
+asyncCheck launchSwarm(cast[ptr SockAddr](name))
+while true:
+  poll()
+  if recvCount == swarmSize * messagesToSend:
+    break
+assert msgCount == swarmSize * messagesToSend
+assert sendports == recvports
+echo msgCount
diff --git a/tests/async/tnimcall_to_closure.nim b/tests/async/tnimcall_to_closure.nim
new file mode 100644
index 000000000..748b67cb1
--- /dev/null
+++ b/tests/async/tnimcall_to_closure.nim
@@ -0,0 +1,17 @@
+
+import asyncdispatch
+
+proc defaultOnProgressChanged() = discard
+
+proc ask(x: proc()) = x()
+
+proc retrFile*(onProgressChanged: proc() {.nimcall.}): Future[void] =
+  var retFuture = newFuture[void]("retrFile")
+  iterator retrFileIter(): FutureBase {.closure.} =
+    ask(onProgressChanged)
+    complete(retFuture)
+
+  var nameIterVar = retrFileIter
+  return retFuture
+
+discard retrFile(defaultOnProgressChanged)
diff --git a/tests/async/tpendingcheck.nim b/tests/async/tpendingcheck.nim
new file mode 100644
index 000000000..4eceb0353
--- /dev/null
+++ b/tests/async/tpendingcheck.nim
@@ -0,0 +1,18 @@
+discard """
+  output: ""
+"""
+
+import asyncdispatch
+
+doAssert(not hasPendingOperations())
+
+proc test() {.async.} =
+  await sleepAsync(50)
+
+var f = test()
+while not f.finished:
+  doAssert(hasPendingOperations())
+  poll(10)
+f.read
+
+doAssert(not hasPendingOperations())
diff --git a/tests/async/tpolltimeouts.nim b/tests/async/tpolltimeouts.nim
new file mode 100644
index 000000000..dac33732d
--- /dev/null
+++ b/tests/async/tpolltimeouts.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "true"
+"""
+# Issue https://github.com/nim-lang/Nim/issues/4262
+import asyncdispatch, times
+
+proc foo(): Future[int] {.async.} =
+  return 1
+
+proc bar(): Future[int] {.async.} =
+  return await foo()
+
+let start = epochTime()
+let barFut = bar()
+
+while not barFut.finished:
+  poll(2000)
+
+echo(epochTime() - start < 1.0)
diff --git a/tests/async/treturn_await.nim b/tests/async/treturn_await.nim
new file mode 100644
index 000000000..8d266d665
--- /dev/null
+++ b/tests/async/treturn_await.nim
@@ -0,0 +1,23 @@
+
+# bug #4371
+
+import strutils, asyncdispatch, asynchttpserver
+
+type
+  List[A] = ref object
+    value: A
+    next: List[A]
+  StrPair* = tuple[k, v: string]
+  Context* = object
+    position*: int
+    accept*: bool
+    headers*: List[StrPair]
+  Handler* = proc(req: ref Request, ctx: Context): Future[Context]
+
+proc logging*(handler: Handler): auto =
+  proc h(req: ref Request, ctx: Context): Future[Context] {.async.} =
+    let ret = handler(req, ctx)
+    debugEcho "$3 $1 $2".format(req.reqMethod, req.url.path, req.hostname)
+    return await ret
+
+  return h
diff --git a/tests/async/ttemplateinasync.nim b/tests/async/ttemplateinasync.nim
new file mode 100644
index 000000000..f4a2da538
--- /dev/null
+++ b/tests/async/ttemplateinasync.nim
@@ -0,0 +1,11 @@
+discard """
+  output: 42
+"""
+
+import asyncdispatch
+
+proc foo(): Future[int] {.async.} =
+  template ret() = return 42
+  ret()
+
+echo (waitFor foo())
diff --git a/tests/async/tupcoming_async.nim b/tests/async/tupcoming_async.nim
new file mode 100644
index 000000000..0b6e53454
--- /dev/null
+++ b/tests/async/tupcoming_async.nim
@@ -0,0 +1,157 @@
+discard """
+  output: '''
+OK
+'''
+"""
+
+when defined(upcoming):
+  import asyncdispatch, times, streams, posix
+  from ioselectors import ioselSupportedPlatform
+
+  proc delayedSet(ev: AsyncEvent, timeout: int): Future[void] {.async.} =
+    await sleepAsync(timeout)
+    ev.trigger()
+
+  proc waitEvent(ev: AsyncEvent, closeEvent = false): Future[void] =
+    var retFuture = newFuture[void]("waitEvent")
+    proc cb(fd: AsyncFD): bool =
+      retFuture.complete()
+      if closeEvent:
+        return true
+      else:
+        return false
+    addEvent(ev, cb)
+    return retFuture
+
+  proc eventTest() =
+    var event = newAsyncEvent()
+    var fut = waitEvent(event)
+    asyncCheck(delayedSet(event, 500))
+    waitFor(fut or sleepAsync(1000))
+    if not fut.finished:
+      echo "eventTest: Timeout expired before event received!"
+
+  proc eventTest5304() =
+    # Event should not be signaled if it was uregistered,
+    # even in case, when poll() was not called yet.
+    # Issue #5304.
+    var unregistered = false
+    let e = newAsyncEvent()
+    addEvent(e) do (fd: AsyncFD) -> bool:
+      assert(not unregistered)
+    e.trigger()
+    e.unregister()
+    unregistered = true
+    poll()
+
+  proc eventTest5298() =
+    # Event must raise `AssertionDefect` if event was unregistered twice.
+    # Issue #5298.
+    let e = newAsyncEvent()
+    var eventReceived = false
+    addEvent(e) do (fd: AsyncFD) -> bool:
+      eventReceived = true
+      return true
+    e.trigger()
+    while not eventReceived:
+      poll()
+    try:
+      e.unregister()
+    except AssertionDefect:
+      discard
+    e.close()
+
+  proc eventTest5331() =
+    # Event must not raise any exceptions while was unregistered inside of
+    # own callback.
+    # Issue #5331.
+    let e = newAsyncEvent()
+    addEvent(e) do (fd: AsyncFD) -> bool:
+      e.unregister()
+      e.close()
+    e.trigger()
+    poll()
+
+  when ioselSupportedPlatform or defined(windows):
+
+    import osproc
+
+    proc waitTimer(timeout: int): Future[void] =
+      var retFuture = newFuture[void]("waitTimer")
+      proc cb(fd: AsyncFD): bool =
+        retFuture.complete()
+      addTimer(timeout, true, cb)
+      return retFuture
+
+    proc waitProcess(p: Process): Future[void] =
+      var retFuture = newFuture[void]("waitProcess")
+      proc cb(fd: AsyncFD): bool =
+        retFuture.complete()
+      addProcess(p.processID(), cb)
+      return retFuture
+
+    proc timerTest() =
+      waitFor(waitTimer(200))
+
+    proc processTest() =
+      when defined(windows):
+        var process = startProcess("ping.exe", "",
+                                   ["127.0.0.1", "-n", "2", "-w", "100"], nil,
+                                   {poStdErrToStdOut, poUsePath, poInteractive,
+                                   poDaemon})
+      else:
+        var process = startProcess("sleep", "", ["1"], nil,
+                                   {poStdErrToStdOut, poUsePath})
+      var fut = waitProcess(process)
+      waitFor(fut or waitTimer(2000))
+      if fut.finished and process.peekExitCode() == 0:
+        discard
+      else:
+        echo "processTest: Timeout expired before process exited!"
+
+  when ioselSupportedPlatform:
+
+    proc waitSignal(signal: int): Future[void] =
+      var retFuture = newFuture[void]("waitSignal")
+      proc cb(fd: AsyncFD): bool =
+        retFuture.complete()
+      addSignal(signal, cb)
+      return retFuture
+
+    proc delayedSignal(signal: int, timeout: int): Future[void] {.async.} =
+      await waitTimer(timeout)
+      var pid = posix.getpid()
+      discard posix.kill(pid, signal.cint)
+
+    proc signalTest() =
+      var fut = waitSignal(posix.SIGINT)
+      asyncCheck(delayedSignal(posix.SIGINT, 500))
+      waitFor(fut or waitTimer(1000))
+      if not fut.finished:
+        echo "signalTest: Timeout expired before signal received!"
+
+  when ioselSupportedPlatform:
+    timerTest()
+    eventTest()
+    eventTest5304()
+    eventTest5298()
+    eventTest5331()
+    processTest()
+    signalTest()
+    echo "OK"
+  elif defined(windows):
+    timerTest()
+    eventTest()
+    eventTest5304()
+    eventTest5298()
+    eventTest5331()
+    processTest()
+    echo "OK"
+  else:
+    eventTest()
+    eventTest5304()
+    eventTest5298()
+    eventTest5331()
+    echo "OK"
+else:
+  echo "OK"
diff --git a/tests/async/twinasyncrw.nim b/tests/async/twinasyncrw.nim
new file mode 100644
index 000000000..f0a8f6a62
--- /dev/null
+++ b/tests/async/twinasyncrw.nim
@@ -0,0 +1,243 @@
+when defined(windows):
+  import asyncdispatch, nativesockets, net, strutils, os, winlean
+  from stdtest/netutils import bindAvailablePort
+  var msgCount = 0
+
+  const
+    swarmSize = 50
+    messagesToSend = 100
+
+  var clientCount = 0
+
+  proc winConnect*(socket: AsyncFD, address: string, port: Port,
+      domain = Domain.AF_INET): Future[void] =
+    var retFuture = newFuture[void]("winConnect")
+    proc cb(fd: AsyncFD): bool =
+      var ret = SocketHandle(fd).getSockOptInt(cint(SOL_SOCKET), cint(SO_ERROR))
+      if ret == 0:
+          # We have connected.
+          retFuture.complete()
+          return true
+      else:
+          retFuture.fail(newOSError(OSErrorCode(ret)))
+          return true
+
+    var aiList = getAddrInfo(address, port, domain)
+    var success = false
+    var lastError: OSErrorCode = OSErrorCode(0)
+    var it = aiList
+    while it != nil:
+      var ret = nativesockets.connect(socket.SocketHandle, it.ai_addr, it.ai_addrlen.Socklen)
+      if ret == 0:
+        # Request to connect completed immediately.
+        success = true
+        retFuture.complete()
+        break
+      else:
+        lastError = osLastError()
+        if lastError.int32 == WSAEWOULDBLOCK:
+          success = true
+          addWrite(socket, cb)
+          break
+        else:
+          success = false
+      it = it.ai_next
+
+    freeAddrInfo(aiList)
+    if not success:
+      retFuture.fail(newOSError(lastError))
+    return retFuture
+
+  proc winRecv*(socket: AsyncFD, size: int,
+             flags = {SocketFlag.SafeDisconn}): Future[string] =
+    var retFuture = newFuture[string]("recv")
+
+    var readBuffer = newString(size)
+
+    proc cb(sock: AsyncFD): bool =
+      result = true
+      let res = recv(sock.SocketHandle, addr readBuffer[0], size.cint,
+                     flags.toOSFlags())
+      if res < 0:
+        let lastError = osLastError()
+        if flags.isDisconnectionError(lastError):
+          retFuture.complete("")
+        else:
+          retFuture.fail(newOSError(lastError))
+      elif res == 0:
+        # Disconnected
+        retFuture.complete("")
+      else:
+        readBuffer.setLen(res)
+        retFuture.complete(readBuffer)
+    # TODO: The following causes a massive slowdown.
+    #if not cb(socket):
+    addRead(socket, cb)
+    return retFuture
+
+  proc winRecvInto*(socket: AsyncFD, buf: cstring, size: int,
+                  flags = {SocketFlag.SafeDisconn}): Future[int] =
+    var retFuture = newFuture[int]("winRecvInto")
+
+    proc cb(sock: AsyncFD): bool =
+      result = true
+      let res = nativesockets.recv(sock.SocketHandle, buf, size.cint,
+                                   flags.toOSFlags())
+      if res < 0:
+        let lastError = osLastError()
+        if flags.isDisconnectionError(lastError):
+          retFuture.complete(0)
+        else:
+          retFuture.fail(newOSError(lastError))
+      else:
+        retFuture.complete(res)
+    # TODO: The following causes a massive slowdown.
+    #if not cb(socket):
+    addRead(socket, cb)
+    return retFuture
+
+  proc winSend*(socket: AsyncFD, data: string,
+             flags = {SocketFlag.SafeDisconn}): Future[void] =
+    var retFuture = newFuture[void]("winSend")
+
+    var written = 0
+
+    proc cb(sock: AsyncFD): bool =
+      result = true
+      let netSize = data.len-written
+      var d = data.cstring
+      let res = nativesockets.send(sock.SocketHandle, addr d[written], netSize.cint, 0)
+      if res < 0:
+        let lastError = osLastError()
+        if flags.isDisconnectionError(lastError):
+          retFuture.complete()
+        else:
+          retFuture.fail(newOSError(lastError))
+      else:
+        written.inc(res)
+        if res != netSize:
+          result = false # We still have data to send.
+        else:
+          retFuture.complete()
+    # TODO: The following causes crashes.
+    #if not cb(socket):
+    addWrite(socket, cb)
+    return retFuture
+
+  proc winAcceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}):
+      Future[tuple[address: string, client: AsyncFD]] =
+    var retFuture = newFuture[tuple[address: string,
+        client: AsyncFD]]("winAcceptAddr")
+    proc cb(sock: AsyncFD): bool =
+      result = true
+      if not retFuture.finished:
+        var sockAddress = Sockaddr()
+        var addrLen = sizeof(sockAddress).Socklen
+        var client = nativesockets.accept(sock.SocketHandle,
+                                          cast[ptr SockAddr](addr(sockAddress)), addr(addrLen))
+        if client == osInvalidSocket:
+          retFuture.fail(newOSError(osLastError()))
+        else:
+          retFuture.complete((getAddrString(cast[ptr SockAddr](addr sockAddress)), client.AsyncFD))
+
+    addRead(socket, cb)
+    return retFuture
+
+  proc winAccept*(socket: AsyncFD,
+      flags = {SocketFlag.SafeDisconn}): Future[AsyncFD] =
+    ## Accepts a new connection. Returns a future containing the client socket
+    ## corresponding to that connection.
+    ## The future will complete when the connection is successfully accepted.
+    var retFut = newFuture[AsyncFD]("winAccept")
+    var fut = winAcceptAddr(socket, flags)
+    fut.callback =
+      proc (future: Future[tuple[address: string, client: AsyncFD]]) =
+        assert future.finished
+        if future.failed:
+          retFut.fail(future.error)
+        else:
+          retFut.complete(future.read.client)
+    return retFut
+
+
+  proc winRecvLine*(socket: AsyncFD): Future[string] {.async.} =
+    ## Reads a line of data from ``socket``. Returned future will complete once
+    ## a full line is read or an error occurs.
+    ##
+    ## If a full line is read ``\r\L`` is not
+    ## added to ``line``, however if solely ``\r\L`` is read then ``line``
+    ## will be set to it.
+    ##
+    ## If the socket is disconnected, ``line`` will be set to ``""``.
+    ##
+    ## If the socket is disconnected in the middle of a line (before ``\r\L``
+    ## is read) then line will be set to ``""``.
+    ## The partial line **will be lost**.
+    ##
+    ## **Warning**: This assumes that lines are delimited by ``\r\L``.
+    ##
+    ## **Note**: This procedure is mostly used for testing. You likely want to
+    ## use ``asyncnet.recvLine`` instead.
+
+    template addNLIfEmpty() =
+      if result.len == 0:
+        result.add("\c\L")
+
+    result = ""
+    var c = ""
+    while true:
+      c = await winRecv(socket, 1)
+      if c.len == 0:
+        return ""
+      if c == "\r":
+        c = await winRecv(socket, 1)
+        assert c == "\l"
+        addNLIfEmpty()
+        return
+      elif c == "\L":
+        addNLIfEmpty()
+        return
+      add(result, c)
+
+  proc sendMessages(client: AsyncFD) {.async.} =
+    for i in 0 ..< messagesToSend:
+      await winSend(client, "Message " & $i & "\c\L")
+
+  proc launchSwarm(port: Port) {.async.} =
+    for i in 0 ..< swarmSize:
+      var sock = createNativeSocket()
+      setBlocking(sock, false)
+
+      await winConnect(AsyncFD(sock), "localhost", port)
+      await sendMessages(AsyncFD(sock))
+      discard closeSocket(sock)
+
+  proc readMessages(client: AsyncFD) {.async.} =
+    while true:
+      var line = await winRecvLine(client)
+      if line == "":
+        closeSocket(client)
+        clientCount.inc
+        break
+      else:
+        if line.startsWith("Message "):
+          msgCount.inc
+        else:
+          doAssert false
+
+  proc createServer(server: SocketHandle) {.async.} =
+    discard server.listen()
+    while true:
+      asyncCheck readMessages(await winAccept(AsyncFD(server)))
+
+  var server = createNativeSocket()
+  setBlocking(server, false)
+  let port = bindAvailablePort(server)
+  asyncCheck createServer(server)
+  asyncCheck launchSwarm(port)
+  while true:
+    poll()
+    if clientCount == swarmSize: break
+
+  assert msgCount == swarmSize * messagesToSend
+  doAssert msgCount == 5000
diff --git a/tests/avr/nim.cfg b/tests/avr/nim.cfg
new file mode 100644
index 000000000..d6eba8eda
--- /dev/null
+++ b/tests/avr/nim.cfg
@@ -0,0 +1,12 @@
+avr.standalone.gcc.path = "/usr/bin"
+avr.standalone.gcc.exe = "avr-gcc"
+avr.standalone.gcc.linkerexe = "avr-gcc"
+passC = "-Os"
+passC = "-DF_CPU=16000000UL"
+passC = "-mmcu=atmega328p"
+passL = "-mmcu=atmega328p"
+passC = "-flto"
+passL = "-flto"
+cpu = "avr"
+deadCodeElim = "on"
+gc = "arc"
diff --git a/tests/avr/panicoverride.nim b/tests/avr/panicoverride.nim
new file mode 100644
index 000000000..770933ddd
--- /dev/null
+++ b/tests/avr/panicoverride.nim
@@ -0,0 +1,13 @@
+proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
+proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
+
+{.push stack_trace: off, profiler:off.}
+
+proc rawoutput(s: string) =
+  printf("%s\n", s)
+
+proc panic(s: string) =
+  rawoutput(s)
+  exit(1)
+
+{.pop.}
diff --git a/tests/avr/thello.nim b/tests/avr/thello.nim
new file mode 100644
index 000000000..7ebaeae5f
--- /dev/null
+++ b/tests/avr/thello.nim
@@ -0,0 +1,6 @@
+discard """
+  cmd: "nim c --compileOnly --os:standalone --exceptions:quirky -d:noSignalHandler -d:danger --threads:off $file"
+  action: "compile"
+"""
+
+echo "hi"
diff --git a/tests/benchmarks/readme.md b/tests/benchmarks/readme.md
new file mode 100644
index 000000000..1e744fc40
--- /dev/null
+++ b/tests/benchmarks/readme.md
@@ -0,0 +1,5 @@
+# Collection of benchmarks
+
+In future work, benchmarks can be added to CI, but for now we provide benchmarks that can be run locally.
+
+See RFC: https://github.com/timotheecour/Nim/issues/425
diff --git a/tests/benchmarks/ttls.nim b/tests/benchmarks/ttls.nim
new file mode 100644
index 000000000..f5314850f
--- /dev/null
+++ b/tests/benchmarks/ttls.nim
@@ -0,0 +1,30 @@
+discard """
+  action: compile
+"""
+
+#[
+## on osx
+nim r -d:danger --threads --tlsEmulation:off tests/benchmarks/ttls.nim
+9.999999999992654e-07
+
+ditto with `--tlsEmulation:on`:
+0.216999
+]#
+
+import times
+
+proc main2(): int =
+  var g0 {.threadvar.}: int
+  g0.inc
+  result = g0
+
+proc main =
+  let n = 100_000_000
+  var c = 0
+  let t = cpuTime()
+  for i in 0..<n:
+    c += main2()
+  let t2 = cpuTime() - t
+  doAssert c != 0
+  echo t2
+main()
diff --git a/tests/c/tcompile.c b/tests/c/tcompile.c
new file mode 100644
index 000000000..fc0482e40
--- /dev/null
+++ b/tests/c/tcompile.c
@@ -0,0 +1,3 @@
+int foo(int a, int b) {
+  return a+b;
+}
diff --git a/tests/c/tcompile.nim b/tests/c/tcompile.nim
new file mode 100644
index 000000000..cf99fd7ed
--- /dev/null
+++ b/tests/c/tcompile.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''44'''
+  joinable: "false"
+"""
+
+{.compile: "tcompile.c".}
+
+proc foo(a, b: cint): cint {.importc: "foo", cdecl.}
+
+echo foo(40, 4)
diff --git a/tests/c/temit.nim b/tests/c/temit.nim
new file mode 100644
index 000000000..1943c94ea
--- /dev/null
+++ b/tests/c/temit.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "509"
+"""
+# Test the new ``emit`` pragma:
+
+{.emit: """
+#include <stdio.h>
+static int cvariable = 420;
+
+""".}
+
+proc embedsC() =
+  var nimVar = 89
+  {.emit: """printf("%d\n", cvariable + (int)`nimVar`);""".}
+
+embedsC()
diff --git a/tests/c/treservedcidentsasfields.nim b/tests/c/treservedcidentsasfields.nim
new file mode 100644
index 000000000..6cdf9e855
--- /dev/null
+++ b/tests/c/treservedcidentsasfields.nim
@@ -0,0 +1,39 @@
+discard """
+  targets: "c cpp"
+"""
+
+import macros
+
+macro make_test_type(idents: varargs[untyped]): untyped =
+  result = nnkStmtList.newTree()
+
+  var ident_defs: seq[NimNode] = @[]
+  for i in idents:
+    ident_defs.add newIdentDefs(i, ident("int"))
+
+  result.add newTree(nnkTypeSection,
+    newTree(nnkTypeDef,
+      ident("TestType"),
+      newEmptyNode(),
+      newTree(nnkObjectTy,
+        newEmptyNode(),
+        newEmptyNode(),
+        newTree(nnkRecList,
+          ident_defs
+        )
+      )
+    )
+  )
+
+make_test_type(
+  auto, bool, catch, char, class, compl, const_cast, default, delete, double,
+  dynamic_cast, explicit, extern, false, float, friend, goto, int, long,
+  mutable, namespace, new, operator, private, protected, public, register,
+  reinterpret_cast, restrict, short, signed, sizeof, static_cast, struct, switch,
+  this, throw, true, typedef, typeid, typeof, typename, union, packed, unsigned,
+  virtual, void, volatile, wchar_t, alignas, alignof, constexpr, decltype, nullptr,
+  noexcept, thread_local, static_assert, char16_t, char32_t
+)
+
+# Make sure the type makes it to codegen.
+var test_instance: TestType
diff --git a/tests/cairotest.nim b/tests/cairotest.nim
deleted file mode 100755
index 2c28e1abf..000000000
--- a/tests/cairotest.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-import cairo
-
-var surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 240, 80)
-var cr = cairo_create(surface)
-
-cairo_select_font_face(cr, "serif", CAIRO_FONT_SLANT_NORMAL, 
-                                    CAIRO_FONT_WEIGHT_BOLD)
-cairo_set_font_size(cr, 32.0)
-cairo_set_source_rgb(cr, 0.0, 0.0, 1.0)
-cairo_move_to(cr, 10.0, 50.0)
-cairo_show_text(cr, "Hello, world")
-cairo_destroy(cr)
-discard cairo_surface_write_to_png(surface, "hello.png")
-cairo_surface_destroy(surface)
diff --git a/tests/casestmt/t18964.nim b/tests/casestmt/t18964.nim
new file mode 100644
index 000000000..1d2de2bbc
--- /dev/null
+++ b/tests/casestmt/t18964.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "invalid order of case branches"
+"""
+
+import macros
+
+macro genCase(val: string): untyped =
+  result = nnkCaseStmt.newTree(val,
+    nnkElse.newTree(quote do: echo "else"),
+    nnkOfBranch.newTree(newLit("miauz"), quote do: echo "first branch"))
+
+genCase("miauz")
diff --git a/tests/casestmt/t7699.nim b/tests/casestmt/t7699.nim
new file mode 100644
index 000000000..1354551c1
--- /dev/null
+++ b/tests/casestmt/t7699.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "case statement cannot work on enums with holes for computed goto"
+  line: 13
+"""
+
+type
+  X = enum
+    A = 0, B = 100
+
+var z = A
+while true:
+  {.computedGoto.}
+  case z
+  of A: discard
+  of B: discard
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/tcaseexpr1.nim b/tests/casestmt/tcaseexpr1.nim
new file mode 100644
index 000000000..4f5bbf100
--- /dev/null
+++ b/tests/casestmt/tcaseexpr1.nim
@@ -0,0 +1,39 @@
+discard """
+  cmd: "nim check $options $file"
+  action: "reject"
+  nimout: '''
+tcaseexpr1.nim(33, 10) Error: not all cases are covered; missing: {C}
+tcaseexpr1.nim(39, 12) Error: type mismatch: got <string> but expected 'int literal(10)'
+'''
+"""
+
+
+
+
+
+
+
+
+
+
+
+# line 20
+type
+  E = enum A, B, C
+
+proc foo(x: int): auto =
+  return case x
+    of 1..9: "digit"
+    else: "number"
+
+var r = foo(10)
+
+var x = C
+
+var t1 = case x:
+  of A: "a"
+  of B: "b"
+
+var t2 = case x:
+  of A: 10
+  of B, C: "23"
diff --git a/tests/casestmt/tcaseoverlaprange.nim b/tests/casestmt/tcaseoverlaprange.nim
new file mode 100644
index 000000000..e9651c69f
--- /dev/null
+++ b/tests/casestmt/tcaseoverlaprange.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "duplicate case label"
+  line: 13
+"""
+
+type
+  TE = enum A, B, C, D
+
+var
+  e: TE
+
+case e
+of A..D, B..C:
+  echo "redundant"
+else: nil
diff --git a/tests/casestmt/tcaseoverlaprange2.nim b/tests/casestmt/tcaseoverlaprange2.nim
new file mode 100644
index 000000000..4a1cb3ea6
--- /dev/null
+++ b/tests/casestmt/tcaseoverlaprange2.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "duplicate case label"
+  line: 13
+"""
+
+
+
+
+proc checkDuplicates(myval: int32): bool =
+  case myval
+  of 0x7B:
+    echo "this should not compile"
+  of 0x78 .. 0x7D:
+    result = true
+  else:
+    nil
+
+echo checkDuplicates(0x7B)
diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim
new file mode 100644
index 000000000..66de4183d
--- /dev/null
+++ b/tests/casestmt/tcasestmt.nim
@@ -0,0 +1,319 @@
+discard """
+output:
+'''
+Not found!
+Found!
+1
+compiles for 1
+i am always two
+default for 3
+set is 4 not 5
+array is 6 not 7
+default for 8
+an identifier
+OK
+OK
+OK
+ayyydd
+'''
+"""
+
+
+block arrayconstr:
+  const md_extension = [".md", ".markdown"]
+
+  proc test(ext: string) =
+    case ext
+    of ".txt", md_extension:
+      echo "Found!"
+    else:
+      echo "Not found!"
+
+  test(".something")
+  # ensure it's not evaluated at compile-time:
+  var foo = ".markdown"
+  test(foo)
+
+
+converter toInt(x: char): int =
+  x.int
+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:
+  proc whenCase(a: int) =
+    case a
+    of (when compiles(whenCase(1)): 1 else: {}): echo "compiles for 1"
+    of {}: echo "me not fail"
+    of 2: echo "i am always two"
+    of []: echo "me neither"
+    of {4,5}: echo "set is 4 not 5"
+    of [6,7]: echo "array is 6 not 7"
+    of (when compiles(neverCompilesIBet()): 3 else: {}): echo "compiles for 3"
+    #of {},[]: echo "me neither"
+    else: echo "default for ", a
+
+  whenCase(1)
+  whenCase(2)
+  whenCase(3)
+  whenCase(4)
+  whenCase(6)
+  whenCase(8)
+
+
+block setconstr:
+  const
+    SymChars: set[char] = {'a'..'z', 'A'..'Z', '\x80'..'\xFF'}
+
+  proc classify(s: string) =
+    case s[0]
+    of SymChars, '_': echo "an identifier"
+    of {'0'..'9'}: echo "a number"
+    else: echo "other"
+
+  classify("Hurra")
+
+
+
+block tduplicates:
+  type Kind = enum A, B
+  var k = A
+
+  template reject(b) =
+    static: doAssert(not compiles(b))
+
+  reject:
+      var i = 2
+      case i
+      of [1, 1]: discard
+      else: discard
+
+  reject:
+      var i = 2
+      case i
+      of 1, { 1..2 }: discard
+      else: discard
+
+  reject:
+      var i = 2
+      case i
+      of { 1, 1 }: discard
+      of { 1, 1 }: discard
+      else: discard
+
+  reject:
+      case k
+      of [A, A]: discard
+
+  var i = 2
+  case i
+  of { 1, 1 }: discard
+  of { 2, 2 }: echo "OK"
+  else: discard
+
+  case i
+  of { 10..30, 15..25, 5..15, 25..35 }: discard
+  else: echo "OK"
+
+  case k
+  of {A, A..A}: echo "OK"
+  of B: discard
+
+
+block tcasestm:
+  type
+    Tenum = enum eA, eB, eC
+
+  var
+    x: string = "yyy"
+    y: Tenum = eA
+    i: int
+
+  case y
+  of eA: write(stdout, "a")
+  of eB, eC: write(stdout, "b or c")
+
+  case x
+  of "Andreas", "Rumpf": write(stdout, "Hallo Meister!")
+  of "aa", "bb": write(stdout, "Du bist nicht mein Meister")
+  of "cc", "hash", "when": discard
+  of "will", "it", "finally", "be", "generated": discard
+
+  var z = case i
+    of 1..5, 8, 9: "aa"
+    of 6, 7: "bb"
+    elif x == "Ha":
+      "cc"
+    elif x == "yyy":
+      write(stdout, x)
+      "dd"
+    else:
+      "zz"
+
+  echo z
+  #OUT ayyy
+
+  let str1 = "Y"
+  let str2 = "NN"
+  let a = case str1:
+    of "Y": true
+    of "N": false
+    else:
+      echo "no good"
+      quit("quitting")
+
+  proc toBool(s: string): bool =
+    case s:
+    of "": raise newException(ValueError, "Invalid boolean")
+    elif s[0] == 'Y': true
+    elif s[0] == 'N': false
+    else: "error".quit(2)
+
+
+  let b = "NN".toBool()
+
+  doAssert(a == true)
+  doAssert(b == false)
+
+  static:
+    #bug #7407
+    let bstatic = "N".toBool()
+    doAssert(bstatic == false)
+
+  var bb: bool
+  doAssert(not compiles(
+    bb = case str2:
+      of "": raise newException(ValueError, "Invalid boolean")
+      elif str.startsWith("Y"): true
+      elif str.startsWith("N"): false
+  ))
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y": true
+      of "N": false
+  ))
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y": true
+      of "N": raise newException(ValueError, "N not allowed")
+  ))
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y": raise newException(ValueError, "Invalid Y")
+      else: raise newException(ValueError, "Invalid N")
+  ))
+
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y":
+        raise newException(ValueError, "Invalid Y")
+        true
+      else: raise newException(ValueError, "Invalid")
+  ))
+
+
+  doAssert(not compiles(
+    bb = case str2:
+      of "Y":
+        "invalid Y".quit(3)
+        true
+      else: raise newException(ValueError, "Invalid")
+  ))
+
+#issue #11552
+
+proc positiveOrNegative(num: int): string =
+  result = case num
+  of (low(int)+2) .. -1:
+    "negative"
+  of 0:
+    "zero"
+  else:
+    "impossible"
+
+#issue #11551
+
+proc negativeOrNot(num: int): string =
+    result = case num
+    of low(int) .. -1:
+      "negative"
+    else:
+      "zero or positive"
+
+doAssert negativeOrNot(-1) == "negative"
+doAssert negativeOrNot(10000000) == "zero or positive"
+doAssert negativeOrNot(0) == "zero or positive"
+
+########################################################
+# issue #13490
+import strutils
+func foo(input: string): int =
+  try:
+    parseInt(input)
+  except:
+    return
+
+func foo2(b, input: string): int =
+  case b:
+    of "Y":
+      for c in input:
+        result =  if c in '0'..'9': parseInt($c)
+                  else: break
+    of "N":
+      for c in input:
+        result =  if c in '0'..'9': parseInt($c)
+                  else: continue
+    else: return
+
+
+static:
+  doAssert(foo("3") == 3)
+  doAssert(foo("a") == 0)
+  doAssert(foo2("Y", "a2") == 0)
+  doAssert(foo2("Y", "2a") == 2)
+  doAssert(foo2("N", "a3") == 3)
+  doAssert(foo2("z", "2") == 0)
+
+doAssert(foo("3") == 3)
+doAssert(foo("a") == 0)
+doAssert(foo2("Y", "a2") == 0)
+doAssert(foo2("Y", "2a") == 2)
+doAssert(foo2("N", "a3") == 3)
+doAssert(foo2("z", "2") == 0)
+
+
+# bug #20031
+proc main(a: uint64) =
+  case a
+  else:
+    discard
+
+static:
+  main(10)
+main(10)
+
+block:
+  # Just needs to compile
+  proc bar(): int {.discardable.} = discard
+
+  proc foo() {.noreturn.} = discard
+
+  case "*"
+  of "*":
+    bar()
+  else:
+    # Make sure this noreturn doesn't
+    # cause the discardable to not discard
+    foo()
diff --git a/tests/casestmt/tcomputedgoto.nim b/tests/casestmt/tcomputedgoto.nim
new file mode 100644
index 000000000..f7603dac3
--- /dev/null
+++ b/tests/casestmt/tcomputedgoto.nim
@@ -0,0 +1,59 @@
+discard """
+  output: '''
+yeah A enumB
+uneven
+yeah A enumB
+yeah CD enumD
+uneven
+yeah CD enumE
+yeah A enumB
+uneven
+yeah CD enumE
+yeah CD enumD
+uneven
+yeah A enumB
+yeah B enumC
+uneven
+yeah A enumB
+yeah A enumB
+uneven
+yeah A enumB
+'''
+"""
+
+type
+  MyEnum = enum
+    enumA, enumB, enumC, enumD, enumE, enumLast
+
+proc vm() =
+  var instructions: array[0..100, MyEnum]
+  instructions[2] = enumC
+  instructions[3] = enumD
+  instructions[4] = enumA
+  instructions[5] = enumD
+  instructions[6] = enumC
+  instructions[7] = enumA
+  instructions[8] = enumB
+
+  instructions[12] = enumE
+  var pc = 0
+  while true:
+    {.computedGoto.}
+    let instr = instructions[pc]
+    let ra = instr.succ # instr.regA
+    case instr
+    of enumA:
+      echo "yeah A ", ra
+    of enumC, enumD:
+      echo "yeah CD ", ra
+    of enumB:
+      echo "yeah B ", ra
+    of enumE:
+      break
+    of enumLast: discard
+    inc(pc)
+
+    if pc mod 2 == 1:
+      echo "uneven"
+
+vm()
diff --git a/tests/casestmt/tcstring.nim b/tests/casestmt/tcstring.nim
new file mode 100644
index 000000000..288373402
--- /dev/null
+++ b/tests/casestmt/tcstring.nim
@@ -0,0 +1,52 @@
+discard """
+  targets: "c cpp js"
+"""
+
+type Result = enum none, a, b, c, d, e, f
+
+proc foo1(x: cstring): Result =
+  const y = cstring"hash"
+  const arr = [cstring"it", cstring"finally"]
+  result = none
+  case x
+  of "Andreas", "Rumpf": result = a
+  of cstring"aa", "bb": result = b
+  of "cc", y, "when": result = c
+  of "will", arr, "be", "generated": result = d
+  of nil: result = f
+
+var results = [
+  foo1("Rumpf"), foo1("Andreas"),
+  foo1("aa"), foo1(cstring"bb"),
+  foo1("cc"), foo1("hash"),
+  foo1("finally"), foo1("generated"),
+  foo1("no"), foo1("another no"),
+  foo1(nil)]
+doAssert results == [a, a, b, b, c, c, d, d, none, none, f], $results
+
+proc foo2(x: cstring): Result =
+  const y = cstring"hash"
+  const arr = [cstring"it", cstring"finally"]
+  doAssert not (compiles do:
+    result = case x
+    of "Andreas", "Rumpf": a
+    of cstring"aa", "bb": b
+    of "cc", y, "when": c
+    of "will", arr, "be", "generated": d)
+  case x
+  of "Andreas", "Rumpf": a
+  of cstring"aa", "bb": b
+  of "cc", y, "when": c
+  of "will", arr, "be", "generated": d
+  of nil: f
+  else: e
+
+results = [
+  foo2("Rumpf"), foo2("Andreas"),
+  foo2("aa"), foo2(cstring"bb"),
+  foo2("cc"), foo2("hash"),
+  foo2("finally"), foo2("generated"),
+  foo2("no"), foo2("another no"),
+  foo2(nil)]
+
+doAssert results == [a, a, b, b, c, c, d, d, e, e, f], $results
diff --git a/tests/casestmt/tincompletecaseobject.nim b/tests/casestmt/tincompletecaseobject.nim
new file mode 100644
index 000000000..aa5deda7a
--- /dev/null
+++ b/tests/casestmt/tincompletecaseobject.nim
@@ -0,0 +1,115 @@
+discard """
+errormsg: '''
+not all cases are covered; missing: {nnkComesFrom, nnkDotCall, nnkHiddenCallConv, nnkVarTuple, nnkCurlyExpr, nnkRange, nnkCheckedFieldExpr, nnkDerefExpr, nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkBind, nnkClosedSymChoice, nnkHiddenSubConv, nnkConv, nnkStaticExpr, nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv, nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange, nnkStringToCString, nnkCStringToString, nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit, nnkImportAs, nnkConverterDef, nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkAsmStmt, nnkTypeDef, nnkFinally, nnkContinueStmt, nnkImportStmt, nnkImportExceptStmt, nnkExportStmt, nnkExportExceptStmt, nnkFromStmt, nnkIncludeStmt, nnkUsingStmt, nnkBlockExpr, nnkStmtListType, nnkBlockType, nnkWith, nnkWithout, nnkTypeOfExpr, nnkObjectTy, nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy, nnkRecList, nnkRecCase, nnkRecWhen, nnkVarTy, nnkConstTy, nnkMutableTy, nnkDistinctTy, nnkProcTy, nnkIteratorTy, nnkSharedTy, nnkEnumTy, nnkEnumFieldDef, nnkArgList, nnkPattern, nnkReturnToken, nnkClosure, nnkGotoState, nnkState, nnkBreakState, nnkFuncDef, nnkTupleConstr}
+'''
+"""
+
+# this isn't imported from macros.nim to make it robust against possible changes in the ast.
+
+type
+  NimNodeKind* = enum
+    nnkNone, nnkEmpty, nnkIdent, nnkSym,
+    nnkType, nnkCharLit, nnkIntLit, nnkInt8Lit,
+    nnkInt16Lit, nnkInt32Lit, nnkInt64Lit, nnkUIntLit, nnkUInt8Lit,
+    nnkUInt16Lit, nnkUInt32Lit, nnkUInt64Lit, nnkFloatLit,
+    nnkFloat32Lit, nnkFloat64Lit, nnkFloat128Lit, nnkStrLit, nnkRStrLit,
+    nnkTripleStrLit, nnkNilLit, nnkComesFrom, nnkDotCall,
+    nnkCommand, nnkCall, nnkCallStrLit, nnkInfix,
+    nnkPrefix, nnkPostfix, nnkHiddenCallConv,
+    nnkExprEqExpr,
+    nnkExprColonExpr, nnkIdentDefs, nnkVarTuple,
+    nnkPar, nnkObjConstr, nnkCurly, nnkCurlyExpr,
+    nnkBracket, nnkBracketExpr, nnkPragmaExpr, nnkRange,
+    nnkDotExpr, nnkCheckedFieldExpr, nnkDerefExpr, nnkIfExpr,
+    nnkElifExpr, nnkElseExpr, nnkLambda, nnkDo, nnkAccQuoted,
+    nnkTableConstr, nnkBind,
+    nnkClosedSymChoice,
+    nnkOpenSymChoice,
+    nnkHiddenStdConv,
+    nnkHiddenSubConv, nnkConv, nnkCast, nnkStaticExpr,
+    nnkAddr, nnkHiddenAddr, nnkHiddenDeref, nnkObjDownConv,
+    nnkObjUpConv, nnkChckRangeF, nnkChckRange64, nnkChckRange,
+    nnkStringToCString, nnkCStringToString, nnkAsgn,
+    nnkFastAsgn, nnkGenericParams, nnkFormalParams, nnkOfInherit,
+    nnkImportAs, nnkProcDef, nnkMethodDef, nnkConverterDef,
+    nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch,
+    nnkElifBranch, nnkExceptBranch, nnkElse,
+    nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt,
+    nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt,
+    nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection,
+    nnkConstDef, nnkTypeDef,
+    nnkYieldStmt, nnkDefer, nnkTryStmt, nnkFinally, nnkRaiseStmt,
+    nnkReturnStmt, nnkBreakStmt, nnkContinueStmt, nnkBlockStmt, nnkStaticStmt,
+    nnkDiscardStmt, nnkStmtList,
+    nnkImportStmt = 1337, # make a hole just for fun
+    nnkImportExceptStmt,
+    nnkExportStmt,
+    nnkExportExceptStmt,
+    nnkFromStmt,
+    nnkIncludeStmt,
+    nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
+    nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
+    nnkStmtListType, nnkBlockType,
+    nnkWith, nnkWithout,
+    nnkTypeOfExpr, nnkObjectTy,
+    nnkTupleTy, nnkTupleClassTy, nnkTypeClassTy, nnkStaticTy,
+    nnkRecList, nnkRecCase, nnkRecWhen,
+    nnkRefTy, nnkPtrTy, nnkVarTy,
+    nnkConstTy, nnkMutableTy,
+    nnkDistinctTy,
+    nnkProcTy,
+    nnkIteratorTy,         # iterator type
+    nnkSharedTy,           # 'shared T'
+    nnkEnumTy,
+    nnkEnumFieldDef,
+    nnkArgList, nnkPattern
+    nnkReturnToken,
+    nnkClosure,
+    nnkGotoState,
+    nnkState,
+    nnkBreakState,
+    nnkFuncDef,
+    nnkTupleConstr
+
+const
+  nnkLiterals* = {nnkCharLit..nnkNilLit}
+
+  nnkSomething* = {nnkStmtList, nnkStmtListExpr, nnkDiscardStmt, nnkVarSection, nnkLetSection,
+       nnkConstSection, nnkPar, nnkAccQuoted, nnkAsgn, nnkDefer, nnkCurly, nnkBracket,
+       nnkStaticStmt, nnkTableConstr, nnkExprColonExpr, nnkInfix, nnkPrefix,
+       nnkRaiseStmt, nnkYieldStmt, nnkBracketExpr, nnkDotExpr, nnkCast, nnkBlockStmt,
+       nnkExprEqExpr}
+
+type
+  MyFictionalType = object
+    a: int
+    case n: NimNodeKind
+    of nnkLiterals, nnkCommentStmt, nnkNone, nnkEmpty, nnkIdent, nnkSym,
+       nnkType, nnkBindStmt, nnkMixinStmt, nnkTypeSection, nnkPragmaBlock,
+       nnkPragmaExpr, nnkPragma, nnkBreakStmt, nnkCallStrLit, nnkPostfix,
+       nnkOpenSymChoice:
+      b: int
+    of nnkCall, nnkCommand:
+      c: int
+    of nnkReturnStmt:
+      d: int
+    of nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkProcDef, nnkMethodDef:
+      e: int
+    of nnkSomething, nnkRefTy, nnkPtrTy, nnkHiddenStdConv:
+      f: int
+    of nnkObjConstr:
+      g: int
+    of nnkIfStmt, nnkIfExpr, nnkWhenStmt:
+      # if when and case statements are branching statements. So a
+      # single function call is allowed to be in all of the braches and
+      # the entire expression can still be considered as a forwarding
+      # template.
+      h: int
+    of nnkCaseStmt:
+      i: int
+    of nnkTryStmt:
+      j: int
+    of nnkIdentDefs:
+      k: int
+    of nnkConstDef:
+      l: int
diff --git a/tests/casestmt/tincompletecaseobject2.nim b/tests/casestmt/tincompletecaseobject2.nim
new file mode 100644
index 000000000..bbeae1909
--- /dev/null
+++ b/tests/casestmt/tincompletecaseobject2.nim
@@ -0,0 +1,26 @@
+discard """
+cmd: "nim check $file"
+"""
+type
+  ABCD = enum A, B, C, D
+  AliasABCD = ABCD
+  RangeABC = range[A .. C]
+  AliasRangeABC = RangeABC
+  PrintableChars = range[' ' .. '~']
+
+case PrintableChars 'x': #[tt.Error
+^ not all cases are covered; missing: {' ', '!', '\"', '#', '$$', '%', '&', '\'', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~'}]#
+of '0'..'9', 'A'..'Z', 'a'..'z': discard
+of '(', ')': discard
+
+case AliasABCD A: #[tt.Error
+^ not all cases are covered; missing: {B, C, D}]#
+of A: discard
+
+case RangeABC A: #[tt.Error
+^ not all cases are covered; missing: {A, C}]#
+of B: discard
+
+case AliasRangeABC A: #[tt.Error
+^ not all cases are covered; missing: {A, B}]#
+of C: discard
diff --git a/tests/casestmt/tlinearscanend.nim b/tests/casestmt/tlinearscanend.nim
new file mode 100644
index 000000000..96e3727d5
--- /dev/null
+++ b/tests/casestmt/tlinearscanend.nim
@@ -0,0 +1,26 @@
+discard """
+action: compile
+"""
+
+import strutils
+
+var x = 343
+
+case stdin.readline.parseInt
+of 0:
+  echo "most common case"
+of 1:
+  {.linearScanEnd.}
+  echo "second most common case"
+of 2: echo "unlikely: use branch table"
+else:
+  echo "unlikely too: use branch table"
+
+
+case x
+of 23: echo "23"
+of 343: echo "343"
+of 21: echo "21"
+else:
+  {.linearScanEnd.}
+  echo "default"
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/cast/tcast.nim b/tests/cast/tcast.nim
new file mode 100644
index 000000000..205444ea3
--- /dev/null
+++ b/tests/cast/tcast.nim
@@ -0,0 +1,21 @@
+discard """
+  targets: "c cpp js"
+"""
+
+proc main() =
+  block: # bug #16806
+    let
+      a = 42u16
+      b = cast[int16](a)
+    doAssert a.int16 == 42
+    doAssert b in int16.low..int16.high
+
+  block: # bug #16808
+    doAssert cast[int8](cast[uint8](int8(-12))) == int8(-12)
+    doAssert cast[int16](cast[uint16](int16(-12))) == int16(-12)
+    doAssert cast[int32](cast[uint32](int32(-12))) == int32(-12)
+
+  doAssert cast[int8](int16.high) == -1
+
+static: main()
+main()
diff --git a/tests/ccgbugs/m1/defs.nim b/tests/ccgbugs/m1/defs.nim
new file mode 100644
index 000000000..ed78d8b72
--- /dev/null
+++ b/tests/ccgbugs/m1/defs.nim
@@ -0,0 +1,4 @@
+type MyObj* = object
+  field1*: int
+  s*: string
+  ch*: char
diff --git a/tests/ccgbugs/m19445.c b/tests/ccgbugs/m19445.c
new file mode 100644
index 000000000..74c23d4b4
--- /dev/null
+++ b/tests/ccgbugs/m19445.c
@@ -0,0 +1,3 @@
+#include "m19445.h"
+
+const Foo f = {10, 20, 30, 40};
\ No newline at end of file
diff --git a/tests/ccgbugs/m2/defs.nim b/tests/ccgbugs/m2/defs.nim
new file mode 100644
index 000000000..798d1fea8
--- /dev/null
+++ b/tests/ccgbugs/m2/defs.nim
@@ -0,0 +1,4 @@
+type MyObj* = object
+  s*: string
+  field1*: int
+  ch*: char
diff --git a/tests/ccgbugs/mstatic_assert.nim b/tests/ccgbugs/mstatic_assert.nim
new file mode 100644
index 000000000..dbf9c03d1
--- /dev/null
+++ b/tests/ccgbugs/mstatic_assert.nim
@@ -0,0 +1,6 @@
+{.emit:"""
+NIM_STATIC_ASSERT(sizeof(bool) == 1, "");
+#warning "foo2"
+NIM_STATIC_ASSERT(sizeof(bool) == 2, "");
+#warning "foo3"
+""".}
diff --git a/tests/ccgbugs/mymodule.nim b/tests/ccgbugs/mymodule.nim
new file mode 100644
index 000000000..8c78cdf9b
--- /dev/null
+++ b/tests/ccgbugs/mymodule.nim
@@ -0,0 +1,14 @@
+type
+  MyRefObject* = ref object
+    s: string
+  
+  BaseObj* = ref object of RootObj
+  ChildObj* = ref object of BaseObj
+
+proc newMyRefObject*(s: string): MyRefObject =
+  new(result)
+  result.s = s
+  
+proc `$`*(o: MyRefObject): string =
+  o.s
+  
\ No newline at end of file
diff --git a/tests/ccgbugs/pkg8616/rtarray.nim b/tests/ccgbugs/pkg8616/rtarray.nim
new file mode 100644
index 000000000..286dbb8cd
--- /dev/null
+++ b/tests/ccgbugs/pkg8616/rtarray.nim
@@ -0,0 +1,2 @@
+proc head*[T](pp: var array[1,T]): var T =
+  result = pp[0]
diff --git a/tests/ccgbugs/pkg8616/scheduler.nim b/tests/ccgbugs/pkg8616/scheduler.nim
new file mode 100644
index 000000000..0730000c4
--- /dev/null
+++ b/tests/ccgbugs/pkg8616/scheduler.nim
@@ -0,0 +1,10 @@
+import rtarray
+
+type
+  T = tuple[x:int]
+
+var
+  arr: array[1,T]
+
+proc init*() =
+  discard head(arr)
diff --git a/tests/ccgbugs/t10128.nim b/tests/ccgbugs/t10128.nim
new file mode 100644
index 000000000..48970916f
--- /dev/null
+++ b/tests/ccgbugs/t10128.nim
@@ -0,0 +1,18 @@
+# bug #10128
+let data = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
+var seq2 = newSeq[char](data.len)
+for i in 0..<data.len:
+  seq2[i] = data[i]
+
+let c = '\128'
+
+# case 1
+doAssert data[c.int] == 'y'
+doAssert seq2[c.int] == 'y'
+
+proc play(x: openArray[char]) =
+  doAssert x[c.int] == 'y'
+
+# case2
+play(data)
+play(seq2)
\ No newline at end of file
diff --git a/tests/ccgbugs/t10964.nim b/tests/ccgbugs/t10964.nim
new file mode 100644
index 000000000..c19db6997
--- /dev/null
+++ b/tests/ccgbugs/t10964.nim
@@ -0,0 +1,7 @@
+func test*(input: var openArray[int32], start: int = 0, fin: int = input.len - 1) =

+    discard

+

+var someSeq = @[1'i32]

+

+test(someSeq)

+# bug with gcc 14
\ No newline at end of file
diff --git a/tests/ccgbugs/t13062.nim b/tests/ccgbugs/t13062.nim
new file mode 100644
index 000000000..cfda1da7c
--- /dev/null
+++ b/tests/ccgbugs/t13062.nim
@@ -0,0 +1,33 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp"
+"""
+
+import atomics
+
+type
+  Pledge* {.exportc.} = object
+    p: PledgePtr
+
+  PledgeKind {.exportc.} = enum
+    Single
+    Iteration
+
+  PledgePtr {.exportc.} = ptr object
+    case kind: PledgeKind
+    of Single:
+      impl: PledgeImpl
+    of Iteration:
+      discard
+
+  PledgeImpl {.exportc.} = object
+    fulfilled: Atomic[bool]
+
+var x: Pledge
+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]"
+else: # fixme # bug #20081
+  doAssert x.repr == "Pledge(p: nil)"
diff --git a/tests/ccgbugs/t13902.nim b/tests/ccgbugs/t13902.nim
new file mode 100644
index 000000000..fd4f76d15
--- /dev/null
+++ b/tests/ccgbugs/t13902.nim
@@ -0,0 +1,12 @@
+
+#issue #13902
+block:
+  type Slot = distinct uint64
+  var s = Slot(1)
+  proc `$`(x: Slot): string {.borrow.}
+  proc `+=`(x: var Slot, y: uint64) {.borrow.}
+  # test was failing with either 0 or 2 echos but not with 1 echo
+  # echo "s = ", s
+  s += 1
+  # echo "s = ", s
+  doAssert s.uint64 == 2, $s # was failing, showing 18419607611339964418
diff --git a/tests/ccgbugs/t15428.nim b/tests/ccgbugs/t15428.nim
new file mode 100644
index 000000000..d9ae8ff16
--- /dev/null
+++ b/tests/ccgbugs/t15428.nim
@@ -0,0 +1,22 @@
+discard """

+    cmd: "nim $target --mm:refc $file"

+    output: '''5

+5

+[1, 2, 3, 4, 5]

+(data: [1, 2, 3, 4, 5])

+'''

+"""

+

+proc take[T](f: openArray[T]) =

+  echo f.len

+let f = @[0,1,2,3,4]

+take(f.toOpenArray(0,4))

+

+{.experimental: "views".}

+type

+  Foo = object

+    data: openArray[int]

+let f2 = Foo(data: [1,2,3,4,5])

+echo f2.data.len

+echo f2.data

+echo f2
\ No newline at end of file
diff --git a/tests/ccgbugs/t16027.nim b/tests/ccgbugs/t16027.nim
new file mode 100644
index 000000000..58f15eb6e
--- /dev/null
+++ b/tests/ccgbugs/t16027.nim
@@ -0,0 +1,13 @@
+discard """
+  ccodecheck: "__restrict__"
+  action: compile
+  joinable: false
+"""
+
+# see bug #16027
+iterator myitems(s: seq[int]): int =
+  var data {.codegenDecl: "$# __restrict__ $#".} : ptr int = nil
+  yield 1
+
+for i in @[1].myitems:
+  discard
diff --git a/tests/ccgbugs/t16374.nim b/tests/ccgbugs/t16374.nim
new file mode 100644
index 000000000..8ccfa4815
--- /dev/null
+++ b/tests/ccgbugs/t16374.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--gc:refc; --gc:orc"
+"""
+
+block:
+  iterator mvalues(t: var seq[seq[int]]): var seq[int] =
+    yield t[0]
+
+  var t: seq[seq[int]]
+
+  while false:
+    for v in t.mvalues:
+      discard
+
+  proc ok =
+    while false:
+      for v in t.mvalues:
+        discard
+
+  ok()
+
+block:
+  iterator mvalues(t: var seq[seq[int]]): lent seq[int] =
+    yield t[0]
+
+  var t: seq[seq[int]]
+
+  while false:
+    for v in t.mvalues:
+      discard
+
+  proc ok =
+    while false:
+      for v in t.mvalues:
+        discard
+
+  ok()
+
diff --git a/tests/ccgbugs/t19445.nim b/tests/ccgbugs/t19445.nim
new file mode 100644
index 000000000..b6e8d028c
--- /dev/null
+++ b/tests/ccgbugs/t19445.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "--nimcache:tests/ccgbugs/nimcache19445 --cincludes:nimcache19445 --header:m19445"
+  targets: "c"
+"""
+
+# bug #19445
+type
+  Foo* {.exportc.} = object
+    a*, b*, c*, d*: int
+
+proc dummy(): Foo {.exportc.} = discard
+
+{.compile:"m19445.c".}
\ No newline at end of file
diff --git a/tests/ccgbugs/t20139.nim b/tests/ccgbugs/t20139.nim
new file mode 100644
index 000000000..4592b994d
--- /dev/null
+++ b/tests/ccgbugs/t20139.nim
@@ -0,0 +1,10 @@
+discard """
+  joinable: false
+"""
+
+# bug #20139
+import m1/defs as md1
+import m2/defs as md2
+
+doAssert $(md1.MyObj(field1: 1)) == """(field1: 1, s: "", ch: '\x00')"""
+doAssert $(md2.MyObj(field1: 1)) == """(s: "", field1: 1, ch: '\x00')"""
diff --git a/tests/ccgbugs/t20141.nim b/tests/ccgbugs/t20141.nim
new file mode 100644
index 000000000..60e130690
--- /dev/null
+++ b/tests/ccgbugs/t20141.nim
@@ -0,0 +1,27 @@
+discard """
+  joinable: false
+"""
+
+# bug #20141
+type
+  A = object
+  B = object
+  U = proc()
+
+proc m(h: var B) = discard
+
+template n[T, U](x: U): T =
+  static: doAssert true
+  cast[ptr T](addr x)[]
+
+proc k() =
+  var res: A
+  m(n[B, A](res))
+
+proc w(mounter: U) = discard
+
+proc mount(proto: U) = discard
+proc v() = mount k
+
+# This is required for failure
+w(v)
diff --git a/tests/ccgbugs/t20787.nim b/tests/ccgbugs/t20787.nim
new file mode 100644
index 000000000..c2d848c2c
--- /dev/null
+++ b/tests/ccgbugs/t20787.nim
@@ -0,0 +1,4 @@
+type
+  Obj = object
+    f: UncheckedArray[byte]
+let o = new Obj
\ No newline at end of file
diff --git a/tests/ccgbugs/t21116.nim b/tests/ccgbugs/t21116.nim
new file mode 100644
index 000000000..cc77de198
--- /dev/null
+++ b/tests/ccgbugs/t21116.nim
@@ -0,0 +1,10 @@
+discard """
+  targets: "c cpp"
+  disabled: windows
+"""
+# bug #21116
+import std/os
+
+proc p(glob: string) =
+  for _ in walkFiles(glob): discard
+p("dir/*")
diff --git a/tests/ccgbugs/t21972.nim b/tests/ccgbugs/t21972.nim
new file mode 100644
index 000000000..58d0cfc62
--- /dev/null
+++ b/tests/ccgbugs/t21972.nim
@@ -0,0 +1,33 @@
+discard """

+    targets: "c cpp"

+    outputsub: "Error: unhandled exception: Err2 [IOError]"

+    exitcode: "1"

+"""

+

+proc bar(x: var int) =

+  inc x

+  if x == 3:

+    raise newException(ValueError, "H0")

+

+  elif x == 5:

+    raise newException(IOError, "H1")

+

+  elif x > 7:

+    raise newException(IOError, "H2")

+

+

+proc foo() =

+  var i = 0

+  while true:

+    try:

+      bar(i)

+      echo i

+

+    except ValueError:

+      debugEcho("ValueError")

+

+    except IOError:

+      raise newException(IOError, "Err2")

+

+when isMainModule:

+  foo()
\ No newline at end of file
diff --git a/tests/ccgbugs/t21995.nim b/tests/ccgbugs/t21995.nim
new file mode 100644
index 000000000..0ec88aa59
--- /dev/null
+++ b/tests/ccgbugs/t21995.nim
@@ -0,0 +1,9 @@
+discard """
+    targets: "c cpp"
+    output: "Hi!"
+"""
+
+try:
+  raise
+except:
+  echo "Hi!"
\ No newline at end of file
diff --git a/tests/ccgbugs/t22462.nim b/tests/ccgbugs/t22462.nim
new file mode 100644
index 000000000..9adfbb19b
--- /dev/null
+++ b/tests/ccgbugs/t22462.nim
@@ -0,0 +1,20 @@
+discard """
+  action: "run"
+  output: '''
+1
+1
+1
+'''
+  matrix: "--mm:refc"
+  targets: "c cpp"
+"""
+
+type Object = object
+  someComplexType: seq[int]
+  index: Natural
+
+func newObject(): Object = result.index.inc
+
+for i in 1..3:
+  let o = newObject()
+  echo o.index
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/t2procs.nim b/tests/ccgbugs/t2procs.nim
new file mode 100644
index 000000000..d8b7a2815
--- /dev/null
+++ b/tests/ccgbugs/t2procs.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''before
+1
+before
+2'''
+"""
+
+proc fn[T1, T2](a: T1, b: T2) =
+  a(1)
+  b(2)
+
+fn( (proc(x: int) =
+      echo "before" # example block, can span multiple lines
+      echo x),
+    (proc (y: int) =
+      echo "before"
+      echo y)
+)
diff --git a/tests/ccgbugs/t5296.nim b/tests/ccgbugs/t5296.nim
new file mode 100644
index 000000000..8fbed35c4
--- /dev/null
+++ b/tests/ccgbugs/t5296.nim
@@ -0,0 +1,21 @@
+discard """
+cmd: "nim c -d:release $file"
+output: '''1
+-1'''
+"""
+
+proc bug() : void =
+    var x = 0
+    try:
+        inc x
+        raise new(Exception)
+    except Exception:
+        echo x
+
+bug()
+
+# bug #19051
+type GInt[T] = int
+
+var a = 1
+echo -a
diff --git a/tests/ccgbugs/t5345.nim b/tests/ccgbugs/t5345.nim
new file mode 100644
index 000000000..f9ee833c4
--- /dev/null
+++ b/tests/ccgbugs/t5345.nim
@@ -0,0 +1,10 @@
+discard """
+  output: true
+"""
+
+proc cmpx(d: int): bool {.inline.} = d > 0
+
+proc abc[C](cx: C, d: int) =
+  echo cx(d)
+  
+abc(cmpx, 10)
diff --git a/tests/ccgbugs/t6279.nim b/tests/ccgbugs/t6279.nim
new file mode 100644
index 000000000..5a3d6768c
--- /dev/null
+++ b/tests/ccgbugs/t6279.nim
@@ -0,0 +1,9 @@
+discard """
+cmd: "nim c -r -d:fulldebug -d:smokeCycles --gc:refc $file"
+output: '''@["a"]'''
+"""
+
+# bug #6279
+var foo = newSeq[tuple[a: seq[string], b: seq[string]]]()
+foo.add((@["a"], @["b"]))
+echo foo[0].a # Crashes on this line
diff --git a/tests/ccgbugs/t6756.nim b/tests/ccgbugs/t6756.nim
new file mode 100644
index 000000000..5990eba58
--- /dev/null
+++ b/tests/ccgbugs/t6756.nim
@@ -0,0 +1,24 @@
+discard """
+output: '''
+(v: 3)
+'''
+"""
+
+import typetraits
+type
+  A[T] = ref object
+    v: T
+
+template templ(o: A, op: untyped): untyped =
+  type T = typeof(o.v)
+
+  var res: A[T]
+
+  block:
+    var it {.inject.}: T
+    it = o.v
+    res = A[T](v: op)
+  res
+
+let a = A[int](v: 1)
+echo templ(a, it + 2)[]
diff --git a/tests/ccgbugs/t7079.nim b/tests/ccgbugs/t7079.nim
new file mode 100644
index 000000000..bfa1b77a6
--- /dev/null
+++ b/tests/ccgbugs/t7079.nim
@@ -0,0 +1,9 @@
+discard """
+  action: run
+  targets: '''c js'''
+"""
+
+import math
+let x = -0.0
+doAssert classify(x) == fcNegZero
+doAssert classify(1 / -0.0) == fcNegInf
\ No newline at end of file
diff --git a/tests/ccgbugs/t8616.nim b/tests/ccgbugs/t8616.nim
new file mode 100644
index 000000000..5fd940d3b
--- /dev/null
+++ b/tests/ccgbugs/t8616.nim
@@ -0,0 +1,4 @@
+import pkg8616 / scheduler
+
+when true:
+  init()
diff --git a/tests/ccgbugs/t8781.nim b/tests/ccgbugs/t8781.nim
new file mode 100644
index 000000000..884c6962a
--- /dev/null
+++ b/tests/ccgbugs/t8781.nim
@@ -0,0 +1,25 @@
+discard """
+output: ""
+"""
+
+type
+  Drawable = object of RootObj
+    discard
+
+  # issue #8781, following type was broken due to 'U' suffix
+  # on `animatedU`. U also added as union identifier for C.
+  # replaced by "_U" prefix, which is not allowed as an
+  # identifier
+  TypeOne = ref object of Drawable
+    animatedU: bool
+    case animated: bool
+    of true:
+        frames: seq[int]
+    of false:
+        region: float
+
+when true:
+  let r = 1.5
+  let a = TypeOne(animatedU: true,
+                  animated: false,
+                  region: r)
diff --git a/tests/ccgbugs/t8967.nim b/tests/ccgbugs/t8967.nim
new file mode 100644
index 000000000..0301a2e4f
--- /dev/null
+++ b/tests/ccgbugs/t8967.nim
@@ -0,0 +1,14 @@
+discard """
+  targets: "c cpp"
+"""
+
+import marshal
+
+template main() =
+  let orig: set[char] = {'A'..'Z'}
+  let m = $$orig
+  let old = to[set[char]](m)
+  doAssert orig - old == {}
+
+static: main()
+main()
diff --git a/tests/ccgbugs/t9098.nim b/tests/ccgbugs/t9098.nim
new file mode 100644
index 000000000..e1dbb6883
--- /dev/null
+++ b/tests/ccgbugs/t9098.nim
@@ -0,0 +1,12 @@
+discard """
+  targets: "c cpp js"
+  output: '''
+{'a', 'b'}
+'''
+"""
+
+var x = new(ref set[char])
+var y = new(ref set[char])
+x[] = {'a'}
+y[] = {'b'}
+echo x[] + y[]
diff --git a/tests/ccgbugs/t9286.nim b/tests/ccgbugs/t9286.nim
new file mode 100644
index 000000000..2fec23307
--- /dev/null
+++ b/tests/ccgbugs/t9286.nim
@@ -0,0 +1,22 @@
+discard """
+  action: run
+"""
+
+import options
+type Foo  = ref object
+  i:      int
+
+proc next(foo: Foo): Option[Foo] =
+  try:    doAssert(foo.i == 0)
+  except: return      # 2º: none
+  return some(foo)    # 1º: some
+
+proc test =
+  let foo = Foo()
+  var opt = next(foo) # 1º Some
+  while isSome(opt) and foo.i < 10:
+    inc(foo.i)
+    opt = next(foo)   # 2º None
+  doAssert foo.i == 1, $foo.i
+
+test()
diff --git a/tests/ccgbugs/t9578.nim b/tests/ccgbugs/t9578.nim
new file mode 100644
index 000000000..25b7b6695
--- /dev/null
+++ b/tests/ccgbugs/t9578.nim
@@ -0,0 +1,76 @@
+discard """
+output: '''
+@[(v: -1), (v: 2), (v: 3)]
+@[(v: -1), (v: 2), (v: 3)]
+[(v: -1), (v: 2), (v: 3)]
+[(v: -1), (v: 2), (v: 3)]
+((v: -1), (v: 2), (v: 3))
+((v: -1), (v: 2), (v: 3))
+@[(v: -1), (v: 2), (v: 3)]
+@[(v: -1), (v: 2), (v: 3)]
+@[(v: -1), (v: 2), (v: 3)]
+'''
+"""
+
+type mytype* = object
+  v:int
+
+proc f*(x:ptr mytype) = x.v = -1
+
+func g(x:int):mytype = mytype(v:x)
+
+
+import xseq9578
+block:
+  var x = @[1.g,2.g,3.g]
+  testSeq(x)
+  echo x
+block:
+  var x = @[1.g,2.g,3.g]
+  var y = addr x
+  testSeq2(y)
+  echo x
+
+
+import xarray9578
+block:
+  var x = [1.g,2.g,3.g]
+  testArray(x)
+  echo x
+block:
+  var x = [1.g,2.g,3.g]
+  var y = addr x
+  testArray2(y)
+  echo x
+
+
+import xtuple9578
+block:
+  var x = (1.g,2.g,3.g)
+  testTuple(x)
+  echo x
+block:
+  var x = (1.g,2.g,3.g)
+  var y = addr x
+  testTuple2(y)
+  echo x
+
+
+import xoa9578
+block:
+  var x = @[1.g,2.g,3.g]
+  testOpenArray(x)
+  echo x
+
+
+import xua9578
+block:
+  var x = @[1.g,2.g,3.g]
+  var y = cast[ptr UncheckedArray[mytype]](addr x[0])
+  testUncheckedArray(y[])
+  echo x
+block:
+  var x = @[1.g,2.g,3.g]
+  var y = cast[ptr UncheckedArray[mytype]](addr x[0])
+  testUncheckedArray2(y)
+  echo x
diff --git a/tests/ccgbugs/t9655.nim b/tests/ccgbugs/t9655.nim
new file mode 100644
index 000000000..29fb903a4
--- /dev/null
+++ b/tests/ccgbugs/t9655.nim
@@ -0,0 +1,30 @@
+discard """
+  action: "compile"
+"""
+
+import std/[asynchttpserver, asyncdispatch]
+import std/[strformat]
+
+proc main() =
+  let local = "123"
+
+  proc serveIndex(req: Request) {.async, gcsafe.} =
+    await req.respond(Http200, &"{local}")
+
+  proc serve404(req: Request) {.async, gcsafe.} =
+    echo req.url.path
+    await req.respond(Http404, "not found")
+
+  proc serve(req: Request) {.async, gcsafe.} =
+    let handler = case req.url.path:
+      of "/":
+        serveIndex
+      else:
+        serve404
+    await handler(req)
+
+  let server = newAsyncHttpServer()
+  waitFor server.serve(Port(8080), serve, address = "127.0.0.1")
+
+when isMainModule:
+  main()
diff --git a/tests/ccgbugs/taddhigh.nim b/tests/ccgbugs/taddhigh.nim
new file mode 100644
index 000000000..6b0658612
--- /dev/null
+++ b/tests/ccgbugs/taddhigh.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''@[5, 5, 5, 5, 5]'''
+"""
+
+# bug #1832
+
+var s = @[5]
+
+# Works fine:
+let x = s[s.high]
+s.add x
+
+# Causes the 0 to appear:
+s.add s[s.high]
+
+s.add s[s.len-1]
+s.add s[s.len-1]
+
+echo s # @[5, 5, 0]
diff --git a/tests/ccgbugs/targ_lefttoright.nim b/tests/ccgbugs/targ_lefttoright.nim
new file mode 100644
index 000000000..a0adce157
--- /dev/null
+++ b/tests/ccgbugs/targ_lefttoright.nim
@@ -0,0 +1,71 @@
+discard """
+  nimout: '''1,2
+2,3
+2,2
+1,2
+1,2
+2,2
+1,2
+'''
+  output: '''1,2
+2,3
+1,2
+2,2
+1,2
+1,2
+2,2
+1,2
+'''
+  cmd: "nim c --gc:orc $file"
+"""
+
+template test =
+  proc say(a, b: int) =
+    echo a,",",b
+
+  var a = 1
+  say a, (a += 1; a) #1,2
+
+  var b = 1
+  say (b += 1; b), (b += 1; b) #2,3
+
+  type C {.byRef.} = object
+    i: int
+
+  proc say(a, b: C) =
+    echo a.i,",",b.i
+
+  proc `+=`(x: var C, y: C) = x.i += y.i
+
+  var c = C(i: 1)
+  when nimvm: #XXX: This would output 2,2 in the VM, which is wrong
+    discard
+  else:
+    say c, (c += C(i: 1); c) #1,2
+
+  proc sayVar(a: var int, b: int) =
+    echo a,",",b
+
+  var d = 1
+  sayVar d, (d += 1; d) #2,2
+
+  var e = 1
+  say (addr e)[], (e += 1; e) #1,2
+
+  var f = 1
+  say f, if false: f
+         else: f += 1; f #1,2
+
+  var g = 1
+  say g + 1, if false: g
+             else: g += 1; g #2,2
+
+  proc `+=+`(x: var int, y: int): int = (inc(x, y); x)
+
+  var h = 1
+  say h, h +=+ 1 # 1,2
+
+test
+
+static:
+  test
diff --git a/tests/ccgbugs/tarray_equality.nim b/tests/ccgbugs/tarray_equality.nim
new file mode 100644
index 000000000..66a953439
--- /dev/null
+++ b/tests/ccgbugs/tarray_equality.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''true
+true'''
+"""
+
+# bug #2489
+
+let a = [1]
+let b = [1]
+echo a == b
+
+# bug #2498
+var x: array[0, int]
+var y: array[0, int]
+echo x == y
diff --git a/tests/ccgbugs/tassign_nil_strings.nim b/tests/ccgbugs/tassign_nil_strings.nim
new file mode 100644
index 000000000..e32bfcade
--- /dev/null
+++ b/tests/ccgbugs/tassign_nil_strings.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "--mm:refc"
+  output: "Hello"
+  ccodecheck: "\\i@'a = ((NimStringDesc*) NIM_NIL)'"
+"""
+
+proc main() =
+  var a = "Hello"
+  echo a
+  a = ""
+  doAssert a.len == 0
+
+main()
diff --git a/tests/ccgbugs/tborrowmagic.nim b/tests/ccgbugs/tborrowmagic.nim
new file mode 100644
index 000000000..8d42ddcd8
--- /dev/null
+++ b/tests/ccgbugs/tborrowmagic.nim
@@ -0,0 +1,8 @@
+type
+  Bytes = distinct seq[byte]
+
+proc add(x: var Bytes; b: byte) {.borrow.}
+var x = @[].Bytes
+x.add(42)
+let base = cast[seq[byte]](x)
+doAssert base.len == 1 and base[0] == 42
diff --git a/tests/ccgbugs/tbug1081.nim b/tests/ccgbugs/tbug1081.nim
new file mode 100644
index 000000000..baef99d84
--- /dev/null
+++ b/tests/ccgbugs/tbug1081.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''1
+0
+0
+0
+x = ['a', 'b', 'c', '0', '1', '2', '3', '4', '5', '6'] and y = ['a', 'b', 'c', '0', '1', '2', '3', '4', '5', '6']'''
+"""
+
+proc `1/1`() = echo(1 div 1)
+template `1/2`() = echo(1 div 2)
+var `1/3` = 1 div 4
+`1/3` = 1 div 3 # oops, 1/3!=1/4
+let `1/4` = 1 div 4
+
+`1/1`()
+`1/2`()
+echo `1/3`
+echo `1/4`
+
+# bug #6422
+
+proc toCharArray1(N : static[int], s: string): array[N, char] =
+  doAssert s.len <= N
+  let x = cast[ptr array[N, char]](s.cstring)
+  x[]
+
+proc toCharArray2(N : static[int], s: string): array[N, char] =
+  doAssert s.len <= N
+  let x = cast[ptr array[N, char]](s.cstring)
+  result = x[]
+
+let x = toCharArray1(10, "abc0123456")
+let y = toCharArray2(10, "abc0123456")
+echo "x = ", $x, " and y = ", $y
diff --git a/tests/ccgbugs/tbug21505.nim b/tests/ccgbugs/tbug21505.nim
new file mode 100644
index 000000000..0c0811ec5
--- /dev/null
+++ b/tests/ccgbugs/tbug21505.nim
@@ -0,0 +1,39 @@
+discard """
+    action: "compile"
+    targets: "cpp"
+    cmd: "nim cpp $file"
+"""
+
+# see #21505: ensure compilation of imported C++ objects with explicit constructors while retaining default initialization through codegen changes due to #21279
+
+{.emit:"""/*TYPESECTION*/
+
+struct ExplObj
+{
+  explicit ExplObj(int bar = 0) {}  
+};
+
+struct BareObj
+{
+    BareObj() {}
+};
+
+""".}
+
+type
+  ExplObj {.importcpp.} = object
+  BareObj {.importcpp.} = object
+
+type
+  Composer = object
+    explObj: ExplObj
+    bareObj: BareObj
+
+proc foo =
+  var composer1 {.used.}: Composer
+  let composer2 {.used.} = Composer()
+
+var composer1 {.used.}: Composer
+let composer2 {.used.} = Composer()
+
+foo()
\ No newline at end of file
diff --git a/tests/ccgbugs/tcapture_static.nim b/tests/ccgbugs/tcapture_static.nim
new file mode 100644
index 000000000..2afb8de47
--- /dev/null
+++ b/tests/ccgbugs/tcapture_static.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''hi'''
+"""
+
+# bug #4551
+
+proc foo() =
+    let arr = ["hi"]
+    for i, v in arr:
+        let bar = proc =
+            echo v
+        bar()
+foo()
diff --git a/tests/ccgbugs/tccgen1.nim b/tests/ccgbugs/tccgen1.nim
new file mode 100644
index 000000000..be571de08
--- /dev/null
+++ b/tests/ccgbugs/tccgen1.nim
@@ -0,0 +1,67 @@
+
+
+type
+  Feature = tuple[name: string, version: string]
+  PDOMImplementation* = ref DOMImplementation
+  DOMImplementation = object
+    Features: seq[Feature] # Read-Only
+
+  PNode* = ref Node
+  Node {.inheritable.} = object
+    attributes*: seq[PAttr]
+    childNodes*: seq[PNode]
+    FLocalName: string # Read-only
+    FNamespaceURI: string # Read-only
+    FNodeName: string # Read-only
+    nodeValue*: string
+    FNodeType: int # Read-only
+    FOwnerDocument: PDocument # Read-Only
+    FParentNode: PNode # Read-Only
+    prefix*: string # Setting this should change some values... TODO!
+
+  PElement* = ref Element
+  Element = object of Node
+    FTagName: string # Read-only
+
+  PCharacterData = ref CharacterData
+  CharacterData = object of Node
+    data*: string
+
+  PDocument* = ref Document
+  Document = object of Node
+    FImplementation: PDOMImplementation # Read-only
+    FDocumentElement: PElement # Read-only
+
+  PAttr* = ref Attr
+  Attr = object of Node
+    FName: string # Read-only
+    FSpecified: bool # Read-only
+    value*: string
+    FOwnerElement: PElement # Read-only
+
+  PDocumentFragment* = ref DocumentFragment
+  DocumentFragment = object of Node
+
+  PText* = ref Text
+  Text = object of CharacterData
+
+  PComment* = ref Comment
+  Comment = object of CharacterData
+
+  PCDataSection* = ref CDataSection
+  CDataSection = object of Text
+
+  PProcessingInstruction* = ref ProcessingInstruction
+  ProcessingInstruction = object of Node
+    data*: string
+    FTarget: string # Read-only
+
+proc `namespaceURI=`*(n: var PNode, value: string) =
+  n.FNamespaceURI = value
+
+proc main =
+  var n: PNode
+  new(n)
+  n.namespaceURI = "test"
+
+main()
diff --git a/tests/ccgbugs/tccgissues.nim b/tests/ccgbugs/tccgissues.nim
new file mode 100644
index 000000000..8207ccbba
--- /dev/null
+++ b/tests/ccgbugs/tccgissues.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''
+@[1, 2, 3, 4]
+'''
+"""
+
+# issue #10999
+
+proc varargsToSeq(vals: varargs[int32]): seq[int32] =
+  result = newSeqOfCap[int32](vals.len)
+  for v in vals:
+    result.add v
+
+echo varargsToSeq(1, 2, 3, 4)
diff --git a/tests/ccgbugs/tcgbug.nim b/tests/ccgbugs/tcgbug.nim
new file mode 100644
index 000000000..2eddc6fdd
--- /dev/null
+++ b/tests/ccgbugs/tcgbug.nim
@@ -0,0 +1,163 @@
+discard """
+output: '''
+success
+M1 M2
+ok
+'''
+matrix: "--mm:refc;--mm:orc"
+"""
+
+type
+  TObj = object
+    x, y: int
+  PObj = ref TObj
+
+proc p(a: PObj) =
+  a.x = 0
+
+proc q(a: var PObj) =
+  a.p()
+
+var
+  a: PObj
+new(a)
+q(a)
+
+# bug #914
+when defined(windows):
+  import std/widestrs
+  var x = newWideCString("Hello")
+
+echo "success"
+
+
+# bug #833
+
+type
+  PFuture*[T] = ref object
+    value*: T
+    finished*: bool
+    cb: proc (future: PFuture[T]) {.closure.}
+
+var k = PFuture[void]()
+
+
+##bug #9297 and #13281
+
+import strutils
+
+type
+  MyKind = enum
+    M1, M2, M3
+
+  MyObject {.exportc: "ExtObject"} = object
+    case kind: MyKind
+      of M1: a:int
+      of M2: b:float
+      of M3: c:cstring
+
+  MyObjectRef {.exportc: "ExtObject2"} = ref object
+    case kind: MyKind
+      of M1: a:int
+      of M2: b:float
+      of M3: c:cstring
+
+  Helper* {.exportc: "PublicHelper".} = object
+    case isKind: bool
+      of true:
+        formatted: string
+      of false:
+        parsed1: string
+        parsed2: string
+
+proc newMyObject(kind: MyKind, val: string): MyObject =
+  result = MyObject(kind: kind)
+
+  case kind
+    of M1: result.a = parseInt(val)
+    of M2: result.b = parseFloat(val)
+    of M3: result.c = val
+
+proc newMyObjectRef(kind: MyKind, val: string): MyObjectRef =
+  result = MyObjectRef(kind: kind)
+  case kind
+    of M1: result.a = parseInt(val)
+    of M2: result.b = parseFloat(val)
+    of M3: result.c = val
+
+
+echo newMyObject(M1, "2").kind, " ", newMyObjectRef(M2, "3").kind
+
+
+proc test(c: Helper): string =
+  c.formatted
+
+echo test(Helper(isKind: true, formatted: "ok"))
+
+
+# bug #19613
+
+type
+  Eth2Digest = object
+    data: array[42, byte]
+
+  BlockId* = object
+    root*: Eth2Digest
+
+  BlockSlotId* = object
+    bid*: BlockId
+    slot*: uint64
+
+func init*(T: type BlockSlotId, bid: BlockId, slot: uint64): T =
+  #debugecho "init ", bid, " ", slot
+  BlockSlotId(bid: bid, slot: slot)
+
+proc bug19613 =
+  var x: BlockSlotId
+  x.bid.root.data[0] = 42
+
+  x =
+    if x.slot > 0:
+      BlockSlotId.init(x.bid, x.slot)
+    else:
+      BlockSlotId.init(x.bid, x.slot)
+  doAssert x.bid.root.data[0] == 42
+
+bug19613()
+
+proc foo = # bug #23280
+  let foo = @[1,2,3,4,5,6]
+  doAssert toOpenArray(foo, 0, 5).len == 6
+  doAssert toOpenArray(foo, 0, 5).len mod 6 == 0 # this should output 0
+  doAssert toOpenArray(foo, 0, 5).max mod 6 == 0
+  let L = toOpenArray(foo, 0, 5).len
+  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/tclosureeq.nim b/tests/ccgbugs/tclosureeq.nim
new file mode 100644
index 000000000..0486a9559
--- /dev/null
+++ b/tests/ccgbugs/tclosureeq.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''true
+true'''
+"""
+
+# bug #4186
+type
+  Predicate[T] = proc(item: T): bool
+
+proc a[T](): Predicate[T] =
+  return nil
+
+proc b[T](): Predicate[T] =
+  return a[T]()
+
+echo b[int]() == nil  # ok
+
+let x = b[int]()
+echo x == nil     #won't compile
diff --git a/tests/ccgbugs/tcodegenbug1.nim b/tests/ccgbugs/tcodegenbug1.nim
new file mode 100644
index 000000000..d2ab97ede
--- /dev/null
+++ b/tests/ccgbugs/tcodegenbug1.nim
@@ -0,0 +1,185 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''obj = (inner: (kind: Just, id: 7))
+obj.inner.id = 7
+id = 7
+obj = (inner: (kind: Just, id: 7))
+2
+(a: "a", b: "b", c: "")
+caught
+(a: "a", b: "b", c: "")'''
+"""
+
+# bug #6960
+
+import sugar
+type
+  Kind = enum None, Just, Huge
+  Inner = object
+    case kind: Kind
+    of None: discard
+    of Just: id: int
+    of Huge: a,b,c,d,e,f: string
+  Outer = object
+    inner: Inner
+
+
+proc shouldDoNothing(id: int): Inner =
+  dump id
+  Inner(kind: Just, id: id)
+
+var obj = Outer(inner: Inner(kind: Just, id: 7))
+dump obj
+dump obj.inner.id
+obj.inner = shouldDoNothing(obj.inner.id)
+dump obj
+
+import os
+
+type
+  TStatusEnum* = enum
+    sUnknown = -1, sBuildFailure, sBuildInProgress, sBuildSuccess,
+    sTestFailure, sTestInProgress, sTestSuccess, # ORDER MATTERS!
+    sDocGenFailure, sDocGenInProgress, sDocGenSuccess,
+    sCSrcGenFailure, sCSrcGenInProgress, sCSrcGenSuccess
+
+  TStatus* = object
+    status*: TStatusEnum
+    desc*: string
+    hash*: string
+
+proc initStatus*(): TStatus =
+  result.status = sUnknown
+  result.desc = ""
+  result.hash = ""
+
+proc isInProgress*(status: TStatusEnum): bool =
+  return status in {sBuildInProgress, sTestInProgress, sDocGenInProgress,
+                    sCSrcGenInProgress}
+
+proc `$`*(status: TStatusEnum): string =
+  case status
+  of sBuildFailure:
+    return "build failure"
+  of sBuildInProgress:
+    return "build in progress"
+  of sBuildSuccess:
+    return "build finished"
+  of sTestFailure:
+    return "testing failure"
+  of sTestInProgress:
+    return "testing in progress"
+  of sTestSuccess:
+    return "testing finished"
+  of sDocGenFailure:
+    return "documentation generation failed"
+  of sDocGenInProgress:
+    return "generating documentation"
+  of sDocGenSuccess:
+    return "documentation generation succeeded"
+  of sCSrcGenFailure:
+    return "csource generation failed"
+  of sCSrcGenInProgress:
+    return "csource generation in progress"
+  of sCSrcGenSuccess:
+    return "csource generation succeeded"
+  of sUnknown:
+    return "unknown"
+
+proc makeCommitPath*(platform, hash: string): string =
+  return platform / "nim_" & hash.substr(0, 11) # 11 Chars.
+
+type
+  TFlag = enum
+    A, B, C, D
+
+  TFlags = set[TFlag]
+
+  TObj = object
+    x: int
+    flags: TFlags
+
+# have a proc taking TFlags as param and returning object having TFlags field
+proc foo(flags: TFlags): TObj = nil
+
+
+# bug #5137
+type
+  MyInt {.importc: "int".} = object
+  MyIntDistinct = distinct MyInt
+
+proc bug5137(d: MyIntDistinct) =
+  discard d.MyInt
+
+#-------------------------------------
+# bug #8979
+
+type
+  MyKind = enum
+    Fixed, Float
+
+  MyObject = object
+    someInt: int
+    case kind: MyKind
+      of Float: index: string
+      of Fixed: nil
+
+  MyResult = object
+    val: array[0..1, string]
+    vis: set[0..1]
+
+import macros
+
+func myfunc(obj: MyObject): MyResult {.raises: [].} =
+  template index: auto =
+    case obj.kind:
+      of Float: $obj.index
+      of Fixed: "Fixed"
+  macro to_str(a: untyped): string =
+    result = newStrLitNode(a.repr)
+  result.val[0] = index
+  result.val[1] = to_str(obj.kind + Ola)
+
+let x = MyObject(someInt: 10, kind: Fixed)
+echo myfunc(x).val.len
+
+# bug #14126
+
+type X = object
+  a, b, c: string
+
+proc f(): X =
+  result.a = "a"
+  result.b = "b"
+  raise (ref ValueError)()
+
+proc ohmanNoNRVO =
+  var x: X
+  x.a = "1"
+  x.b = "2"
+  x.c = "3"
+
+  try:
+    x = f()
+  except:
+    discard
+
+  echo x
+  # once NVRO is sorted out, x.c == "3"
+  doAssert x.c == "", "shouldn't modify x if f raises"
+
+ohmanNoNRVO()
+
+proc ohmanNoNRVO2(x: var X) =
+  x.a = "1"
+  x.c = "3"
+  x = f()
+
+var xgg: X
+try:
+  ohmanNoNRVO2(xgg)
+except:
+  echo "caught"
+echo xgg
+# once NVRO is sorted out, xgg.c == "3"
+doAssert xgg.c == "", "this assert will fail"
diff --git a/tests/ccgbugs/tcodegenbug_bool.nim b/tests/ccgbugs/tcodegenbug_bool.nim
new file mode 100644
index 000000000..a0dbf4eb2
--- /dev/null
+++ b/tests/ccgbugs/tcodegenbug_bool.nim
@@ -0,0 +1,11 @@
+discard """
+"""
+
+# issue #13798
+{.emit:"""
+#include <stdbool.h>
+void fun(bool a){}
+""".}
+
+proc fun(a: bool) {.importc.}
+fun(true)
diff --git a/tests/ccgbugs/tcodegendecllambda.nim b/tests/ccgbugs/tcodegendecllambda.nim
new file mode 100644
index 000000000..814dcf206
--- /dev/null
+++ b/tests/ccgbugs/tcodegendecllambda.nim
@@ -0,0 +1,14 @@
+discard """
+  targets: "c cpp js"
+  ccodecheck: "'HELLO'"
+  action: compile
+"""
+
+when defined(js):
+  var foo = proc(): void{.codegenDecl: "/*HELLO*/function $2($3)".} =
+    echo "baa"
+else:
+  var foo = proc(): void{.codegenDecl: "/*HELLO*/$1 $2 $3".} =
+    echo "baa"
+
+foo()
diff --git a/tests/ccgbugs/tcompile_time_var_at_runtime.nim b/tests/ccgbugs/tcompile_time_var_at_runtime.nim
new file mode 100644
index 000000000..c0de0390b
--- /dev/null
+++ b/tests/ccgbugs/tcompile_time_var_at_runtime.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "1\n2\n2\n3"
+"""
+var a {.compileTime.} = 1
+
+echo a
+a = 2
+echo a
+echo a
+a = 3
+echo a 
\ No newline at end of file
diff --git a/tests/ccgbugs/tctypes.nim b/tests/ccgbugs/tctypes.nim
new file mode 100644
index 000000000..be6009115
--- /dev/null
+++ b/tests/ccgbugs/tctypes.nim
@@ -0,0 +1,43 @@
+discard """
+  targets: "c cpp"
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #7308
+proc foo(x: seq[int32]) =
+  var y = newSeq[cint](1)
+
+proc bar =
+  var t = newSeq[int32](1)
+  foo(t)
+
+bar()
+
+
+# bug #16246
+
+proc testWeirdTypeAliases() =
+  var values = newSeq[cuint](8)
+  # var values: seq[cuint] does not produce codegen error
+  var drawCb = proc(): seq[uint32] =
+    result = newSeq[uint32](10)
+
+testWeirdTypeAliases()
+
+block: # bug #11797
+  block:
+    type cdouble2 = cdouble
+    type Foo1 = seq[cdouble]
+    type Foo2 = seq[cdouble2]
+    static: doAssert Foo1 is Foo2
+    var a1: Foo1
+    var a2: Foo2
+    doAssert a1 == @[]
+    doAssert a2 == @[]
+
+  block:
+    proc foo[T: int|cint](fun: proc(): T) = discard
+    proc foo1(): cint = 1
+    proc foo3(): int32 = 2
+    foo(proc(): cint = foo1())
+    foo(proc(): int32 = foo3())
diff --git a/tests/ccgbugs/tcvarargs.nim b/tests/ccgbugs/tcvarargs.nim
new file mode 100644
index 000000000..261885f4f
--- /dev/null
+++ b/tests/ccgbugs/tcvarargs.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''17
+17
+17
+17
+17
+17
+'''
+"""
+
+# bug #1593
+
+{.emit: """
+#include <stdarg.h>
+#include <stdio.h>
+
+void foo(int n, ...) {
+  NI64 k;
+  int i;
+  va_list argp;
+  va_start(argp, n);
+  for (i = 1; i <= n; i++) {
+    k = va_arg(argp, NI64);
+    printf("%lld\n", (long long)k);
+  }
+  va_end(argp);
+}
+""".}
+
+proc foo(x: cint) {.importc, varargs, nodecl.}
+
+proc main() =
+  const k = 17'i64
+  foo(6, k, k, k, k, k, k)
+main()
diff --git a/tests/ccgbugs/tdeepcopy_addr_rval.nim b/tests/ccgbugs/tdeepcopy_addr_rval.nim
new file mode 100644
index 000000000..4a0b0deaa
--- /dev/null
+++ b/tests/ccgbugs/tdeepcopy_addr_rval.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: "--mm:refc; --mm:orc --deepcopy:on"
+  output: "3"
+"""
+
+# issue 5166
+
+type
+  Test = ref object
+    x: int
+
+let x = Test(x: 3)
+let p = cast[pointer](x)
+
+var v: Test
+deepCopy(v, cast[Test](p))
+echo v.x
diff --git a/tests/ccgbugs/tderefblock.nim b/tests/ccgbugs/tderefblock.nim
new file mode 100644
index 000000000..d3ba07667
--- /dev/null
+++ b/tests/ccgbugs/tderefblock.nim
@@ -0,0 +1,76 @@
+discard """
+  matrix: "--mm:refc -d:release -d:danger;--mm:orc -d:useMalloc -d:release -d:danger"
+  output: "42"
+"""
+
+# bug #20107
+
+type Foo = object
+  a, b, c, d: uint64
+
+proc c(i: uint64): Foo =
+  Foo(a: i, b: i, c: i, d: i)
+
+func x(f: Foo): lent Foo {.inline.} =
+  f
+
+proc m() =
+  let f = block:
+    let i = c(42)
+    x(i)
+
+  echo $f.a
+
+m()
+
+block: # bug #21540
+  type
+    Option = object
+      val: string
+      has: bool
+
+  proc some(val: string): Option =
+    result.has = true
+    result.val = val
+
+  # Remove lent and it works
+  proc get(self: Option): lent string =
+    result = self.val
+
+  type
+    StringStream = ref object
+      data: string
+      pos: int
+
+  proc readAll(s: StringStream): string =
+    result = newString(s.data.len)
+    copyMem(addr(result[0]), addr(s.data[0]), s.data.len)
+
+  proc newStringStream(s: string = ""): StringStream =
+    new(result)
+    result.data = s
+
+  proc parseJson(s: string): string =
+    let stream = newStringStream(s)
+    result = stream.readAll()
+
+  proc main =
+    let initialFEN = block:
+      let initialFEN = some parseJson("startpos")
+      initialFEN.get
+
+    doAssert initialFEN == "startpos"
+
+  main()
+
+import std/[
+    json,
+    options
+]
+
+block: # bug #21540
+  let cheek = block:
+    let initialFEN = some("""{"initialFen": "startpos"}""".parseJson{"initialFen"}.getStr)
+    initialFEN.get
+
+  doAssert cheek == "startpos"
diff --git a/tests/ccgbugs/tescaping_temps.nim b/tests/ccgbugs/tescaping_temps.nim
new file mode 100644
index 000000000..ea09261ea
--- /dev/null
+++ b/tests/ccgbugs/tescaping_temps.nim
@@ -0,0 +1,31 @@
+
+# bug #4505
+
+proc f(t: tuple[]) = discard
+f((block: ()))
+
+# bug #4230
+# If we make `test` function return nothing - the bug disappears
+proc test(dothejob: proc()): int {.discardable.} =
+    dothejob()
+
+test proc() =
+    let f = 15
+    if f > 10:
+        test proc() = discard
+    # If we remove elif branch of the condition - the bug disappears
+    elif f < 3:
+        test proc() = discard
+    else:
+        test proc() = discard
+
+# ensure 'case' does not trigger the same bug:
+test proc() =
+    let f = 15
+    case f
+    of 10:
+        test proc() = discard
+    of 3:
+        test proc() = discard
+    else:
+        test proc() = discard
diff --git a/tests/ccgbugs/tforward_decl_only.nim b/tests/ccgbugs/tforward_decl_only.nim
new file mode 100644
index 000000000..b115dcbe7
--- /dev/null
+++ b/tests/ccgbugs/tforward_decl_only.nim
@@ -0,0 +1,34 @@
+discard """
+ccodecheck: "\\i !@('struct tyObject_MyRefObject'[0-z]+' _')"
+output: "hello"
+"""
+
+# issue #7339 
+# Test that MyRefObject is only forward declared as it used only by reference
+
+import mymodule
+type AnotherType = object
+  f: MyRefObject 
+
+let x = AnotherType(f: newMyRefObject("hello"))
+echo $x.f
+
+
+# bug #7363
+
+type 
+  Foo = object
+    a: cint
+  Foo2 = object
+    b: cint
+
+proc f(foo: ptr Foo, foo2: ptr Foo2): cint =
+  if foo  != nil:  {.emit: "`result` = `foo`->a;".}
+  if foo2 != nil: {.emit: [result, " = ", foo2[], ".b;"].}
+
+discard f(nil, nil)
+
+
+# bug #7392
+var x1: BaseObj
+var x2 = ChildObj(x1)
diff --git a/tests/ccgbugs/tgeneric_closure.nim b/tests/ccgbugs/tgeneric_closure.nim
new file mode 100644
index 000000000..9f3c5b446
--- /dev/null
+++ b/tests/ccgbugs/tgeneric_closure.nim
@@ -0,0 +1,34 @@
+discard """
+output: '''
+2
+2
+2
+'''
+"""
+
+# bug 2659
+
+type
+  GenProcType[T,U] = proc(x:T, y:var U)
+  IntProcType = proc(x:int, y:var int)
+
+proc mult(x:int, y:var int) =
+  y = 2 * x
+
+when true:
+
+  var input = 1
+  var output = 0
+
+  var someIntProc:IntProcType = mult
+  var someGenProc:GenProcType[int,int] = mult
+
+  mult(input, output)
+  echo output
+
+  someIntProc(input, output)
+  echo output
+
+  # Uncommenting causes an error in the C compiler.
+  someGenProc(input, output)
+  echo output
diff --git a/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim b/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim
new file mode 100644
index 000000000..3788b9985
--- /dev/null
+++ b/tests/ccgbugs/tgeneric_smallobj_asgn_opt.nim
@@ -0,0 +1,27 @@
+discard """
+  output: "done generic smallobj asgn opt"
+"""
+
+# bug #5402
+
+import lists
+
+type
+  Container[T] = ref object
+    obj: T
+
+  ListOfContainers[T] = ref object
+    list: DoublyLinkedList[Container[T]]
+
+proc contains[T](this: ListOfContainers[T], obj: T): bool =
+  for item in this.list.items():
+    if item.obj == obj: return true
+  return false
+
+proc newListOfContainers[T](): ListOfContainers[T] =
+  new(result)
+  result.list = initDoublyLinkedList[Container[T]]()
+
+let q = newListOfContainers[int64]()
+if not q.contains(123):
+  echo "done generic smallobj asgn opt"
diff --git a/tests/ccgbugs/thtiobj.nim b/tests/ccgbugs/thtiobj.nim
new file mode 100644
index 000000000..6db24dad0
--- /dev/null
+++ b/tests/ccgbugs/thtiobj.nim
@@ -0,0 +1,9 @@
+discard """
+  matrix: "--mm:refc"
+  targets: "c cpp"
+"""
+
+import typeinfo
+
+var x = ""
+discard (getPointer(toAny(x)))
diff --git a/tests/ccgbugs/tissues.nim b/tests/ccgbugs/tissues.nim
new file mode 100644
index 000000000..a0c402cc0
--- /dev/null
+++ b/tests/ccgbugs/tissues.nim
@@ -0,0 +1,38 @@
+discard """
+action: compile
+"""
+
+# bug #2233
+type MalType = object
+  fun: proc: MalType
+
+proc f(x: proc: MalType) =
+  discard x()
+
+f(nil)
+
+# bug #2823
+
+type A = object #of RootObj <-- Uncomment this to get no errors
+  test: proc(i: A): bool
+var a: proc(i: A): bool # Or comment this line to get no errors
+
+
+# bug #2703
+type
+  fooObj[T] = object of RootObj
+  bazObj[T] = object of fooObj[T]
+    x: T
+
+var troz: fooObj[string]
+echo bazObj[string](troz).x
+
+
+# bug #14880
+type step = object
+  exec: proc ()
+
+const pipeline = @[step()]
+
+let crash = pipeline[0]
+
diff --git a/tests/ccgbugs/tlvalueconv.nim b/tests/ccgbugs/tlvalueconv.nim
new file mode 100644
index 000000000..b2cb11eef
--- /dev/null
+++ b/tests/ccgbugs/tlvalueconv.nim
@@ -0,0 +1,32 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #14160
+
+type
+  TPassContext = object of RootObj
+  PPassContext = ref TPassContext
+
+  PCtx = ref object of TPassContext
+    a: int
+
+  ModuleGraph = object
+    vm: RootRef
+
+proc main() =
+  var g = ModuleGraph(vm: new(Pctx))
+  PCtx(g.vm) = nil #This generates invalid C code
+  doAssert g.vm == nil
+
+main()
+
+# bug #14325
+
+proc main2() =
+  var g = ModuleGraph(vm: new(Pctx))
+  PPassContext(PCtx(g.vm)) = nil #This compiles, but crashes at runtime with gc:arc
+  doAssert g.vm == nil
+
+main2()
+
diff --git a/tests/ccgbugs/tmangle.nim b/tests/ccgbugs/tmangle.nim
new file mode 100644
index 000000000..0050cef92
--- /dev/null
+++ b/tests/ccgbugs/tmangle.nim
@@ -0,0 +1,16 @@
+block:
+  proc hello() =
+    let NAN_INFINITY = 12
+    doAssert NAN_INFINITY == 12
+    let INF = "2.0"
+    doAssert INF == "2.0"
+    let NAN = 2.3
+    doAssert NAN == 2.3
+
+  hello()
+
+block:
+  proc hello(NAN: float) =
+    doAssert NAN == 2.0
+
+  hello(2.0)
diff --git a/tests/ccgbugs/tmangle_field.nim b/tests/ccgbugs/tmangle_field.nim
new file mode 100644
index 000000000..da2720aaa
--- /dev/null
+++ b/tests/ccgbugs/tmangle_field.nim
@@ -0,0 +1,16 @@
+discard """
+"""
+
+# bug #5404
+
+import parseopt
+
+{.emit: """typedef struct {
+    int key;
+} foo;""".}
+
+type foo* {.importc: "foo", nodecl.} = object
+  key* {.importc: "key".}: cint
+
+for kind, key, value in parseopt.getopt():
+  discard
diff --git a/tests/ccgbugs/tmarkerproc_regression.nim b/tests/ccgbugs/tmarkerproc_regression.nim
new file mode 100644
index 000000000..3b606b834
--- /dev/null
+++ b/tests/ccgbugs/tmarkerproc_regression.nim
@@ -0,0 +1,47 @@
+discard """
+  output: "done markerproc regression"
+"""
+
+type
+  Version* = distinct string
+  Special* = distinct string
+
+  VersionRangeEnum* = enum
+    verLater, # > V
+    verEarlier, # < V
+    verEqLater, # >= V -- Equal or later
+    verEqEarlier, # <= V -- Equal or earlier
+    verIntersect, # > V & < V
+    verEq, # V
+    verAny, # *
+    verSpecial # #head
+
+  VersionRange* = ref VersionRangeObj
+  VersionRangeObj = object
+    case kind*: VersionRangeEnum
+    of verLater, verEarlier, verEqLater, verEqEarlier, verEq:
+      ver*: Version
+    of verSpecial:
+      spe*: Special
+    of verIntersect:
+      verILeft, verIRight: VersionRange
+    of verAny:
+      nil
+
+proc foo(x: string): VersionRange =
+  new(result)
+  result.kind = verEq
+  result.ver = Version(x)
+
+proc main =
+  var a: array[500, VersionRange]
+  for i in 0 ..< 500:
+    a[i] = foo($i & "some longer text here " & $i)
+  GC_fullcollect()
+  for i in 0 ..< 500:
+    let expected = $i & "some longer text here " & $i
+    if a[i].ver.string != expected:
+      quit "bug!"
+  echo "done markerproc regression"
+
+main()
diff --git a/tests/ccgbugs/tmissing_ccgtrav_unique_type.nim b/tests/ccgbugs/tmissing_ccgtrav_unique_type.nim
new file mode 100644
index 000000000..cb87eabd8
--- /dev/null
+++ b/tests/ccgbugs/tmissing_ccgtrav_unique_type.nim
@@ -0,0 +1,12 @@
+
+# bug #3794
+
+
+import options
+
+proc getRef*(): Option[int] =
+  return none(int)
+
+proc getChild*() =
+  let iter = iterator (): int {.closure.} =
+    let reference = getRef()
diff --git a/tests/ccgbugs/tmissingbracket.nim b/tests/ccgbugs/tmissingbracket.nim
new file mode 100644
index 000000000..2919efe0e
--- /dev/null
+++ b/tests/ccgbugs/tmissingbracket.nim
@@ -0,0 +1,53 @@
+discard """
+output: '''
+Subobject test called
+5
+'''
+"""
+
+type
+  TClassOfTCustomObject {.pure, inheritable.} = object
+    base* : ptr TClassOfTCustomObject
+    className* : string
+  TClassOfTobj = object of TClassOfTCustomObject
+    nil
+  TCustomObject {.inheritable.} = ref object
+    class* : ptr TClassOfTCustomObject
+  TObj = ref object of TCustomObject
+    data: int
+
+var ClassOfTObj: TClassOfTObj
+
+proc initClassOfTObj() =
+  ClassOfTObj.base = nil
+  ClassOfTObj.className = "TObj"
+
+initClassOfTObj()
+
+proc initialize*(self: TObj) =
+  self.class = addr ClassOfTObj
+  # this generates wrong C code: && instead of &
+
+proc newInstance(T: typedesc): T =
+  mixin initialize
+  new(result)
+  initialize(result)
+
+var o = TObj.newInstance()
+
+type
+    TestObj* = object of RootObj
+        t:int
+    SubObject* = object of TestObj
+
+method test*(t:var TestObj) {.base.} =
+    echo "test called"
+
+method test*(t:var SubObject) =
+    echo "Subobject test called"
+    t.t= 5
+
+var a: SubObject
+
+a.test()
+echo a.t
diff --git a/tests/ccgbugs/tmissingderef.nim b/tests/ccgbugs/tmissingderef.nim
new file mode 100644
index 000000000..eb7da3023
--- /dev/null
+++ b/tests/ccgbugs/tmissingderef.nim
@@ -0,0 +1,40 @@
+discard """
+  output: '''[10, 0, 0, 0, 0, 0, 0, 0]
+255
+1 1
+0.5'''
+"""
+
+# bug #1181
+
+type
+  TFoo = object
+    x: int32
+
+proc mainowar =
+  var foo: TFoo
+  foo.x = 0xff
+  var arr1 = cast[ptr array[4, uint8]](addr foo)[] # Fails.
+  echo arr1[when cpuEndian == littleEndian: 0 else: 3]
+
+  var i = 1i32
+  let x = addr i
+  var arr2 = cast[ptr array[4, uint8]](x)[] # Fails.
+  echo arr2[when cpuEndian == littleEndian: 0 else: 3], " ", i
+
+  # bug #1715
+  var a: array[2, float32] = [0.5'f32, 0.7]
+  let p = addr a
+  var b = p[]
+  echo b[0]
+
+
+# bug 2963
+var
+  a = [8, 7, 3, 10, 0, 0, 0, 1]
+  b = [10, 0, 0, 0, 0, 0, 0, 0]
+  ap = addr a
+ap[] = b
+echo repr(a)
+
+mainowar()
diff --git a/tests/ccgbugs/tmissingderef2.nim b/tests/ccgbugs/tmissingderef2.nim
new file mode 100644
index 000000000..23be61bcb
--- /dev/null
+++ b/tests/ccgbugs/tmissingderef2.nim
@@ -0,0 +1,25 @@
+discard """
+  output: "c"
+"""
+
+# bug #5079
+
+import tables
+
+type Test = ref object
+  s: string
+
+proc `test=`(t: Test, s: string) =
+  t.s = s
+
+var t = Test()
+
+#t.test = spaces(2) # -- works
+
+var a = newTable[string, string]()
+a["b"] = "c"
+
+#t.s = a["b"] # -- works
+#t.test a["b"] # -- works
+t.test = a["b"] # -- prints "out of memory" and quits
+echo t.s
diff --git a/tests/ccgbugs/tmissinginit.nim b/tests/ccgbugs/tmissinginit.nim
new file mode 100644
index 000000000..9eb58221c
--- /dev/null
+++ b/tests/ccgbugs/tmissinginit.nim
@@ -0,0 +1,31 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''0
+0
+0
+0
+[[a = "",
+b = []]]'''
+"""
+
+# bug #1475
+type
+  Crash = object
+    a: string
+    b: seq[string]
+
+proc initCrash(): Crash = discard
+
+proc test() =
+  var blongname = [initCrash()]
+  echo repr(blongname)
+
+# bug #1434
+proc bug: array[1, int] = discard
+
+echo bug()[0]
+echo bug()[0]
+echo bug()[0]
+echo bug()[0]
+
+test()
diff --git a/tests/ccgbugs/tmissingvolatile.nim b/tests/ccgbugs/tmissingvolatile.nim
new file mode 100644
index 000000000..b877eff71
--- /dev/null
+++ b/tests/ccgbugs/tmissingvolatile.nim
@@ -0,0 +1,21 @@
+discard """
+  output: "1"
+  cmd: r"nim c --hints:on $options --mm:refc -d:release $file"
+  ccodecheck: "'NI volatile state;'"
+  targets: "c"
+"""
+
+# bug #1539
+
+proc err() =
+  raise newException(Exception, "test")
+
+proc main() =
+  var state: int
+  try:
+    state = 1
+    err()
+  except:
+    echo state
+
+main()
diff --git a/tests/ccgbugs/tnil_type.nim b/tests/ccgbugs/tnil_type.nim
new file mode 100644
index 000000000..9921b24a3
--- /dev/null
+++ b/tests/ccgbugs/tnil_type.nim
@@ -0,0 +1,15 @@
+discard """
+  targets: "c cpp"
+"""
+
+proc f1(v: typeof(nil)) = discard
+f1(nil)
+
+proc f2[T]() = discard
+f2[typeof(nil)]()
+
+proc f3(_: typedesc) = discard
+f3(typeof(nil))
+
+proc f4[T](_: T) = discard
+f4(nil)
diff --git a/tests/ccgbugs/tnoalias.nim b/tests/ccgbugs/tnoalias.nim
new file mode 100644
index 000000000..2c3c2f0f4
--- /dev/null
+++ b/tests/ccgbugs/tnoalias.nim
@@ -0,0 +1,13 @@
+discard """
+  ccodecheck: "\\i@'NI* NIM_NOALIAS field;' @'NIM_CHAR* NIM_NOALIAS x_p0,' @'void* NIM_NOALIAS q'"
+"""
+
+type
+  BigNum = object
+    field {.noalias.}: ptr UncheckedArray[int]
+
+proc p(x {.noalias.}: openArray[char]) =
+  var q {.noalias.}: pointer = addr(x[0])
+
+var bn: BigNum
+p "abc"
diff --git a/tests/ccgbugs/tnocodegen_for_compiletime.nim b/tests/ccgbugs/tnocodegen_for_compiletime.nim
new file mode 100644
index 000000000..3a952e303
--- /dev/null
+++ b/tests/ccgbugs/tnocodegen_for_compiletime.nim
@@ -0,0 +1,9 @@
+# bug #1679
+import macros, tables, hashes
+proc hash(v: NimNode): Hash = 4  # performance is for suckers
+macro test(body: untyped) =
+  var a = initCountTable[NimNode]()
+  a.inc(body)
+
+test:
+  1 + 1
diff --git a/tests/ccgbugs/tobjconstr_bad_aliasing.nim b/tests/ccgbugs/tobjconstr_bad_aliasing.nim
new file mode 100644
index 000000000..550f9ab75
--- /dev/null
+++ b/tests/ccgbugs/tobjconstr_bad_aliasing.nim
@@ -0,0 +1,76 @@
+discard """
+  output: '''(10, (20, ))
+42
+(x: 900.0, y: 900.0)
+(x: 900.0, y: 900.0)
+(x: 900.0, y: 900.0)'''
+"""
+
+import strutils, sequtils
+
+# bug #668
+
+type
+  TThing = ref object
+    data: int
+    children: seq[TThing]
+
+proc `$`(t: TThing): string =
+  result = "($1, $2)" % @[$t.data, join(map(t.children, proc(th: TThing): string = $th), ", ")]
+
+proc somethingelse(): seq[TThing] =
+  result = @[TThing(data: 20, children: @[])]
+
+proc dosomething(): seq[TThing] =
+  result = somethingelse()
+
+  result = @[TThing(data: 10, children: result)]
+
+echo($dosomething()[0])
+
+
+# bug #9844
+
+proc f(v: int): int = v
+
+type X = object
+  v: int
+
+var x = X(v: 42)
+
+x = X(v: f(x.v))
+echo x.v
+
+
+# bug #11525
+type
+  Point[T] = object
+    x, y: T
+
+proc adjustPos[T](width, height: int, pos: Point[T]): Point[T] =
+  result = pos
+
+  result = Point[T](
+    x: pos.x - (width / 2),
+    y: pos.y - (height / 2)
+  )
+
+proc adjustPos2[T](width, height: int, pos: Point[T]): Point[T] =
+  result = pos
+
+  result = Point[T](
+    x: result.x - (width / 2),
+    y: result.y - (height / 2)
+  )
+
+proc adjustPos3(width, height: int, pos: Point): Point =
+  result = pos
+
+  result = Point(
+    x: result.x - (width / 2),
+    y: result.y - (height / 2)
+  )
+
+echo adjustPos(200, 200, Point[float](x: 1000, y: 1000))
+echo adjustPos2(200, 200, Point[float](x: 1000, y: 1000))
+echo adjustPos3(200, 200, Point[float](x: 1000, y: 1000))
diff --git a/tests/ccgbugs/tobjconstr_outoforder.nim b/tests/ccgbugs/tobjconstr_outoforder.nim
new file mode 100644
index 000000000..846a753d5
--- /dev/null
+++ b/tests/ccgbugs/tobjconstr_outoforder.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''(left: 1, up: 0, right: 2, down: 0)
+(left: 0, up: 1, right: 0, down: 2)
+@[(left: 1, up: 0, right: 2, down: 0), (left: 0, up: 1, right: 0, down: 2)]
+@[(left: 1, up: 0, right: 2, down: 0), (left: 0, up: 1, right: 0, down: 2)]
+true'''
+"""
+
+# bug #5339
+type
+  Dirs = object
+    left: int
+    up: int
+    right: int
+    down: int
+
+let
+  a = Dirs(
+    left: 1,
+    right: 2,
+  )
+  b = Dirs(
+    up: 1,
+    down: 2,
+  )
+  works = @[
+    a,
+    b,
+  ]
+  fails = @[
+    Dirs(left: 1, right: 2),
+    Dirs(up: 1, down: 2),
+  ]
+echo a
+echo b
+echo works
+echo fails
+echo works == fails
diff --git a/tests/ccgbugs/tobjconstr_regression.nim b/tests/ccgbugs/tobjconstr_regression.nim
new file mode 100644
index 000000000..d29abad97
--- /dev/null
+++ b/tests/ccgbugs/tobjconstr_regression.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''@[(username: "user", role: "admin", description: "desc", email_addr: "email"), (username: "user", role: "admin", description: "desc", email_addr: "email")]'''
+"""
+
+type
+  User = object of RootObj
+    username, role, description, email_addr: string
+
+# bug 5055
+let us4 = @[
+  User(username:"user", role:"admin", description:"desc", email_addr:"email"),
+  User(username:"user", role:"admin", description:"desc", email_addr:"email"),
+]
+echo us4
diff --git a/tests/ccgbugs/topenarraycast.nim b/tests/ccgbugs/topenarraycast.nim
new file mode 100644
index 000000000..7d1bc8d03
--- /dev/null
+++ b/tests/ccgbugs/topenarraycast.nim
@@ -0,0 +1,8 @@
+proc foo[T](s: var openArray[T]): T =
+  for x in s: result += x
+
+proc bar(xyz: var seq[int]) =
+  doAssert 6 == (seq[int](xyz)).foo()
+
+var t = @[1,2,3]
+bar(t)
diff --git a/tests/ccgbugs/tpartialcs.nim b/tests/ccgbugs/tpartialcs.nim
new file mode 100644
index 000000000..12ff65c37
--- /dev/null
+++ b/tests/ccgbugs/tpartialcs.nim
@@ -0,0 +1,20 @@
+
+# bug #2551
+
+type Tup = tuple
+  A, a: int
+
+type Obj = object
+  A, a: int
+
+var x: Tup # This works.
+var y: Obj # This doesn't.
+
+# bug #2212
+
+proc f() =
+  let
+    p = 1.0
+    P = 0.25 + 0.5
+
+f()
diff --git a/tests/ccgbugs/tprogmem.nim b/tests/ccgbugs/tprogmem.nim
new file mode 100644
index 000000000..58a20583a
--- /dev/null
+++ b/tests/ccgbugs/tprogmem.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "5"
+  cmd: r"nim c --hints:on $options -d:release $file"
+  ccodecheck: "'/*PROGMEM*/ myLetVariable = {'"
+  targets: "c"
+"""
+
+var myLetVariable {.exportc, codegenDecl: "$# /*PROGMEM*/ $#".} = [1, 2, 3]
+
+myLetVariable[0] = 5
+echo myLetVariable[0]
diff --git a/tests/ccgbugs/trecursive_table.nim b/tests/ccgbugs/trecursive_table.nim
new file mode 100644
index 000000000..3406a1c31
--- /dev/null
+++ b/tests/ccgbugs/trecursive_table.nim
@@ -0,0 +1,17 @@
+
+# bug #1700
+import tables
+
+type
+  E* = enum
+    eX
+    eY
+  T* = object
+    case kind: E
+    of eX:
+      xVal: Table[string, T]
+    of eY:
+      nil
+
+proc p*(x: Table[string, T]) =
+  discard
diff --git a/tests/ccgbugs/trefseqsort.nim b/tests/ccgbugs/trefseqsort.nim
new file mode 100644
index 000000000..2410770cf
--- /dev/null
+++ b/tests/ccgbugs/trefseqsort.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''@[0, 4, 9, 1, 3, 2]
+@[0, 1, 2, 3, 9]'''
+"""
+# bug #6724
+import algorithm
+
+type
+  Bar = object
+    bar: ref seq[int]
+  Foo = ref Bar
+
+proc test(x: ref Foo) =
+  x.bar[].del(1)
+  x.bar[].sort(cmp)
+
+proc main() =
+  var foo: ref Foo
+  new(foo)
+
+  var s = @[0, 4, 9, 1, 3, 2]
+
+  var sr: ref seq[int]
+  new(sr)
+  sr[] = s
+
+  foo[] = Foo(bar: sr)
+  echo($foo.bar[])
+
+  test(foo)
+  echo($foo.bar[])
+
+main()
diff --git a/tests/ccgbugs/tresult_of_array.nim b/tests/ccgbugs/tresult_of_array.nim
new file mode 100644
index 000000000..fb5abf18a
--- /dev/null
+++ b/tests/ccgbugs/tresult_of_array.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''false
+true
+false
+[false, false, false]
+'''
+"""
+
+# bug #7332
+# resetLoc generate incorrect memset code
+# because of array passed as argument decaying into a pointer
+
+import tables
+const tableOfArray = {
+    "one": [true, false, false],
+    "two": [false, true, false],
+    "three": [false, false, true]
+}.toTable()
+for i in 0..2:
+    echo tableOfArray["two"][i]
+
+var seqOfArray = @[
+    [true, false, false],
+    [false, true, false],
+    [false, false, true]
+]
+proc crashingProc*[B](t: seq[B], index: Natural): B =
+    discard
+echo seqOfArray.crashingProc(0)
diff --git a/tests/ccgbugs/tret_arg_init.nim b/tests/ccgbugs/tret_arg_init.nim
new file mode 100644
index 000000000..e39e5a0de
--- /dev/null
+++ b/tests/ccgbugs/tret_arg_init.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''
+
+
+
+'''
+"""
+
+type Bar = object
+  s1, s2: string
+
+proc initBar(): Bar = discard
+
+var a: array[5, Bar]
+a[0].s1 = "hey"
+a[0] = initBar()
+echo a[0].s1
+
+type Foo = object
+  b: Bar
+var f: Foo
+f.b.s1 = "hi"
+f.b = initBar()
+echo f.b.s1
+
+var ad = addr f.b
+ad[] = initBar()
+echo ad[].s1
diff --git a/tests/ccgbugs/tsamename3.nim b/tests/ccgbugs/tsamename3.nim
new file mode 100644
index 000000000..ded18e9f8
--- /dev/null
+++ b/tests/ccgbugs/tsamename3.nim
@@ -0,0 +1,120 @@
+block: # bug #15526
+  block:
+    type Foo = ref object
+      x1: int
+    let f1 = Foo(x1: 1)
+  block:
+    type Foo = ref object
+      x2: int
+    let f2 = Foo(x2: 2)
+
+block: # ditto
+  template fn() =
+    block:
+      type Foo = ref object
+        x1: int
+      let f1 = Foo(x1: 1)
+      doAssert f1.x1 == 1
+    block:
+      type Foo = ref object
+        x2: int
+      let f2 = Foo(x2: 2)
+      doAssert f2.x2 == 2
+  static: fn()
+  fn()
+
+block: # bug #17162
+  template fn =
+    var ret: string
+    block:
+      type A = enum a0, a1, a2
+      for ai in A:
+        ret.add $ai
+    block:
+      type A = enum b0, b1, b2, b3
+      for ai in A:
+        ret.add $ai
+    doAssert ret == "a0a1a2b0b1b2b3"
+
+  static: fn() # ok
+  fn() # was bug
+
+block: # ditto
+  proc fn =
+    var ret: string
+    block:
+      type A = enum a0, a1, a2
+      for ai in A:
+        ret.add $ai
+    block:
+      type A = enum b0, b1, b2, b3
+      for ai in A:
+        ret.add $ai
+    doAssert ret == "a0a1a2b0b1b2b3"
+
+  static: fn() # ok
+  fn() # was bug
+
+block: # bug #5170
+  block:
+    type Foo = object
+      x1: int
+    let f1 = Foo(x1: 1)
+  block:
+    type Foo = object
+      x2: int
+    let f2 = Foo(x2: 2)
+
+block: # ditto
+  block:
+    type Foo = object
+      bar: bool
+    var f1: Foo
+
+  block:
+    type Foo = object
+      baz: int
+    var f2: Foo
+    doAssert f2.baz == 0
+
+  block:
+    template fn() =
+      block:
+        type Foo = object
+          x1: int
+        let f1 = Foo(x1: 1)
+        doAssert f1.x1 == 1
+      block:
+        type Foo = object
+          x2: int
+        let f2 = Foo(x2: 2)
+        doAssert f2.x2 == 2
+    static: fn()
+    fn()
+
+when true: # ditto, refs https://github.com/nim-lang/Nim/issues/5170#issuecomment-582712132
+  type Foo1 = object # at top level
+    bar: bool
+  var f1: Foo1
+
+  block:
+    type Foo1 = object
+      baz: int
+    var f2: Foo1
+    doAssert f2.baz == 0
+
+block: # make sure `hashType` doesn't recurse infinitely
+  type
+    PFoo = ref object
+      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/ccgbugs/tsequence_outoforder.nim b/tests/ccgbugs/tsequence_outoforder.nim
new file mode 100644
index 000000000..93a45900d
--- /dev/null
+++ b/tests/ccgbugs/tsequence_outoforder.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''@[2]'''
+"""
+
+# bug #9684
+
+var s2 = @[2, 2]
+
+s2 = @[s2.len]
+
+echo s2
diff --git a/tests/ccgbugs/tsighash_typename_regression.nim b/tests/ccgbugs/tsighash_typename_regression.nim
new file mode 100644
index 000000000..b93eebd20
--- /dev/null
+++ b/tests/ccgbugs/tsighash_typename_regression.nim
@@ -0,0 +1,32 @@
+discard """
+output: '''
+123
+baz
+'''
+"""
+
+# bug #5147
+
+proc foo[T](t: T) =
+  type Wrapper = object
+    get: T
+  let w = Wrapper(get: t)
+  echo w.get
+
+foo(123)
+foo("baz")
+
+# Empty type in template is correctly disambiguated
+block:
+  template foo() =
+    type M = object
+      discard
+    var y = M()
+
+  foo()
+
+  type M = object
+    x: int
+
+  var x = M(x: 1)
+  doAssert(x.x == 1)
diff --git a/tests/ccgbugs/tstringslice.nim b/tests/ccgbugs/tstringslice.nim
new file mode 100644
index 000000000..0ff448dcf
--- /dev/null
+++ b/tests/ccgbugs/tstringslice.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''1
+1234
+2
+234
+3
+34
+4
+4'''
+"""
+
+# bug #794
+type TRange = range[0..3]
+
+const str = "123456789"
+
+for i in TRange.low .. TRange.high:
+  echo str[i]                          #This works fine
+  echo str[int(i) .. int(TRange.high)] #So does this
+  #echo str[i .. TRange.high]           #The compiler complains about this
diff --git a/tests/ccgbugs/tunsafeaddr.nim b/tests/ccgbugs/tunsafeaddr.nim
new file mode 100644
index 000000000..f868739de
--- /dev/null
+++ b/tests/ccgbugs/tunsafeaddr.nim
@@ -0,0 +1,47 @@
+discard """
+  output: '''12
+4'''
+"""
+
+{.emit: """
+NI sum(NI* a, NI len) {
+  NI i, result = 0;
+  for (i = 0; i < len; ++i) result += a[i];
+  return result;
+}
+""".}
+
+proc sum(a: ptr int; len: int): int {.importc, nodecl.}
+
+proc main =
+  let foo = [8, 3, 1]
+  echo sum(unsafeAddr foo[0], foo.len)
+
+
+# bug #3736
+
+proc p(x: seq[int]) = discard x[0].unsafeAddr # works
+proc q(x: seq[SomeInteger]) = discard x[0].unsafeAddr # doesn't work
+
+p(@[1])
+q(@[1])
+
+main()
+
+# bug #9403
+
+type
+  MyObj = ref object
+    len: int
+    val: UncheckedArray[uint64]
+
+proc spot(x: MyObj): int64 =
+  result = cast[UncheckedArray[int64]](x.val)[0]
+
+proc newMyObj(len: int): MyObj =
+  unsafeNew(result, sizeof(result[]) + len * sizeof(uint64))
+  result.len = len
+  result.val[0] = 4u64
+  result.val[1] = 8u64
+
+echo spot(newMyObj(2))
diff --git a/tests/ccgbugs/tuple_canon.nim b/tests/ccgbugs/tuple_canon.nim
new file mode 100644
index 000000000..fbb971861
--- /dev/null
+++ b/tests/ccgbugs/tuple_canon.nim
@@ -0,0 +1,119 @@
+discard """
+output: '''
+vidx 18
+0,0
+'''
+"""
+
+# bug #4626
+var foo: (int, array[1, int]) # Tuple must be of length > 1
+let bar = (1, [1])
+foo = bar                     # No error if assigned directly
+
+# bug #2250
+
+import math
+
+type
+    Meters = float
+    Point2[T] = tuple[x, y: T]
+
+    HexState* = enum
+        hsOn, hsOff
+
+    Index = uint16
+
+    HexGrid* = object
+        w, h: int                       ## Width and height of the hex grid.
+        radius: Meters                  ## Radius of circle that circumscribes a hexagon.
+        grid: seq[HexState]             ## Information on what hexes are drawn.
+
+    HexVtxIndex = enum
+        hiA, hiB, hiC, hiD, hiE, hiF
+
+    HexCoord* = Point2[int]
+
+const
+    HexDY = sqrt(1.0 - (0.5 * 0.5))     # dy from center to midpoint of 1-2
+    HexDX = sqrt(1.0 - (HexDY * HexDY)) # dx from center to midpoint of 1-5 (0.5)
+
+
+let
+    hexOffsets : array[HexVtxIndex, Point2[float]] = [
+                  (-1.0, 0.0),
+                  (-HexDX, -HexDY),
+                  (HexDX, -HexDY),
+                  (1.0, 0.0),
+                  (HexDX, HexDY),
+                  (-HexDX, HexDY)]
+
+    evenSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,-1), hiA),
+            ((1,0), hiB),
+            ((1,0), hiA),
+            ((0,1), hiB)]
+
+    oddSharingOffsets : array[HexVtxIndex, tuple[hc: HexCoord; idx: HexVtxIndex]] = [
+            ((0,0), hiA),
+            ((0,0), hiB),
+            ((1,0), hiA),
+            ((1,1), hiB),
+            ((1,1), hiA),
+            ((0,1), hiB)]
+
+template odd*(i: int) : untyped =
+    (i and 1) != 0
+
+proc vidx(hg: HexGrid; col, row: int; i: HexVtxIndex) : Index =
+    #NOTE: this variation compiles
+    #var offset : typeof(evenSharingOffsets[i])
+    #
+    #if odd(col):
+    #    offset = oddSharingOffsets[i]
+    #else:
+    #    offset = evenSharingOffsets[i]
+
+    let
+        #NOTE: this line generates the bad code
+        offset = (if odd(col): oddSharingOffsets[i] else: evenSharingOffsets[i])
+        x = col + 1 + offset.hc.x
+        y = row + 1 + offset.hc.y
+
+    result = Index(x*2 + y * (hg.w + 2)*2 + int(offset.idx))
+
+proc go() =
+    var hg : HexGrid
+
+    echo "vidx ", $vidx(hg, 1, 2, hiC)
+
+go()
+
+# another sighashes problem: In tuples we have to ignore ranges.
+
+type
+  Position = tuple[x, y: int16]
+  n16 = range[0'i16..high(int16)]
+
+proc print(pos: Position) =
+  echo $pos.x, ",", $pos.y
+
+var x = 0.n16
+var y = 0.n16
+print((x, y))
+
+
+# bug #6889
+proc createProgressSetterWithPropSetter[T](setter: proc(v: T)) = discard
+
+type A = distinct array[4, float32]
+type B = distinct array[3, float32]
+
+type Foo[T] = tuple
+    setter: proc(v: T)
+
+proc getFoo[T](): Foo[T] = discard
+
+createProgressSetterWithPropSetter(getFoo[A]().setter)
+createProgressSetterWithPropSetter(getFoo[B]().setter)
diff --git a/tests/ccgbugs/tuplecast.nim b/tests/ccgbugs/tuplecast.nim
new file mode 100644
index 000000000..d60e8c490
--- /dev/null
+++ b/tests/ccgbugs/tuplecast.nim
@@ -0,0 +1,8 @@
+
+# bug #4345
+
+# only needs to compile
+proc f(): tuple[a, b: uint8] = (1'u8, 2'u8)
+
+let a, b = f()
+let c = cast[int](b)
diff --git a/tests/ccgbugs/tweakopenarray.nim b/tests/ccgbugs/tweakopenarray.nim
new file mode 100644
index 000000000..51d781331
--- /dev/null
+++ b/tests/ccgbugs/tweakopenarray.nim
@@ -0,0 +1,12 @@
+# bug #4089
+
+type
+  Proc = proc(args: openArray[Bar]): Bar
+
+  Foo = object
+    p: Proc
+
+  Bar = object
+    f: Foo
+
+proc bar(val: Foo): Bar = Bar()
diff --git a/tests/ccgbugs/twrong_discriminant_check.nim b/tests/ccgbugs/twrong_discriminant_check.nim
new file mode 100644
index 000000000..a802f45ef
--- /dev/null
+++ b/tests/ccgbugs/twrong_discriminant_check.nim
@@ -0,0 +1,30 @@
+discard """
+  output: "(kind: None)"
+"""
+
+when true:
+  # bug #2637
+
+  type
+    OptionKind = enum
+      None,
+      Some
+
+    Option*[T] = object
+      case kind: OptionKind
+      of None:
+        discard
+      of Some:
+        value*: T
+
+  proc none*[T](): Option[T] =
+    Option[T](kind: None)
+
+  proc none*(T: typedesc): Option[T] = none[T]()
+
+
+  proc test(): Option[int] =
+    int.none
+
+  echo test()
+
diff --git a/tests/ccgbugs/twrong_method.nim b/tests/ccgbugs/twrong_method.nim
new file mode 100644
index 000000000..9879c6114
--- /dev/null
+++ b/tests/ccgbugs/twrong_method.nim
@@ -0,0 +1,27 @@
+discard """
+  cmd: "nim c -d:release $file"
+  output: '''correct method'''
+"""
+# bug #5439
+type
+  Control* = ref object of RootObj
+
+  ControlImpl* = ref object of Control
+
+  Container* = ref object of ControlImpl
+
+  ContainerImpl* = ref object of Container
+
+method testProc*(control: Control) {.base.} = echo "wrong method"
+
+method testProc*(container: Container) = echo "correct method"
+
+proc main()
+
+main() # wrong method called
+
+proc main() =
+  var container = new ContainerImpl
+  container.testProc()
+
+# main() # correct method called
diff --git a/tests/ccgbugs/twrong_rc_for_refarray.nim b/tests/ccgbugs/twrong_rc_for_refarray.nim
new file mode 100644
index 000000000..99bdac5e1
--- /dev/null
+++ b/tests/ccgbugs/twrong_rc_for_refarray.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''m[0][0] = 1.0
+m[0][0] = 2.0'''
+"""
+# bug #4653
+type
+  Vector = ref array[2, float64]
+  Matrix = ref array[2, Vector]
+
+proc newVector(): Vector =
+  new(result)
+
+proc newMatrix(): Matrix =
+  new(result)
+  for ix in 0 .. 1:
+    result[ix] = newVector()
+
+let m = newMatrix()
+
+m[0][0] = 1.0
+echo "m[0][0] = ", m[0][0]
+
+GC_fullCollect()
+
+m[0][0] = 2.0
+echo "m[0][0] = ", m[0][0]
diff --git a/tests/ccgbugs/twrong_string_asgn.nim b/tests/ccgbugs/twrong_string_asgn.nim
new file mode 100644
index 000000000..669b7f8f5
--- /dev/null
+++ b/tests/ccgbugs/twrong_string_asgn.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "adf"
+"""
+
+import asyncdispatch
+const
+  test = ["adf"]
+
+proc foo() {.async.} =
+  for i in test:
+    echo(i)
+
+var finished = false
+let x = foo()
+x.callback =
+  proc () =
+    finished = true
+
+while not finished: poll()
diff --git a/tests/ccgbugs/twrong_tupleconv.nim b/tests/ccgbugs/twrong_tupleconv.nim
new file mode 100644
index 000000000..031712dac
--- /dev/null
+++ b/tests/ccgbugs/twrong_tupleconv.nim
@@ -0,0 +1,35 @@
+discard """
+  targets: "c cpp"
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #1833
+iterator myitems*[T](a: var seq[T]): var T {.inline.} =
+  ## iterates over each item of `a` so that you can modify the yielded value.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    doAssert(len(a) == L, "the length of the seq changed while iterating over it")
+
+# Works fine
+var xs = @[1,2,3]
+for x in myitems(xs):
+  inc x
+
+# Tuples don't work
+var ys = @[(1,"a"),(2,"b"),(3,"c")]
+for y in myitems(ys):
+  inc y[0]
+
+# bug #16331
+type T1 = tuple[a, b: int]
+
+proc p(b: bool): string =
+  var x: T1 = (10, 20)
+  x = if b: (x.b, x.a) else: (-x.b, -x.a)
+  $x
+
+assert p(false) == "(a: -20, b: -10)"
+assert p(true) == "(a: 20, b: 10)"
diff --git a/tests/ccgbugs/twrongrefcounting.nim b/tests/ccgbugs/twrongrefcounting.nim
new file mode 100644
index 000000000..8ebaf4058
--- /dev/null
+++ b/tests/ccgbugs/twrongrefcounting.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''ok'''
+  cmd: "nim c -r --gc:refc -d:useGcAssert -d:useSysAssert -d:fulldebug -d:smokeCycles $file"
+"""
+
+# bug #9825
+func empty(T: typedesc): T = discard
+const emptyChunk = @(empty(array[10, byte]))
+
+var lst: seq[seq[byte]]
+lst.add emptyChunk
+
+doAssert($lst == "@[@[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]")
+
+
+# bug #6234
+type
+    Foo = ref object
+        s: seq[Bar]
+    Bar = ref object
+        f: Foo
+
+proc test() =
+    var f = Foo.new()
+    for i in 0 .. 5:
+        f.s = @[]
+        for j in 0 .. 5:
+            var b = Bar.new()
+            b.f = f
+            f.s.add(b)
+
+test()
+echo "ok"
diff --git a/tests/ccgbugs/xarray9578.nim b/tests/ccgbugs/xarray9578.nim
new file mode 100644
index 000000000..849f16821
--- /dev/null
+++ b/tests/ccgbugs/xarray9578.nim
@@ -0,0 +1,7 @@
+import t9578
+
+proc testArray*(x: var array[3,mytype]) =
+  f(x[0].addr)
+
+proc testArray2*(x: var ptr array[3,mytype]) =
+  f(x[0].addr)
diff --git a/tests/ccgbugs/xoa9578.nim b/tests/ccgbugs/xoa9578.nim
new file mode 100644
index 000000000..94ef34519
--- /dev/null
+++ b/tests/ccgbugs/xoa9578.nim
@@ -0,0 +1,4 @@
+import t9578
+
+proc testOpenArray*(x: var openArray[mytype]) =
+  f(x[0].addr)
diff --git a/tests/ccgbugs/xseq9578.nim b/tests/ccgbugs/xseq9578.nim
new file mode 100644
index 000000000..782efe04f
--- /dev/null
+++ b/tests/ccgbugs/xseq9578.nim
@@ -0,0 +1,7 @@
+import t9578
+
+proc testSeq*(x: var seq[mytype]) =
+  f(x[0].addr)
+
+proc testSeq2*(x: var ptr seq[mytype]) =
+  f(x[0].addr)
diff --git a/tests/ccgbugs/xtuple9578.nim b/tests/ccgbugs/xtuple9578.nim
new file mode 100644
index 000000000..b6320fc24
--- /dev/null
+++ b/tests/ccgbugs/xtuple9578.nim
@@ -0,0 +1,7 @@
+import t9578
+
+proc testTuple*(x: var tuple[a:mytype,b:mytype,c:mytype]) =
+  f(x[0].addr)
+
+proc testTuple2*(x: var ptr tuple[a:mytype,b:mytype,c:mytype]) =
+  f(x[0].addr)
diff --git a/tests/ccgbugs/xua9578.nim b/tests/ccgbugs/xua9578.nim
new file mode 100644
index 000000000..9ba6f8fbc
--- /dev/null
+++ b/tests/ccgbugs/xua9578.nim
@@ -0,0 +1,7 @@
+import t9578
+
+proc testUncheckedArray*(x: var UncheckedArray[mytype]) =
+  f(x[0].addr)
+
+proc testUncheckedArray2*(x: var ptr UncheckedArray[mytype]) =
+  f(x[0].addr)
diff --git a/tests/ccgbugs2/tcodegen.nim b/tests/ccgbugs2/tcodegen.nim
new file mode 100644
index 000000000..aac1ecaf3
--- /dev/null
+++ b/tests/ccgbugs2/tcodegen.nim
@@ -0,0 +1,47 @@
+discard """

+  targets: "c cpp"

+"""

+

+# bug #19094

+type

+  X = object

+    filler: array[2048, int]

+    innerAddress: uint

+

+proc initX(): X =

+  result.innerAddress = cast[uint](result.addr)

+

+proc initXInPlace(x: var X) =

+  x.innerAddress = cast[uint](x.addr)

+

+block: # NRVO1

+  var x = initX()

+  let innerAddress = x.innerAddress

+  let outerAddress = cast[uint](x.addr)

+  doAssert(innerAddress == outerAddress) # [OK]

+

+block: # NRVO2

+  var x: X

+  initXInPlace(x)

+  let innerAddress = x.innerAddress

+  let outerAddress = cast[uint](x.addr)

+  doAssert(innerAddress == outerAddress) # [OK]

+

+block: # bug #22354

+  type Object = object

+    foo: int

+

+  proc takeFoo(self: var Object): int =

+    result = self.foo

+    self.foo = 999

+

+  proc doSomething(self: var Object; foo: int = self.takeFoo()) =

+    discard

+

+  proc main() =

+    var obj = Object(foo: 2)

+    obj.doSomething()

+    doAssert obj.foo == 999

+

+

+  main()

diff --git a/tests/ccgbugs2/tinefficient_const_table.nim b/tests/ccgbugs2/tinefficient_const_table.nim
new file mode 100644
index 000000000..8ab895cb0
--- /dev/null
+++ b/tests/ccgbugs2/tinefficient_const_table.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''a
+long
+list
+of
+words'''
+  cmd: r"nim c --hints:on $options -d:release $file"
+  ccodecheck: "! @'genericSeqAssign'"
+  targets: "c"
+"""
+
+# bug #4354
+import tables
+import sets
+import strutils
+
+#const FRUITS = ["banana", "apple", "grapes"]
+#let FRUITS = ["banana", "apple", "grapes"].toHashSet
+const FRUITS = {"banana":0, "apple":0, "grapes":0}.toTable
+
+proc main() =
+    let L = "a long list of words".split()
+    for word in L:
+        if word notin FRUITS:
+            echo(word)
+
+main()
diff --git a/tests/cgitest.nim b/tests/cgitest.nim
deleted file mode 100755
index ef115c80b..000000000
--- a/tests/cgitest.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-# Test the new CGI module
-import strtabs, cgi
-
-
-#setTestData("name", "the andreas", "password", "rumpf\t\ttab")
-
-var myData = readData()
-validateData(myData, "name", "password")
-writeContentType()
-
-write(stdout, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n")
-write(stdout, "<html><head><title>Test</title></head><body>\n")
-writeln(stdout, "name: " & myData["name"])
-writeln(stdout, "password: " & myData["password"])
-writeln(stdout, "</body></html>")
diff --git a/tests/closure/t11042.nim b/tests/closure/t11042.nim
new file mode 100644
index 000000000..6a3928316
--- /dev/null
+++ b/tests/closure/t11042.nim
@@ -0,0 +1,55 @@
+discard """
+  output:'''
+foo: 1
+foo: 2
+bar: 1
+bar: 2
+foo: 1
+foo: 2
+bar: 1
+bar: 2
+bar: 3
+bar: 4
+bar: 5
+bar: 6
+bar: 7
+bar: 8
+bar: 9
+'''
+"""
+
+# bug #11042
+block:
+  iterator foo: int =
+    for x in 1..2:
+      echo "foo: ", x
+      for y in 1..2:
+        discard
+
+  for x in foo(): discard
+
+  let bar = iterator: int =
+    for x in 1..2:
+      echo "bar: ", x
+      for y in 1..2:
+        discard
+
+  for x in bar(): discard
+
+
+block:
+  iterator foo: int =
+    for x in 1..2:
+      echo "foo: ", x
+      for y in 1..2:
+        discard
+
+  for x in foo(): discard
+
+  let bar = iterator: int =
+    for x in 1..9:
+      echo "bar: ", x
+      for y in 1..2:
+        discard
+
+  for x in bar(): discard
\ No newline at end of file
diff --git a/tests/closure/t15594.nim b/tests/closure/t15594.nim
new file mode 100644
index 000000000..aacd9ed84
--- /dev/null
+++ b/tests/closure/t15594.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "The variable name cannot be `result`!"
+"""
+
+import sugar
+
+proc begin(): int =
+  capture result:
+    echo 1+1
+  result
diff --git a/tests/closure/t1641.nim b/tests/closure/t1641.nim
new file mode 100644
index 000000000..a3e4da367
--- /dev/null
+++ b/tests/closure/t1641.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''foo 0
+bar 0
+baz'''
+"""
+
+# bug #1641
+proc baz() =
+  echo "baz"
+
+proc bar(x: int, p: proc()) =
+  echo "bar ", x
+  p()
+
+proc foo(x: int, p: proc(x: int)) =
+  echo "foo ", x
+  p(x)
+
+let x = 0
+x.foo do(x: int): x.bar do(): baz()
diff --git a/tests/closure/t19095.nim b/tests/closure/t19095.nim
new file mode 100644
index 000000000..880456e02
--- /dev/null
+++ b/tests/closure/t19095.nim
@@ -0,0 +1,35 @@
+discard """
+  action: compile
+"""
+
+block:
+  func inCheck() =
+    discard
+
+  iterator iter(): int =
+    yield 0
+    yield 0
+
+  func search() =
+    let inCheck = 0
+
+    for i in iter():
+
+      proc hello() =
+        inCheck()
+
+  search()
+block:
+  iterator iter(): int =
+    yield 0
+    yield 0
+
+  func search() =
+    let lmrMoveCounter = 0
+
+    for i in iter():
+
+      proc hello() =
+        discard lmrMoveCounter
+
+  search()
diff --git a/tests/closure/t20152.nim b/tests/closure/t20152.nim
new file mode 100644
index 000000000..484ea0741
--- /dev/null
+++ b/tests/closure/t20152.nim
@@ -0,0 +1,20 @@
+discard """

+  action: compile

+"""

+

+proc foo() =

+  iterator it():int {.closure.} =

+    yield 1

+  proc useIter() {.nimcall.} =

+    var iii = it # <-- illegal capture

+    doAssert iii() == 1

+  useIter()

+foo()

+

+proc foo2() =

+  proc bar() = # Local function, but not a closure, because no captures

+    echo "hi"

+  proc baz() {.nimcall.} = # Calls local function

+    bar()

+  baz()

+foo2()

diff --git a/tests/closure/t8550.nim b/tests/closure/t8550.nim
new file mode 100644
index 000000000..a07f45cdc
--- /dev/null
+++ b/tests/closure/t8550.nim
@@ -0,0 +1,13 @@
+discard """
+  targets: "c js"
+  output: "@[\"42\"]"
+"""
+
+proc chk_fail(): seq[string] =
+  iterator x(): int {.closure.} = yield 42
+  proc f(cl: iterator(): int {.closure.}): seq[string] =
+    result = @[]
+    for i in cl(): result.add($i)
+  result = f(x)
+
+echo(chk_fail())
diff --git a/tests/closure/t9334.nim b/tests/closure/t9334.nim
new file mode 100644
index 000000000..36a9a7d77
--- /dev/null
+++ b/tests/closure/t9334.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim $target --hints:off $options -r $file"
+  nimout: '''@[1]
+@[1, 1]
+'''
+  nimoutFull: true
+"""
+proc p(s: var seq[int]): auto =
+  let sptr = addr s
+  return proc() = sptr[].add 1
+
+proc f =
+  var data = @[1]
+  p(data)()
+  echo repr data
+
+static:
+  f() # prints [1]
+f() # prints [1, 1]
diff --git a/tests/closure/tboehmdeepcopy.nim b/tests/closure/tboehmdeepcopy.nim
new file mode 100644
index 000000000..7c937ca10
--- /dev/null
+++ b/tests/closure/tboehmdeepcopy.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim c --gc:boehm $options $file"
+  output: '''meep'''
+  disabled: "windows"
+"""
+
+proc callit(it: proc ()) =
+  it()
+
+proc main =
+  var outer = "meep"
+  proc x =
+    echo outer
+  var y: proc()
+  deepCopy(y, x)
+  callit(y)
+
+main()
diff --git a/tests/closure/tcapture.nim b/tests/closure/tcapture.nim
new file mode 100644
index 000000000..dafc44739
--- /dev/null
+++ b/tests/closure/tcapture.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''
+to be, or not to be
+(v: 1)
+(w: -1)
+(v: 1)
+(w: -1)
+'''
+  joinable: false
+"""
+
+import sequtils, sugar
+
+let m = @[proc (s: string): string = "to " & s, proc (s: string): string = "not to " & s]
+var l = m.mapIt(capture([it], proc (s: string): string = it(s)))
+let r = l.mapIt(it("be"))
+echo r[0] & ", or " & r[1]
+
+type
+  O = object
+    v: int
+  U = object
+    w: int
+var o = O(v: 1)
+var u = U(w: -1)
+var execute: proc()
+capture o, u:
+  execute = proc() =
+    echo o
+    echo u
+execute()
+o.v = -1
+u.w = 1
+execute()
diff --git a/tests/closure/tclosure.nim b/tests/closure/tclosure.nim
new file mode 100644
index 000000000..401a71d40
--- /dev/null
+++ b/tests/closure/tclosure.nim
@@ -0,0 +1,504 @@
+discard """
+  targets: "c"
+  output: '''
+1 3 6 11 20 foo
+foo88
+23 24foo 88
+18
+18
+99
+99
+99
+99 99
+99 99
+12 99 99
+12 99 99
+success
+@[1, 2, 5]
+click at 10,20
+lost focus 1
+lost focus 2
+registered handler for UserEvent 1
+registered handler for UserEvent 2
+registered handler for UserEvent 3
+registered handler for UserEvent 4
+asdas
+processClient end
+false
+baro0
+foo88
+23 24foo 88
+foo88
+23 24foo 88
+11
+@[1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1]
+'''
+joinable: false
+"""
+
+
+block tclosure:
+  proc map(n: var openArray[int], fn: proc (x: int): int {.closure}) =
+    for i in 0..n.len-1: n[i] = fn(n[i])
+
+  proc each(n: openArray[int], fn: proc(x: int) {.closure.}) =
+    for i in 0..n.len-1:
+      fn(n[i])
+
+  var myData: array[0..4, int] = [0, 1, 2, 3, 4]
+
+  proc testA() =
+    var p = 0
+    map(myData, proc (x: int): int =
+                  result = x + 1 shl (proc (y: int): int =
+                    return y + p
+                  )(0)
+                  inc(p))
+
+  testA()
+
+  myData.each do (x: int):
+    write(stdout, x)
+    write(stdout, " ")
+
+  #OUT 2 4 6 8 10
+
+  # bug #5015
+
+  type Mutator = proc(matched: string): string {.noSideEffect, gcsafe.}
+
+  proc putMutated(
+      MutatorCount: static[int],
+      mTable: static[array[MutatorCount, Mutator]], input: string) =
+    for i in 0..<MutatorCount: echo mTable[i](input)
+
+  proc mutator0(matched: string): string =
+      "foo"
+
+  const
+    mTable = [Mutator(mutator0)]
+
+  putMutated(1, mTable, "foo")
+
+
+
+block tclosure0:
+  when true:
+    # test simple closure within dummy 'main':
+    proc dummy =
+      proc main2(param: int) =
+        var fooB = 23
+        proc outer(outerParam: string) =
+          var outerVar = 88
+          echo outerParam, outerVar
+          proc inner() =
+            block Test:
+              echo fooB, " ", param, outerParam, " ", outerVar
+          inner()
+        outer("foo")
+      main2(24)
+
+    dummy()
+
+  when true:
+    proc outer2(x:int) : proc(y:int):int =   # curry-ed application
+        return proc(y:int):int = x*y
+
+    var fn = outer2(6)  # the closure
+    echo fn(3)   # it works
+
+    var rawP = fn.rawProc()
+    var rawE = fn.rawEnv()
+
+    # A type to cast the function pointer into a nimcall
+    type TimesClosure = proc(a: int, x: pointer): int {.nimcall.}
+
+    # Call the function with its closure
+    echo cast[TimesClosure](rawP)(3, rawE)
+
+  when true:
+    proc outer =
+      var x, y: int = 99
+      proc innerA = echo x
+      proc innerB =
+        echo y
+        innerA()
+
+      innerA()
+      innerB()
+
+    outer()
+
+  when true:
+    proc indirectDep =
+      var x, y: int = 99
+      proc innerA = echo x, " ", y
+      proc innerB =
+        innerA()
+
+      innerA()
+      innerB()
+
+    indirectDep()
+
+  when true:
+    proc needlessIndirection =
+      var x, y: int = 99
+      proc indirection =
+        var z = 12
+        proc innerA = echo z, " ", x, " ", y
+        proc innerB =
+          innerA()
+
+        innerA()
+        innerB()
+      indirection()
+
+    needlessIndirection()
+
+
+
+
+
+
+block tclosure3:
+  proc main =
+    const n = 30
+    for iterations in 0..10_000:
+      var s: seq[proc(): string {.closure.}] = @[]
+      for i in 0 .. n-1:
+        (proc () =
+          let ii = i
+          s.add(proc(): string = return $(ii*ii)))()
+      for i in 0 .. n-1:
+        let val = s[i]()
+        if val != $(i*i): echo "bug  ", val
+
+      if getOccupiedMem() > 5000_000: quit("still a leak!")
+    echo "success"
+
+  main()
+
+
+
+import json, tables, sequtils
+block tclosure4:
+  proc run(json_params: OrderedTable) =
+    let json_elems = json_params["files"].elems
+    # These fail compilation.
+    var files = map(json_elems, proc (x: JsonNode): string = x.str)
+
+  let text = """{"files": ["a", "b", "c"]}"""
+  run((text.parseJson).fields)
+
+
+
+import sugar
+block inference3304:
+  type
+    List[T] = ref object
+      val: T
+
+  proc foo[T](l: List[T]): seq[int] =
+    @[1,2,3,5].filter(x => x != l.val)
+
+  echo(foo(List[int](val: 3)))
+
+
+
+block tcodegenerr1923:
+  type
+    Foo[M] = proc() : M
+
+  proc bar[M](f : Foo[M]) =
+    discard f()
+
+  proc baz() : int = 42
+
+  bar(baz)
+
+
+
+block doNotation:
+  type
+    Button = object
+    Event = object
+      x, y: int
+
+  proc onClick(x: Button, handler: proc(x: Event)) =
+    handler(Event(x: 10, y: 20))
+
+  proc onFocusLost(x: Button, handler: proc()) =
+    handler()
+
+  proc onUserEvent(x: Button, eventName: string, handler: proc) =
+    echo "registered handler for ", eventName
+
+  var b = Button()
+
+  b.onClick do (e: Event):
+    echo "click at ", e.x, ",", e.y
+
+  b.onFocusLost do ():
+    echo "lost focus 1"
+
+  b.onFocusLost do ():
+    echo "lost focus 2"
+
+  b.onUserEvent("UserEvent 1") do ():
+    discard
+
+  onUserEvent(b, "UserEvent 2") do ():
+    discard
+
+  b.onUserEvent("UserEvent 3") do ():
+    discard
+
+  b.onUserEvent("UserEvent 4", () => echo "event 4")
+
+
+
+import tables
+block fib50:
+  proc memoize(f: proc (a: int64): int64): proc (a: int64): int64 =
+      var previous = initTable[int64, int64]()
+      return proc(i: int64): int64 =
+          if not previous.hasKey i:
+              previous[i] = f(i)
+          return previous[i]
+
+  var fib: proc(a: int64): int64
+
+  fib = memoize(proc (i: int64): int64 =
+      if i == 0 or i == 1:
+          return 1
+      return fib(i-1) + fib(i-2)
+  )
+
+  doAssert fib(50) == 20365011074
+
+
+
+block tflatmap:
+  # bug #3995
+  type
+    RNG = tuple[]
+    Rand[A] = (RNG) -> (A, RNG)
+
+  proc nextInt(r: RNG): (int, RNG) =
+    (1, ())
+
+  proc flatMap[A,B](f: Rand[A], g: A -> Rand[B]): Rand[B] =
+    (rng: RNG) => (
+      let (a, rng2) = f(rng);
+      let g1 = g(a);
+      g1(rng2)
+    )
+
+  proc map[A,B](s: Rand[A], f: A -> B): Rand[B] =
+    let g: A -> Rand[B] = (a: A) => ((rng: RNG) => (f(a), rng))
+    flatMap(s, g)
+
+  discard nextInt.map(i => i - i mod 2)
+
+
+
+block tforum:
+  type
+    PAsyncHttpServer = ref object
+      value: string
+    PFutureBase = ref object
+      callback: proc () {.closure.}
+      value: string
+      failed: bool
+
+  proc accept(server: PAsyncHttpServer): PFutureBase =
+    new(result)
+    result.callback = proc () =
+      discard
+    server.value = "hahaha"
+
+  proc processClient(): PFutureBase =
+    new(result)
+
+  proc serve(server: PAsyncHttpServer): PFutureBase =
+    iterator serveIter(): PFutureBase {.closure.} =
+      echo server.value
+      while true:
+        var acceptAddrFut = server.accept()
+        yield acceptAddrFut
+        var fut = acceptAddrFut.value
+
+        var f = processClient()
+        f.callback =
+          proc () =
+            echo("processClient end")
+            echo(f.failed)
+        yield f
+    var x = serveIter
+    for i in 0 .. 1:
+      result = x()
+      result.callback()
+
+  discard serve(PAsyncHttpServer(value: "asdas"))
+
+
+
+block futclosure2138:
+  proc any[T](list: varargs[T], pred: (T) -> bool): bool =
+    for item in list:
+        if pred(item):
+            result = true
+            break
+
+  proc contains(s: string, words: varargs[string]): bool =
+    any(words, (word) => s.contains(word))
+
+
+
+block tinterf:
+  type
+    ITest = tuple[
+      setter: proc(v: int) {.closure.},
+      getter1: proc(): int {.closure.},
+      getter2: proc(): int {.closure.}]
+
+  proc getInterf(): ITest =
+    var shared1, shared2: int
+
+    return (setter: proc (x: int) =
+              shared1 = x
+              shared2 = x + 10,
+            getter1: proc (): int = result = shared1,
+            getter2: proc (): int = return shared2)
+
+  var i = getInterf()
+  i.setter(56)
+
+  doAssert i.getter1() == 56
+  doAssert i.getter2() == 66
+
+
+
+block tjester:
+  type
+    Future[T] = ref object
+      data: T
+      callback: proc () {.closure.}
+
+  proc cbOuter(response: string) {.discardable.} =
+    iterator cbIter(): Future[int] {.closure.} =
+      for i in 0..7:
+        proc foo(): int =
+          iterator fooIter(): Future[int] {.closure.} =
+            echo response, i
+            yield Future[int](data: 17)
+          var iterVar = fooIter
+          iterVar().data
+        yield Future[int](data: foo())
+
+    var iterVar2 = cbIter
+    proc cb2() {.closure.} =
+      try:
+        if not finished(iterVar2):
+          let next = iterVar2()
+          if next != nil:
+            next.callback = cb2
+      except:
+        echo "WTF"
+    cb2()
+
+  cbOuter "baro"
+
+
+
+block tnamedparamanonproc:
+  type
+    PButton = ref object
+    TButtonClicked = proc(button: PButton) {.nimcall.}
+
+  proc newButton(onClick: TButtonClicked) =
+    discard
+
+  proc main() =
+    newButton(onClick = proc(b: PButton) =
+      var requestomat = 12
+      )
+
+  main()
+
+
+
+block tnestedclosure:
+  proc main(param: int) =
+    var foo = 23
+    proc outer(outerParam: string) =
+      var outerVar = 88
+      echo outerParam, outerVar
+      proc inner() =
+        block Test:
+          echo foo, " ", param, outerParam, " ", outerVar
+      inner()
+    outer("foo")
+
+  # test simple closure within dummy 'main':
+  proc dummy =
+    proc main2(param: int) =
+      var fooB = 23
+      proc outer(outerParam: string) =
+        var outerVar = 88
+        echo outerParam, outerVar
+        proc inner() =
+          block Test:
+            echo fooB, " ", param, outerParam, " ", outerVar
+        inner()
+      outer("foo")
+    main2(24)
+
+  dummy()
+
+  main(24)
+
+  # Jester + async triggered this bug:
+  proc cbOuter() =
+    var response = "hohoho"
+    block:
+      proc cbIter() =
+        block:
+          proc fooIter() =
+            doAssert response == "hohoho"
+          fooIter()
+      cbIter()
+  cbOuter()
+
+
+
+block tnestedproc:
+  proc p(x, y: int): int =
+    result = x + y
+
+  echo p((proc (): int =
+            var x = 7
+            return x)(),
+         (proc (): int = return 4)())
+
+
+
+block tnoclosure:
+  proc pascal(n: int) =
+    var row = @[1]
+    for r in 1..n:
+      row = zip(row & @[0], @[0] & row).mapIt(it[0] + it[1])
+    echo row
+  pascal(10)
+
+block: # bug #22297
+  iterator f: int {.closure.} =
+    try:
+      yield 12
+    finally:
+      return 14
+
+  let s = f
+  doAssert s() == 12
+  doAssert s() == 14
diff --git a/tests/closure/tclosure_issues.nim b/tests/closure/tclosure_issues.nim
new file mode 100644
index 000000000..b1a2d7c6b
--- /dev/null
+++ b/tests/closure/tclosure_issues.nim
@@ -0,0 +1,82 @@
+discard """
+  output: '''true
+(999, 0)
+ok 0
+ok 1
+ok 2
+'''
+"""
+
+
+block tissue600:
+  for i in 1..1:
+    var reported = false
+    proc report() =
+      reported = true
+
+
+
+import sequtils
+block tissue1502def:
+  let xs: seq[tuple[key: string, val: seq[string]]] = @[("foo", @["bar"])]
+
+  let maps = xs.map(
+    proc(x: auto): tuple[typ: string, maps: seq[string]] =
+      (x.key, x.val.map(proc(x: string): string = x)))
+
+
+
+block tissue1642:
+  var i = 0
+  proc p() = inc(i)
+
+
+
+block tissue1846:
+  type
+    TBinOp[T] = proc (x,y: T): bool
+    THeap[T] = object
+      cmp: TBinOp[T]
+
+  proc less[T](x,y: T): bool =
+    x < y
+
+  proc initHeap[T](cmp: TBinOp[T]): THeap[T] =
+    result.cmp = cmp
+
+  var h = initHeap[int](less[int])
+  echo h.cmp(2,3)
+
+
+
+block tissue1911:
+  proc foo(x: int) : auto =
+
+    proc helper() : int = x
+    proc bar() : int = helper()
+    proc baz() : int = helper()
+
+    return (bar, baz)
+
+# bug #11523
+proc foo(): proc =
+  let a = 999
+  return proc(): (int, int) =
+    return (a, 0)
+
+echo foo()()
+
+
+block tissue7104:
+  proc sp(cb: proc())=
+      cb()
+
+  sp do ():
+      var i = 0
+      echo "ok ", i
+      sp do ():
+          inc i
+          echo "ok ", i
+          sp do ():
+              inc i
+              echo "ok ", i
diff --git a/tests/closure/texplicit_dummy_closure.nim b/tests/closure/texplicit_dummy_closure.nim
new file mode 100644
index 000000000..02b9ac7c7
--- /dev/null
+++ b/tests/closure/texplicit_dummy_closure.nim
@@ -0,0 +1,25 @@
+discard """
+  disabled: true
+"""
+
+# This is a regression of the new lambda lifting; detected by Aporia
+import asyncio, sockets
+import os
+
+type
+  Window = object
+    oneInstSock*: AsyncSocket
+    IODispatcher*: Dispatcher
+
+var
+  win: Window
+
+proc initSocket() =
+  win.oneInstSock = asyncSocket()
+  #win.oneInstSock.handleAccept =
+  proc test(s: AsyncSocket) =
+    var client: AsyncSocket
+    proc dummy(c: AsyncSocket) {.closure.} =
+      discard
+    client.handleRead = dummy
+  test(win.oneInstSock)
diff --git a/tests/closure/tinfer_closure_for_nestedproc.nim b/tests/closure/tinfer_closure_for_nestedproc.nim
new file mode 100644
index 000000000..6450d1492
--- /dev/null
+++ b/tests/closure/tinfer_closure_for_nestedproc.nim
@@ -0,0 +1,42 @@
+discard """
+  action: compile
+"""
+
+# bug #9441
+import asyncdispatch, asyncfutures, strtabs
+
+type
+  Request = object
+  Context = object
+    position: int
+    accept: bool
+    headers: StringTableRef
+  Handler = proc (r: ref Request, c: Context): Future[Context]
+
+proc respond(req: Request): Future[void] = discard
+
+proc handle*(h: Handler): auto = # (proc (req: Request): Future[void]) =
+  proc server(req: Request): Future[void] {.async.} =
+    let emptyCtx = Context(
+      position: 0,
+      accept: true,
+      headers: newStringTable()
+    )
+    var reqHeap = new(Request)
+    reqHeap[] = req
+    var
+      f: Future[Context]
+      ctx: Context
+    try:
+      f = h(reqHeap, emptyCtx)
+      ctx = await f
+    except:
+      discard
+    if f.failed:
+      await req.respond()
+    else:
+      if not ctx.accept:
+        await req.respond()
+  return server
+
+waitFor handle(nil)(Request())
diff --git a/tests/closure/tinvalidclosure.nim b/tests/closure/tinvalidclosure.nim
new file mode 100644
index 000000000..37d0f68a2
--- /dev/null
+++ b/tests/closure/tinvalidclosure.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got <proc (x: int){.nimcall, gcsafe.}>"
+  line: 12
+"""
+
+proc ugh[T](x: T) {.nimcall.} =
+  echo "ugha"
+
+
+proc takeCdecl(p: proc (x: int) {.cdecl.}) = discard
+
+takeCDecl(ugh[int])
diff --git a/tests/closure/tinvalidclosure2.nim b/tests/closure/tinvalidclosure2.nim
new file mode 100644
index 000000000..2d58f0215
--- /dev/null
+++ b/tests/closure/tinvalidclosure2.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "illegal capture 'A'"
+  line: 10
+"""
+
+proc outer() =
+  var A: int
+
+  proc ugh[T](x: T) {.cdecl.} =
+    echo "ugha", A, x
+
+  ugh[int](12)
+
+outer()
diff --git a/tests/closure/tinvalidclosure3.nim b/tests/closure/tinvalidclosure3.nim
new file mode 100644
index 000000000..0cbdaf39e
--- /dev/null
+++ b/tests/closure/tinvalidclosure3.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "illegal capture 'x'"
+  line: 9
+"""
+
+proc outer(arg: string) =
+  var x = 0
+  proc inner {.inline.} =
+    echo "inner", x
+  inner()
+
+outer("abc")
diff --git a/tests/closure/tinvalidclosure4.nim b/tests/closure/tinvalidclosure4.nim
new file mode 100644
index 000000000..7985a2488
--- /dev/null
+++ b/tests/closure/tinvalidclosure4.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "illegal capture 'v'"
+  line: 7
+"""
+
+proc outer(v: int) =
+  proc b {.nimcall.} = echo v
+  b()
+outer(5)
diff --git a/tests/closure/tinvalidclosure5.nim b/tests/closure/tinvalidclosure5.nim
new file mode 100644
index 000000000..3b5f46a40
--- /dev/null
+++ b/tests/closure/tinvalidclosure5.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <proc (){.closure, gcsafe.}> but expected 'A = proc (){.nimcall.}'"
+  line: 9
+"""
+
+type A = proc() {.nimcall.}
+proc main =
+  let b = 1
+  let a: A = proc() = echo b
+
diff --git a/tests/closure/tmacrobust1512.nim b/tests/closure/tmacrobust1512.nim
new file mode 100644
index 000000000..0f44c5e1a
--- /dev/null
+++ b/tests/closure/tmacrobust1512.nim
@@ -0,0 +1,123 @@
+discard """
+output: ""
+"""
+
+import macros, strutils
+
+# https://github.com/nim-lang/Nim/issues/1512
+
+proc macrobust0(input: string): string =
+  var output = ""
+  proc p1(a:string) =
+    output.add(a)
+
+  proc p2(a:string) = p1(a)
+  proc p3(a:string) = p2(a)
+  proc p4(a:string) = p3(a)
+  proc p5(a:string) = p4(a)
+  proc p6(a:string) = p5(a)
+  proc p7(a:string) = p6(a)
+  proc p8(a:string) = p7(a)
+  proc p9(a:string) = p8(a)
+  proc p10(a:string) = p9(a)
+  proc p11(a:string) = p10(a)
+  proc p12(a:string) = p11(a)
+  proc p13(a:string) = p12(a)
+  proc p14(a:string) = p13(a)
+  proc p15(a:string) = p14(a)
+  proc p16(a:string) = p15(a)
+  proc p17(a:string) = p16(a)
+  proc p18(a:string) = p17(a)
+  proc p19(a:string) = p18(a)
+  proc p20(a:string) = p19(a)
+
+  for a in input.split():
+    p20(a)
+    p19(a)
+    p18(a)
+    p17(a)
+    p16(a)
+    p15(a)
+    p14(a)
+    p13(a)
+    p12(a)
+    p11(a)
+    p10(a)
+    p9(a)
+    p8(a)
+    p7(a)
+    p6(a)
+    p5(a)
+    p4(a)
+    p3(a)
+    p2(a)
+    p1(a)
+
+  result = output
+
+macro macrobust(input: static[string]): untyped =
+  var output = ""
+  proc p1(a:string) =
+    output.add(a)
+
+  proc p2(a:string) = p1(a)
+  proc p3(a:string) = p2(a)
+  proc p4(a:string) = p3(a)
+  proc p5(a:string) = p4(a)
+  proc p6(a:string) = p5(a)
+  proc p7(a:string) = p6(a)
+  proc p8(a:string) = p7(a)
+  proc p9(a:string) = p8(a)
+  proc p10(a:string) = p9(a)
+  proc p11(a:string) = p10(a)
+  proc p12(a:string) = p11(a)
+  proc p13(a:string) = p12(a)
+  proc p14(a:string) = p13(a)
+  proc p15(a:string) = p14(a)
+  proc p16(a:string) = p15(a)
+  proc p17(a:string) = p16(a)
+  proc p18(a:string) = p17(a)
+  proc p19(a:string) = p18(a)
+  proc p20(a:string) = p19(a)
+
+  for a in input.split():
+    p20(a)
+    p19(a)
+    p18(a)
+    p17(a)
+    p16(a)
+    p15(a)
+    p14(a)
+    p13(a)
+    p12(a)
+    p11(a)
+    p10(a)
+    p9(a)
+    p8(a)
+    p7(a)
+    p6(a)
+    p5(a)
+    p4(a)
+    p3(a)
+    p2(a)
+    p1(a)
+
+  result = newLit(output)
+
+const input = """
+  fdsasadfsdfa sadfsdafsdaf
+  dsfsdafdsfadsfa fsdaasdfasdf
+  fsdafsadfsad asdfasdfasdf
+  fdsasdfasdfa sadfsadfsadf
+  sadfasdfsdaf sadfsdafsdaf dsfasdaf
+  sadfsdafsadf fdsasdafsadf fdsasadfsdaf
+  sdfasadfsdafdfsa sadfsadfsdaf
+  sdafsdaffsda sdfasadfsadf
+  fsdasdafsdfa sdfasdfafsda
+  sdfasdafsadf sdfasdafsdaf sdfasdafsdaf
+"""
+
+let str1 = macrobust(input)
+let str2 = macrobust0(input)
+
+doAssert str1 == str2
diff --git a/tests/closure/tnested.nim b/tests/closure/tnested.nim
new file mode 100644
index 000000000..ec5af9b13
--- /dev/null
+++ b/tests/closure/tnested.nim
@@ -0,0 +1,215 @@
+discard """
+targets: "c js"
+output: '''
+foo88
+23 24foo 88
+foo88
+23 24foo 88
+11
+int: 108
+0
+11
+1
+11
+2
+11
+3
+11
+4
+11
+5
+11
+6
+11
+7
+11
+8
+11
+9
+11
+11
+py
+py
+py
+py
+px
+6
+proc (){.closure, noSideEffect, gcsafe.}
+'''
+"""
+
+
+block tnestedclosure:
+  proc main(param: int) =
+    var foo = 23
+    proc outer(outerParam: string) =
+      var outerVar = 88
+      echo outerParam, outerVar
+      proc inner() =
+        block Test:
+          echo foo, " ", param, outerParam, " ", outerVar
+      inner()
+    outer("foo")
+
+  # test simple closure within dummy 'main':
+  proc dummy =
+    proc main2(param: int) =
+      var fooB = 23
+      proc outer(outerParam: string) =
+        var outerVar = 88
+        echo outerParam, outerVar
+        proc inner() =
+          block Test:
+            echo fooB, " ", param, outerParam, " ", outerVar
+        inner()
+      outer("foo")
+    main2(24)
+
+  dummy()
+
+  main(24)
+
+  # Jester + async triggered this bug:
+  proc cbOuter() =
+    var response = "hohoho"
+    block:
+      proc cbIter() =
+        block:
+          proc fooIter() =
+            doAssert response == "hohoho"
+          fooIter()
+      cbIter()
+  cbOuter()
+
+
+block tnestedproc:
+  proc p(x, y: int): int =
+    result = x + y
+
+  echo p((proc (): int =
+            var x = 7
+            return x)(),
+         (proc (): int = return 4)())
+
+
+block deeplynested:
+  # bug #4070
+  proc id(f: (proc())): auto =
+    return f
+
+  proc foo(myinteger: int): (iterator(): int) =
+    return iterator(): int {.closure.} =
+            proc bar() =
+              proc kk() =
+                echo "int: ", myinteger
+              kk()
+            id(bar)()
+
+  discard foo(108)()
+
+
+block tclosure2:
+  when true:
+    proc ax =
+      for xxxx in 0..9:
+        var i = 0
+        proc bx =
+          if i > 10:
+            echo xxxx
+            return
+          i += 1
+          #for j in 0 .. 0: echo i
+          bx()
+
+        bx()
+        echo i
+
+    ax()
+
+  when true:
+    proc accumulator(start: int): (proc(): int {.closure.}) =
+      var x = start-1
+      #let dummy = proc =
+      #  discard start
+
+      result = proc (): int =
+        #var x = 9
+        for i in 0 .. 0: x = x + 1
+
+        return x
+
+    var a = accumulator(3)
+    let b = accumulator(4)
+    echo a() + b() + a()
+
+
+    proc outer =
+
+      proc py() =
+        # no closure here:
+        for i in 0..3: echo "py"
+
+      py()
+
+    outer()
+
+
+  when true:
+    proc outer2 =
+      var errorValue = 3
+      proc fac[T](n: T): T =
+        if n < 0: result = errorValue
+        elif n <= 1: result = 1
+        else: result = n * fac(n-1)
+
+      proc px() {.closure.} =
+        echo "px"
+
+      proc py() {.closure.} =
+        echo "py"
+
+      let
+        mapping = {
+          "abc": px,
+          "xyz": py
+        }
+      mapping[0][1]()
+
+      echo fac(3)
+
+
+    outer2()
+
+# bug #5688
+
+import typetraits
+
+block:
+  proc myDiscard[T](a: T) = discard
+
+  proc foo() =
+    let a = 5
+    let f = (proc() =
+              myDiscard (proc() = echo a)
+            )
+    echo name(typeof(f))
+
+  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/closure/tstmtlist.nim b/tests/closure/tstmtlist.nim
new file mode 100644
index 000000000..6a1390617
--- /dev/null
+++ b/tests/closure/tstmtlist.nim
@@ -0,0 +1,9 @@
+discard """
+  action: compile
+"""
+
+proc foo(x: proc()) = x()
+foo: echo "a" #[tt.Warning
+     ^ statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead [StmtListLambda]]#
+foo do: echo "b" #[tt.Warning
+        ^ statement list expression assumed to be anonymous proc; this is deprecated, use `do (): ...` or `proc () = ...` instead [StmtListLambda]]#
diff --git a/tests/closure/ttimeinfo.nim b/tests/closure/ttimeinfo.nim
new file mode 100644
index 000000000..24d535cbf
--- /dev/null
+++ b/tests/closure/ttimeinfo.nim
@@ -0,0 +1,22 @@
+discard """
+output: '''
+@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z]
+@[2000-01-01T00:00:00Z, 2001-01-01T00:00:00Z, 2002-01-01T00:00:00Z, 2003-01-01T00:00:00Z, 2004-01-01T00:00:00Z, 2005-01-01T00:00:00Z, 2006-01-01T00:00:00Z, 2007-01-01T00:00:00Z, 2008-01-01T00:00:00Z, 2009-01-01T00:00:00Z, 2010-01-01T00:00:00Z, 2011-01-01T00:00:00Z, 2012-01-01T00:00:00Z, 2013-01-01T00:00:00Z, 2014-01-01T00:00:00Z, 2015-01-01T00:00:00Z]
+'''
+"""
+
+# bug #2073
+
+import sequtils
+import times
+
+# 1
+proc f(n: int): DateTime =
+  initDateTime(1, mJan, n, 0, 0, 0, utc())
+
+echo toSeq(2000 || 2015).map(f)
+
+# 2
+echo toSeq(2000 || 2015).map(proc (n: int): DateTime =
+  initDateTime(1, mJan, n, 0, 0, 0, utc())
+)
diff --git a/tests/closure/uclosures.nim b/tests/closure/uclosures.nim
new file mode 100644
index 000000000..f259cfeb9
--- /dev/null
+++ b/tests/closure/uclosures.nim
@@ -0,0 +1,23 @@
+# This test is included from within tunittests
+import unittest
+
+test "loop variables are captured by ref":
+  var funcs: seq[proc (): int {.closure.}] = @[]
+
+  for i in 0..10:
+    let ii = i
+    funcs.add do -> int: return ii * ii
+
+  check funcs[0]() == 100
+  check funcs[3]() == 100
+
+test "loop variables in closureScope are captured by copy":
+  var funcs: seq[proc (): int {.closure.}] = @[]
+
+  for i in 0..10:
+    closureScope:
+      let ii = i
+      funcs.add do -> int: return ii * ii
+
+  check funcs[0]() == 0
+  check funcs[3]() == 9
diff --git a/tests/codegen/titaniummangle.nim b/tests/codegen/titaniummangle.nim
new file mode 100644
index 000000000..4b45e59ae
--- /dev/null
+++ b/tests/codegen/titaniummangle.nim
@@ -0,0 +1,193 @@
+discard """
+  targets: "c"
+  matrix: "--debugger:native"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE6stringN14titaniummangle3FooE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3int7varargsI6stringE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle3BooE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE8typeDescIN14titaniummangle17EnumAnotherSampleEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI14uncheckedArrayI3intEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3setIN14titaniummangle10EnumSampleEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE4procI6string6stringE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3intN10Comparable10ComparableE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3int3int'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle10EnumSampleE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncEN14titaniummangle17EnumAnotherSampleE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI3int3intE7cstring'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE5tupleI5float5floatE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3intE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrIN14titaniummangle3FooEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3ptrI3ptrI3intEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3refIN14titaniummangle3FooEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3varIN14titaniummangle3FooEE5int325int323refIN14titaniummangle3FooEE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE3varI3intE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE9openArrayI6stringE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE5arrayI7range013intE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI3intE'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE10Container2I5int325int32E'"
+  ccodecheck: "'_ZN14titaniummangle8testFuncE9ContainerI10Container2I5int325int32EE'"
+"""
+
+#When debugging this notice that if one check fails, it can be due to any of the above.
+
+type
+  Comparable = concept x, y
+    (x < y) is bool
+
+  Foo = object
+    a: int32
+    b: int32
+
+  FooTuple = tuple
+    a: int
+    b: int
+
+  Container[T] = object
+    data: T
+      
+  Container2[T, T2] = object
+    data: T
+    data2: T2
+
+  Boo = distinct Foo
+
+  Coo = Foo
+
+  Doo = Boo | Foo 
+
+  TestProc = proc(a:string): string
+
+type EnumSample = enum
+  a, b, c
+
+type EnumAnotherSample = enum
+  a, b, c
+
+proc testFunc(a: set[EnumSample]) = 
+  echo $a
+
+proc testFunc(a: typedesc) = 
+  echo $a
+
+proc testFunc(a: ptr Foo) = 
+  echo repr a
+
+proc testFunc(s: string, a: Coo) = 
+  echo repr a
+
+proc testFunc(s: int, a: Comparable) = 
+  echo repr a
+
+proc testFunc(a: TestProc) = 
+  let b = ""
+  echo repr a("")
+
+proc testFunc(a: ref Foo) = 
+  echo repr a
+
+proc testFunc(b: Boo) = 
+  echo repr b
+
+proc testFunc(a: ptr UncheckedArray[int]) = 
+  echo repr a
+
+proc testFunc(a: ptr int) = 
+  echo repr a
+
+proc testFunc(a: ptr ptr int) = 
+  echo repr a
+
+proc testFunc(e: FooTuple, str: cstring) = 
+  echo e
+
+proc testFunc(e: (float, float)) = 
+  echo e
+
+proc testFunc(e: EnumSample) = 
+  echo e
+
+proc testFunc(e: var int) = 
+  echo e
+
+proc testFunc(e: var Foo, a, b: int32, refFoo: ref Foo) = 
+  echo e
+
+proc testFunc(xs: Container[int]) = 
+  let a = 2
+  echo xs
+
+proc testFunc(xs: Container2[int32, int32]) = 
+  let a = 2
+  echo xs
+
+proc testFunc(xs: Container[Container2[int32, int32]]) = 
+  let a = 2
+  echo xs
+
+proc testFunc(xs: seq[int]) = 
+  let a = 2
+  echo xs
+
+proc testFunc(xs: openArray[string]) = 
+  let a = 2
+  echo xs
+
+proc testFunc(xs: array[2, int]) = 
+  let a = 2
+  echo xs
+
+proc testFunc(e: EnumAnotherSample) = 
+  echo e
+
+proc testFunc(a, b: int) = 
+  echo "hola"
+  discard
+
+proc testFunc(a: int, xs: varargs[string]) = 
+  let a = 10
+  for x in xs:
+    echo x
+
+proc testFunc() = 
+  var a = 2
+  var aPtr = a.addr
+  var foo = Foo()
+  let refFoo : ref Foo = new(Foo)
+  let b = Foo().Boo()
+  let d: Doo = Foo()
+  testFunc("", Coo())
+  testFunc(1, )
+  testFunc(b)
+  testFunc(EnumAnotherSample)
+  var t = [1, 2]
+  let uArr = cast[ptr UncheckedArray[int]](t.addr)
+  testFunc(uArr)
+  testFunc({})
+  testFunc(proc(s:string): string = "test")
+  testFunc(20, a.int32)
+  testFunc(20, 2)
+  testFunc(EnumSample.c)
+  testFunc(EnumAnotherSample.c)
+  testFunc((2, 1), "adios")
+  testFunc((22.1, 1.2))
+  testFunc(a.addr)
+  testFunc(foo.addr)
+  testFunc(aPtr.addr)
+  testFunc(refFoo)
+  testFunc(foo, 2, 1, refFoo)
+  testFunc(a)
+  testFunc(@[2, 1, 2])
+  testFunc(@["hola"])
+  testFunc(2, "hola", "adios")
+  let arr: array[2, int] = [2, 1]
+  testFunc(arr)
+  testFunc(Container[int](data: 10))
+  let c2 = Container2[int32, int32](data: 10, data2: 20)
+  testFunc(c2)
+  testFunc(Container[Container2[int32, int32]](data: c2))
+  
+
+testFunc()
\ No newline at end of file
diff --git a/tests/collections/tactiontable.nim b/tests/collections/tactiontable.nim
new file mode 100644
index 000000000..3f15a70bd
--- /dev/null
+++ b/tests/collections/tactiontable.nim
@@ -0,0 +1,37 @@
+discard """
+  output: '''
+action 3 arg
+action 3 arg
+'''
+"""
+
+import tables
+
+proc action1(arg: string) =
+  echo "action 1 ", arg
+
+proc action2(arg: string) =
+  echo "action 2 ", arg
+
+proc action3(arg: string) =
+  echo "action 3 ", arg
+
+proc action4(arg: string) =
+  echo "action 4 ", arg
+
+var
+  actionTable1 = {
+    "A": action1,
+    "B": action2,
+    "C": action3,
+    "D": action4}.toTable
+
+const
+  actionTable2 = {
+    "A": action1,
+    "B": action2,
+    "C": action3,
+    "D": action4}.toTable
+
+actionTable1["C"]("arg")
+actionTable2["C"]("arg")
diff --git a/tests/collections/tcollections.nim b/tests/collections/tcollections.nim
new file mode 100644
index 000000000..7677f7c1a
--- /dev/null
+++ b/tests/collections/tcollections.nim
@@ -0,0 +1,105 @@
+discard """
+  targets: "c js"
+"""
+
+# see also: tdeques, tlists, tcritbits
+
+import sets, tables, sequtils
+
+block tapply:
+  var x = @[1, 2, 3]
+  x.apply(proc(x: var int) = x = x+10)
+  x.apply(proc(x: int): int = x+100)
+  x.applyIt(it+5000)
+  doAssert x == @[5111, 5112, 5113]
+
+block tmapit:
+  var x = @[1, 2, 3]
+  # This mapIt call will run with preallocation because ``len`` is available.
+  var y = x.mapIt($(it+10))
+  doAssert y == @["11", "12", "13"]
+
+  type structureWithoutLen = object
+    a: array[5, int]
+
+  iterator items(s: structureWithoutLen): int {.inline.} =
+    yield s.a[0]
+    yield s.a[1]
+    yield s.a[2]
+    yield s.a[3]
+    yield s.a[4]
+
+  var st: structureWithoutLen
+  st.a[0] = 0
+  st.a[1] = 1
+  st.a[2] = 2
+  st.a[3] = 3
+  st.a[4] = 4
+
+  # this will run without preallocating the result
+  # since ``len`` is not available
+  var r = st.mapIt($(it+10))
+  doAssert r == @["10", "11", "12", "13", "14"]
+
+
+
+# Collections to string:
+
+# Tests for tuples
+doAssert $(1, 2, 3) == "(1, 2, 3)"
+doAssert $("1", "2", "3") == """("1", "2", "3")"""
+doAssert $('1', '2', '3') == """('1', '2', '3')"""
+
+# Tests for seqs
+doAssert $(@[1, 2, 3]) == "@[1, 2, 3]"
+doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]"""
+doAssert $(@['1', '2', '3']) == """@['1', '2', '3']"""
+
+# Tests for sets
+doAssert $(toHashSet([1])) == "{1}"
+doAssert $(toHashSet(["1"])) == """{"1"}"""
+doAssert $(toHashSet(['1'])) == """{'1'}"""
+doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}"
+doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}"""
+doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}"""
+
+# see also: tcritbitsToString, tlistsToString
+
+# Tests for tables
+when defined(nimIntHash1):
+  doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}"""
+else:
+  doAssert $({1: "1", 2: "2"}.toTable) == """{2: "2", 1: "1"}"""
+let tabStr = $({"1": 1, "2": 2}.toTable)
+doAssert (tabStr == """{"2": 2, "1": 1}""" or tabStr == """{"1": 1, "2": 2}""")
+
+# Test escaping behavior
+block:
+  var s = ""
+  s.addQuoted('\0')
+  s.addQuoted('\31')
+  s.addQuoted('\127')
+  doAssert s == "'\\x00''\\x1F''\\x7F'"
+block:
+  var s = ""
+  s.addQuoted('\\')
+  s.addQuoted('\'')
+  s.addQuoted('\"')
+  doAssert s == """'\\''\'''\"'"""
+block:
+  var s = ""
+  s.addQuoted("Ã¥")
+  s.addQuoted("ä")
+  s.addQuoted("ö")
+  s.addEscapedChar('\xFF')
+  doAssert s == """"å""ä""ö"\xFF"""
+
+# Test customized element representation
+type CustomString = object
+
+proc addQuoted(s: var string, x: CustomString) =
+  s.add("<CustomString>")
+
+block:
+  let s = @[CustomString()]
+  doAssert $s == "@[<CustomString>]"
diff --git a/tests/collections/tcollections_to_string.nim b/tests/collections/tcollections_to_string.nim
new file mode 100644
index 000000000..62ba87334
--- /dev/null
+++ b/tests/collections/tcollections_to_string.nim
@@ -0,0 +1,115 @@
+discard """
+  exitcode: 0
+  output: ""
+"""
+import sets
+import tables
+import deques
+import lists
+import critbits
+
+# Tests for tuples
+doAssert $(1, 2, 3) == "(1, 2, 3)"
+doAssert $("1", "2", "3") == """("1", "2", "3")"""
+doAssert $('1', '2', '3') == """('1', '2', '3')"""
+
+# Tests for seqs
+doAssert $(@[1, 2, 3]) == "@[1, 2, 3]"
+doAssert $(@["1", "2", "3"]) == """@["1", "2", "3"]"""
+doAssert $(@['1', '2', '3']) == """@['1', '2', '3']"""
+
+# Tests for sets
+doAssert $(toHashSet([1])) == "{1}"
+doAssert $(toHashSet(["1"])) == """{"1"}"""
+doAssert $(toHashSet(['1'])) == """{'1'}"""
+doAssert $(toOrderedSet([1, 2, 3])) == "{1, 2, 3}"
+doAssert $(toOrderedSet(["1", "2", "3"])) == """{"1", "2", "3"}"""
+doAssert $(toOrderedSet(['1', '2', '3'])) == """{'1', '2', '3'}"""
+
+# Tests for tables
+when defined(nimIntHash1):
+  doAssert $({1: "1", 2: "2"}.toTable) == """{1: "1", 2: "2"}"""
+else:
+  doAssert $({1: "1", 2: "2"}.toTable) == """{2: "2", 1: "1"}"""
+doAssert $({"1": 1, "2": 2}.toTable) == """{"1": 1, "2": 2}"""
+
+# Tests for deques
+block:
+  var d = initDeque[int]()
+  d.addLast(1)
+  doAssert $d == "[1]"
+block:
+  var d = initDeque[string]()
+  d.addLast("1")
+  doAssert $d == """["1"]"""
+block:
+  var d = initDeque[char]()
+  d.addLast('1')
+  doAssert $d == "['1']"
+
+# Tests for lists
+block:
+  var l = initDoublyLinkedList[int]()
+  l.append(1)
+  l.append(2)
+  l.append(3)
+  doAssert $l == "[1, 2, 3]"
+block:
+  var l = initDoublyLinkedList[string]()
+  l.append("1")
+  l.append("2")
+  l.append("3")
+  doAssert $l == """["1", "2", "3"]"""
+block:
+  var l = initDoublyLinkedList[char]()
+  l.append('1')
+  l.append('2')
+  l.append('3')
+  doAssert $l == """['1', '2', '3']"""
+
+# Tests for critbits
+block:
+  var t: CritBitTree[int]
+  t["a"] = 1
+  doAssert $t == """{"a": 1}"""
+block:
+  var t: CritBitTree[string]
+  t["a"] = "1"
+  doAssert $t == """{"a": "1"}"""
+block:
+  var t: CritBitTree[char]
+  t["a"] = '1'
+  doAssert $t == """{"a": '1'}"""
+
+
+# Test escaping behavior
+block:
+  var s = ""
+  s.addQuoted('\0')
+  s.addQuoted('\31')
+  s.addQuoted('\127')
+  doAssert s == "'\\x00''\\x1F''\\x7F'"
+block:
+  var s = ""
+  s.addQuoted('\\')
+  s.addQuoted('\'')
+  s.addQuoted('\"')
+  doAssert s == """'\\''\'''\"'"""
+block:
+  var s = ""
+  s.addQuoted("Ã¥")
+  s.addQuoted("ä")
+  s.addQuoted("ö")
+  s.addEscapedChar('\xFF')
+  doAssert s == """"å""ä""ö"\xFF"""
+
+# Test customized element representation
+type CustomString = object
+
+proc addQuoted(s: var string, x: CustomString) =
+  s.add("<CustomString>")
+
+block:
+  let s = @[CustomString()]
+  doAssert $s == "@[<CustomString>]"
+
diff --git a/tests/collections/thashsets.nim b/tests/collections/thashsets.nim
new file mode 100644
index 000000000..359eaa51e
--- /dev/null
+++ b/tests/collections/thashsets.nim
@@ -0,0 +1,382 @@
+import sets, hashes, algorithm
+
+
+block setEquality:
+  var
+    a = initHashSet[int]()
+    b = initHashSet[int]()
+    c = initHashSet[string]()
+
+  for i in 0..5: a.incl(i)
+  for i in 1..6: b.incl(i)
+  for i in 0..5: c.incl($i)
+
+  doAssert map(a, proc(x: int): int = x + 1) == b
+  doAssert map(a, proc(x: int): string = $x) == c
+
+
+block setsContainingTuples:
+  var set = initHashSet[tuple[i: int, i64: int64, f: float]]()
+  set.incl( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert set.contains( (i: 123, i64: 123'i64, f: 3.14) )
+  doAssert( not set.contains( (i: 456, i64: 789'i64, f: 2.78) ) )
+
+
+block setWithTuplesWithSeqs:
+  var s = initHashSet[tuple[s: seq[int]]]()
+  s.incl( (s: @[1, 2, 3]) )
+  doAssert s.contains( (s: @[1, 2, 3]) )
+  doAssert( not s.contains((s: @[4, 5, 6])) )
+
+
+block setWithSequences:
+  var s = initHashSet[seq[int]]()
+  s.incl( @[1, 2, 3] )
+  doAssert s.contains(@[1, 2, 3])
+  doAssert( not s.contains(@[4, 5, 6]) )
+
+block setClearWorked:
+  var s = initHashSet[char]()
+
+  for c in "this is a test":
+    s.incl(c)
+
+  doAssert len(s) == 7
+  clear(s)
+  doAssert len(s) == 0
+
+  s.incl('z')
+  for c in "this is a test":
+    s.incl(c)
+
+  doAssert len(s) == 8
+
+block orderedSetClearWorked:
+  var s = initOrderedSet[char]()
+
+  for c in "eat at joes":
+    s.incl(c)
+
+  var r = ""
+
+  for c in items(s):
+    add(r, c)
+
+  doAssert r == "eat jos"
+  clear(s)
+
+  s.incl('z')
+  for c in "eat at joes":
+    s.incl(c)
+
+  r = ""
+  for c in items(s):
+    add(r, c)
+
+  doAssert r == "zeat jos"
+
+block hashForHashedSet:
+  let
+    seq1 = "This is the test."
+    seq2 = "the test is This."
+    s1 = seq1.toHashSet()
+    s2 = seq2.toHashSet()
+  doAssert s1 == s2
+  doAssert hash(s1) == hash(s2)
+
+block hashForOrderdSet:
+  let
+    str = "This is the test."
+    rstr = str.reversed
+
+  var
+    s1 = initOrderedSet[char]()
+    s2 = initOrderedSet[char]()
+    r = initOrderedSet[char]()
+    expected: Hash
+    added: seq[char] = @[]
+    reversed: Hash
+    radded: seq[char] = @[]
+
+  expected = 0
+  for c in str:
+    if (not (c in added)):
+      expected = expected !& hash(c)
+      added.add(c)
+    s1.incl(c)
+    s2.incl(c)
+  expected = !$expected
+  doAssert hash(s1) == expected
+  doAssert hash(s1) == hash(s2)
+  doAssert hash(s1) != hash(r)
+
+  reversed = 0
+  for c in rstr:
+    if (not (c in radded)):
+      reversed = reversed !& hash(c)
+      radded.add(c)
+    r.incl(c)
+  reversed = !$reversed
+  doAssert hash(r) == reversed
+  doAssert hash(s1) != reversed
+
+
+proc testModule() =
+  ## Internal micro test to validate docstrings and such.
+  block lenTest:
+    var values: HashSet[int]
+    doAssert values.len == 0
+    doAssert values.card == 0
+
+  block setIterator:
+    type pair = tuple[a, b: int]
+    var a, b = initHashSet[pair]()
+    a.incl((2, 3))
+    a.incl((3, 2))
+    a.incl((2, 3))
+    for x, y in a.items:
+      b.incl((x - 2, y + 1))
+    doAssert a.len == b.card
+    doAssert a.len == 2
+    #echo b
+
+  block setContains:
+    var values = initHashSet[int]()
+    doAssert(not values.contains(2))
+    values.incl(2)
+    doAssert values.contains(2)
+    values.excl(2)
+    doAssert(not values.contains(2))
+
+    values.incl(4)
+    var others = toHashSet([6, 7])
+    values.incl(others)
+    doAssert values.len == 3
+
+    values.init
+    doAssert values.containsOrIncl(2) == false
+    doAssert values.containsOrIncl(2) == true
+    var
+      a = toHashSet([1, 2])
+      b = toHashSet([1])
+    b.incl(2)
+    doAssert a == b
+
+  block exclusions:
+    var s = toHashSet([2, 3, 6, 7])
+    s.excl(2)
+    s.excl(2)
+    doAssert s.len == 3
+
+    var
+      numbers = toHashSet([1, 2, 3, 4, 5])
+      even = toHashSet([2, 4, 6, 8])
+    numbers.excl(even)
+    #echo numbers
+    # --> {1, 3, 5}
+
+  block toSeqAndString:
+    var a = toHashSet([2, 7, 5])
+    var b = initHashSet[int](a.len)
+    for x in [2, 7, 5]: b.incl(x)
+    doAssert($a == $b)
+    #echo a
+    #echo toHashSet(["no", "esc'aping", "is \" provided"])
+
+  #block orderedToSeqAndString:
+  #  echo toOrderedSet([2, 4, 5])
+  #  echo toOrderedSet(["no", "esc'aping", "is \" provided"])
+
+  block setOperations:
+    var
+      a = toHashSet(["a", "b"])
+      b = toHashSet(["b", "c"])
+      c = union(a, b)
+    doAssert c == toHashSet(["a", "b", "c"])
+    var d = intersection(a, b)
+    doAssert d == toHashSet(["b"])
+    var e = difference(a, b)
+    doAssert e == toHashSet(["a"])
+    var f = symmetricDifference(a, b)
+    doAssert f == toHashSet(["a", "c"])
+    doAssert d < a and d < b
+    doAssert((a < a) == false)
+    doAssert d <= a and d <= b
+    doAssert((a <= a))
+    # Alias test.
+    doAssert a + b == toHashSet(["a", "b", "c"])
+    doAssert a * b == toHashSet(["b"])
+    doAssert a - b == toHashSet(["a"])
+    doAssert a -+- b == toHashSet(["a", "c"])
+    doAssert disjoint(a, b) == false
+    doAssert disjoint(a, b - a) == true
+
+  block mapSet:
+    var a = toHashSet([1, 2, 3])
+    var b = a.map(proc (x: int): string = $x)
+    doAssert b == toHashSet(["1", "2", "3"])
+
+  block lenTest:
+    var values: OrderedSet[int]
+    doAssert values.len == 0
+    doAssert values.card == 0
+
+  block setIterator:
+    type pair = tuple[a, b: int]
+    var a, b = initOrderedSet[pair]()
+    a.incl((2, 3))
+    a.incl((3, 2))
+    a.incl((2, 3))
+    for x, y in a.items:
+      b.incl((x - 2, y + 1))
+    doAssert a.len == b.card
+    doAssert a.len == 2
+
+  block setPairsIterator:
+    var s = toOrderedSet([1, 3, 5, 7])
+    var items = newSeq[tuple[a: int, b: int]]()
+    for idx, item in s: items.add((idx, item))
+    doAssert items == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+
+  block exclusions:
+    var s = toOrderedSet([1, 2, 3, 6, 7, 4])
+
+    s.excl(3)
+    s.excl(3)
+    s.excl(1)
+    s.excl(4)
+
+    var items = newSeq[int]()
+    for item in s: items.add item
+    doAssert items == @[2, 6, 7]
+
+  block: #9005
+    var s = initOrderedSet[(int, int)]()
+    for i in 0 .. 30: incl(s, (i, 0))
+    for i in 0 .. 30: excl(s, (i, 0))
+    doAssert s.len == 0
+
+  #block orderedSetIterator:
+  #  var a = initOrderedSet[int]()
+  #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
+  #    a.incl(value)
+  #  for value in a.items:
+  #    echo "Got ", value
+
+  block setContains:
+    var values = initOrderedSet[int]()
+    doAssert(not values.contains(2))
+    values.incl(2)
+    doAssert values.contains(2)
+
+  block toSeqAndString:
+    var a = toOrderedSet([2, 4, 5])
+    var b = initOrderedSet[int]()
+    for x in [2, 4, 5]: b.incl(x)
+    doAssert($a == $b)
+    doAssert(a == b) # https://github.com/Araq/Nim/issues/1413
+
+  block initBlocks:
+    var a: OrderedSet[int]
+    a.init(4)
+    a.incl(2)
+    a.init
+    doAssert a.len == 0
+    a = initOrderedSet[int](4)
+    a.incl(2)
+    doAssert a.len == 1
+
+    var b: HashSet[int]
+    b.init(4)
+    b.incl(2)
+    b.init
+    doAssert b.len == 0
+    b = initHashSet[int](4)
+    b.incl(2)
+    doAssert b.len == 1
+
+  block missingOrExcl:
+    var s = toOrderedSet([2, 3, 6, 7])
+    doAssert s.missingOrExcl(4) == true
+    doAssert s.missingOrExcl(6) == false
+
+  block orderedSetEquality:
+    type pair = tuple[a, b: int]
+
+    var aa = initOrderedSet[pair]()
+    var bb = initOrderedSet[pair]()
+
+    var x = (a: 1, b: 2)
+    var y = (a: 3, b: 4)
+
+    aa.incl(x)
+    aa.incl(y)
+
+    bb.incl(x)
+    bb.incl(y)
+    doAssert aa == bb
+
+  block setsWithoutInit:
+    var
+      a: HashSet[int]
+      b: HashSet[int]
+      c: HashSet[int]
+      d: HashSet[int]
+      e: HashSet[int]
+
+    doAssert a.containsOrIncl(3) == false
+    doAssert a.contains(3)
+    doAssert a.len == 1
+    doAssert a.containsOrIncl(3)
+    a.incl(3)
+    doAssert a.len == 1
+    a.incl(6)
+    doAssert a.len == 2
+
+    b.incl(5)
+    doAssert b.len == 1
+    b.excl(5)
+    b.excl(c)
+    doAssert b.missingOrExcl(5)
+    doAssert b.disjoint(c)
+
+    d = b + c
+    doAssert d.len == 0
+    d = b * c
+    doAssert d.len == 0
+    d = b - c
+    doAssert d.len == 0
+    d = b -+- c
+    doAssert d.len == 0
+
+    doAssert (d < e) == false
+    doAssert d <= e
+    doAssert d == e
+
+  block setsWithoutInit:
+    var
+      a: OrderedSet[int]
+      b: OrderedSet[int]
+      c: OrderedSet[int]
+      d: HashSet[int]
+
+
+    doAssert a.containsOrIncl(3) == false
+    doAssert a.contains(3)
+    doAssert a.len == 1
+    doAssert a.containsOrIncl(3)
+    a.incl(3)
+    doAssert a.len == 1
+    a.incl(6)
+    doAssert a.len == 2
+
+    b.incl(5)
+    doAssert b.len == 1
+    doAssert b.missingOrExcl(5) == false
+    doAssert b.missingOrExcl(5)
+
+    doAssert c.missingOrExcl(9)
+    d.incl(c)
+    doAssert d.len == 0
+
+testModule()
diff --git a/tests/collections/tseq.nim b/tests/collections/tseq.nim
new file mode 100644
index 000000000..0f8084c78
--- /dev/null
+++ b/tests/collections/tseq.nim
@@ -0,0 +1,242 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+Hithere, what's your name?Hathere, what's your name?
+fA13msg1falsefB14msg2truefC15msg3false
+Zip: [{"Field0": 1, "Field1": 2}, {"Field0": 3, "Field1": 4}, {"Field0": 5, "Field1": 6}]
+Filter Iterator: 3
+Filter Iterator: 5
+Filter Iterator: 7
+Filter: [3, 5, 7]
+FilterIt: [1, 3, 7]
+Concat: [1, 3, 5, 7, 2, 4, 6]
+Deduplicate: [1, 2, 3, 4, 5, 7]
+@[()]
+Minmax: (1, 7)
+2345623456
+'''
+"""
+
+block tseq2:
+  proc `*`(a, b: seq[int]): seq[int] =
+    # allocate a new sequence:
+    newSeq(result, len(a))
+    # multiply two int sequences:
+    for i in 0..len(a)-1: result[i] = a[i] * b[i]
+
+  doAssert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
+
+
+
+block tseqcon:
+  const nestedFixed = true
+
+  type
+    TRec {.final.} = object
+      x, y: int
+      s: string
+      seq: seq[string]
+    TRecSeq = seq[TRec]
+
+  proc test() =
+    var s, b: seq[string]
+    s = @[]
+    add(s, "Hi")
+    add(s, "there, ")
+    add(s, "what's your name?")
+
+    b = s # deep copying here!
+    b[0][1] = 'a'
+
+    for i in 0 .. len(s)-1:
+      write(stdout, s[i])
+    for i in 0 .. len(b)-1:
+      write(stdout, b[i])
+
+  when nestedFixed:
+    proc nested() =
+      var
+        s: seq[seq[string]]
+      for i in 0..10_000: # test if the garbage collector
+        # now works with sequences
+        s = @[
+          @["A", "B", "C", "D"],
+          @["E", "F", "G", "H"],
+          @["I", "J", "K", "L"],
+          @["M", "N", "O", "P"]]
+
+  test()
+  when nestedFixed:
+    nested()
+  echo ""
+
+
+
+import os
+block tseqcon2:
+  proc rec_dir(dir: string): seq[string] =
+    result = @[]
+    for kind, path in walk_dir(dir):
+      if kind == pcDir:
+        add(result, rec_dir(path))
+      else:
+        add(result, path)
+
+
+
+block tseqtuple:
+  type
+    TMsg = tuple[
+      file: string,
+      line: int,
+      msg: string,
+      err: bool]
+
+  var s: seq[TMsg] = @[]
+
+  s.add(("fA", 13, "msg1", false))
+  s.add(("fB", 14, "msg2", true))
+  s.add(("fC", 15, "msg3", false))
+
+  for file, line, msg, err in items(s):
+    stdout.write(file)
+    stdout.write($line)
+    stdout.write(msg)
+    stdout.write($err)
+  echo ""
+
+
+import sequtils, marshal
+block tsequtils:
+  proc testFindWhere(item : int) : bool =
+    if item != 1: return true
+
+  var seq1: seq[int] = @[]
+
+  seq1.add(1)
+  seq1.add(3)
+  seq1.add(5)
+  seq1.add(7)
+
+  var seq2: seq[int] = @[2, 4, 6]
+  var final = zip(seq1, seq2)
+
+  echo "Zip: ", $$(final)
+
+  #Test findWhere as a iterator
+
+  for itms in filter(seq1, testFindWhere):
+    echo "Filter Iterator: ", $$(itms)
+
+
+  #Test findWhere as a proc
+
+  var fullseq: seq[int] = filter(seq1, testFindWhere)
+
+  echo "Filter: ", $$(fullseq)
+
+  #Test findIt as a template
+
+  var finditval: seq[int] = filterIt(seq1, it!=5)
+
+  echo "FilterIt: ", $$(finditval)
+
+  var concatseq = concat(seq1,seq2)
+  echo "Concat: ", $$(concatseq)
+
+  var seq3 = @[1,2,3,4,5,5,5,7]
+  var dedupseq = deduplicate(seq3)
+  echo "Deduplicate: ", $$(dedupseq)
+  # bug #4973
+  type
+    SomeObj = object
+    OtherObj = object
+      field: SomeObj
+
+  let aSeq = @[OtherObj(field: SomeObj())]
+  let someObjSeq = aSeq.mapIt(it.field)
+  echo someObjSeq
+
+  block minmax:
+    doAssert minmax(@[0]) == (0, 0)
+    doAssert minmax(@[0, 1]) == (0, 1)
+    doAssert minmax(@[1, 0]) == (0, 1)
+    doAssert minmax(@[8,2,1,7,3,9,4,0,5]) == (0, 9)
+    echo "Minmax: ", $(minmax(concat(seq1, seq2)))
+
+
+when not defined(nimseqsv2):
+  block tshallowseq:
+    proc xxx() =
+      var x: seq[int] = @[1, 2, 3]
+      var y: seq[int]
+      system.shallowCopy(y, x)
+      y[1] = 42
+      doAssert y == @[1, 42, 3]
+      doAssert x == @[1, 42, 3]
+    xxx()
+
+
+  block tshallowemptyseq:
+    proc test() =
+      var nilSeq: seq[int] = @[]
+      var emptySeq: seq[int] = newSeq[int]()
+      block:
+        var t = @[1,2,3]
+        when defined(gcRefc):
+          shallow(nilSeq)
+        t = nilSeq
+        doAssert t == @[]
+      block:
+        var t = @[1,2,3]
+        when defined(gcRefc):
+          shallow(emptySeq)
+        t = emptySeq
+        doAssert t == @[]
+      block:
+        var t = @[1,2,3]
+        shallowCopy(t, nilSeq)
+        doAssert t == @[]
+      block:
+        var t = @[1,2,3]
+        shallowCopy(t, emptySeq)
+        doAssert t == @[]
+    test()
+
+
+import strutils
+block ttoseq:
+  for x in toSeq(countup(2, 6)):
+    stdout.write(x)
+  for x in items(toSeq(countup(2, 6))):
+    stdout.write(x)
+  var y: typeof("a b c".split)
+  y = "xzy"
+  stdout.write("\n")
+
+block tseqmapitchain:
+  doAssert @[101, 102] == [1, 2].mapIt(func (x: int): int = it + x).mapIt(it(100))
+
+
+for i in 0..100:
+  # fix #14655
+  var test = newSeqOfCap[uint32](1)
+  test.setLen(1)
+  doAssert test[0] == 0, $(test[0], i)
+
+
+# bug #22560
+doAssert len(newSeqOfCap[int](42)) == 0
+
+block: # bug #17197
+  type Matrix = seq[seq[int]]
+
+  proc needlemanWunsch(sequence1: string, sequence2: string, gap_penal: int8, match: int8, indel_penal: int8): bool =
+    let seq2_len = sequence2.len
+
+    var grid: Matrix
+    for i in sequence1:
+      grid.add(newSeqOfCap[seq[int]](seq2_len))
+    result = true
+
+  doAssert needlemanWunsch("ABC", "DEFG", 1, 2, 3)
diff --git a/tests/collections/ttables.nim b/tests/collections/ttables.nim
new file mode 100644
index 000000000..95f9418a0
--- /dev/null
+++ b/tests/collections/ttables.nim
@@ -0,0 +1,457 @@
+discard """
+output: '''
+done tableadds
+And we get here
+1
+2
+3
+'''
+joinable: false
+targets: "c cpp js"
+"""
+
+# xxx wrap in a template to test in VM, see https://github.com/timotheecour/Nim/issues/534#issuecomment-769565033
+
+import hashes, sequtils, tables, algorithm
+
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+block tableDollar:
+  # other tests should use `sortedPairs` to be robust to future table/hash
+  # implementation changes
+  doAssert ${1: 'a', 2: 'b'}.toTable in ["{1: 'a', 2: 'b'}", "{2: 'b', 1: 'a'}"]
+
+# test should not be joined because it takes too long.
+block tableadds:
+  proc main =
+    var tab = newTable[string, string]()
+    for i in 0..1000:
+      tab["key"] = "value " & $i
+
+  main()
+  echo "done tableadds"
+
+
+block tcounttable:
+  # bug #2625
+  const s_len = 32
+  var substr_counts: CountTable[string] = initCountTable[string]()
+  var my_string = "Hello, this is sadly broken for strings over 64 characters. Note that it *does* appear to work for short strings."
+  for i in 0..(my_string.len - s_len):
+    let s = my_string[i..i+s_len-1]
+    substr_counts[s] = 1
+    # substr_counts[s] = substr_counts[s] + 1  # Also breaks, + 2 as well, etc.
+    # substr_counts.inc(s)  # This works
+    #echo "Iteration ", i
+
+  echo "And we get here"
+
+
+block thashes:
+  # Test with int
+  block:
+    var t = initTable[int,int]()
+    t[0] = 42
+    t[1] = t[0] + 1
+    doAssert(t[0] == 42)
+    doAssert(t[1] == 43)
+    let t2 = {1: 1, 2: 2}.toTable
+    doAssert(t2[2] == 2)
+
+  # Test with char
+  block:
+    var t = initTable[char,int]()
+    t['0'] = 42
+    t['1'] = t['0'] + 1
+    doAssert(t['0'] == 42)
+    doAssert(t['1'] == 43)
+    let t2 = {'1': 1, '2': 2}.toTable
+    doAssert(t2['2'] == 2)
+
+  # Test with enum
+  block:
+    type
+      E = enum eA, eB, eC
+    var t = initTable[E,int]()
+    t[eA] = 42
+    t[eB] = t[eA] + 1
+    doAssert(t[eA] == 42)
+    doAssert(t[eB] == 43)
+    let t2 = {eA: 1, eB: 2}.toTable
+    doAssert(t2[eB] == 2)
+
+  # Test with range
+  block:
+    type
+      R = range[0..9]
+    var t = initTable[R,int]() # causes warning, why?
+    t[1] = 42 # causes warning, why?
+    t[2] = t[1] + 1
+    doAssert(t[1] == 42)
+    doAssert(t[2] == 43)
+    let t2 = {1.R: 1, 2.R: 2}.toTable
+    doAssert(t2[2.R] == 2)
+
+  # Test which combines the generics for tuples + ordinals
+  block:
+    type
+      E = enum eA, eB, eC
+    var t = initTable[(string, E, int, char), int]()
+    t[("a", eA, 0, '0')] = 42
+    t[("b", eB, 1, '1')] = t[("a", eA, 0, '0')] + 1
+    doAssert(t[("a", eA, 0, '0')] == 42)
+    doAssert(t[("b", eB, 1, '1')] == 43)
+    let t2 = {("a", eA, 0, '0'): 1, ("b", eB, 1, '1'): 2}.toTable
+    doAssert(t2[("b", eB, 1, '1')] == 2)
+
+  # Test to check if overloading is possible
+  # Unfortunately, this does not seem to work for int
+  # The same test with a custom hash(s: string) does
+  # work though.
+  block:
+    proc hash(x: int): Hash {.inline.} =
+      echo "overloaded hash"
+      result = x
+    var t = initTable[int, int]()
+    t[0] = 0
+
+  # Check hashability of all integer types (issue #5429)
+  block:
+    let intTables = (
+      newTable[int, string](),
+      newTable[int8, string](),
+      newTable[int16, string](),
+      newTable[int32, string](),
+      newTable[int64, string](),
+      newTable[uint, string](),
+      newTable[uint8, string](),
+      newTable[uint16, string](),
+      newTable[uint32, string](),
+      newTable[uint64, string](),
+    )
+  echo "1"
+
+
+block tindexby:
+  doAssert indexBy(newSeq[int](), proc(x: int):int = x) == initTable[int, int](), "empty int table"
+
+  var tbl1 = initTable[int, int]()
+  tbl1[1] = 1
+  tbl1[2] = 2
+  doAssert indexBy(@[1,2], proc(x: int):int = x) == tbl1, "int table"
+
+  type
+    TElem = object
+      foo: int
+      bar: string
+
+  let
+    elem1 = TElem(foo: 1, bar: "bar")
+    elem2 = TElem(foo: 2, bar: "baz")
+
+  var tbl2 = initTable[string, TElem]()
+  tbl2["bar"] = elem1
+  tbl2["baz"] = elem2
+  doAssert indexBy(@[elem1,elem2], proc(x: TElem): string = x.bar) == tbl2, "element table"
+
+
+block tableconstr:
+  # Test if the new table constructor syntax works:
+
+  template ignoreExpr(e) =
+    discard
+
+  # test first class '..' syntactical citizen:
+  ignoreExpr x <> 2..4
+  # test table constructor:
+  ignoreExpr({:})
+  ignoreExpr({2: 3, "key": "value"})
+
+  # NEW:
+  doAssert 56 in 50..100
+
+  doAssert 56 in 0..60
+
+
+block ttables2:
+  proc TestHashIntInt() =
+    var tab = initTable[int,int]()
+    let n = 10
+    for i in 1..n:
+      tab[i] = i
+    for i in 1..n:
+      var x = tab[i]
+      if x != i : echo "not found ", i
+
+  TestHashIntInt()
+
+  # bug #2107
+
+  var delTab = initTable[int,int](4)
+
+  for i in 1..4:
+    delTab[i] = i
+    delTab.del(i)
+  delTab[5] = 5
+
+
+  echo "2"
+
+block tablesref:
+  const
+    data = {
+      "34": 123456, "12": 789,
+      "90": 343, "0": 34404,
+      "1": 344004, "2": 344774,
+      "3": 342244, "4": 3412344,
+      "5": 341232144, "6": 34214544,
+      "7": 3434544, "8": 344544,
+      "9": 34435644, "---00": 346677844,
+      "10": 34484, "11": 34474, "19": 34464,
+      "20": 34454, "30": 34141244, "40": 344114,
+      "50": 344490, "60": 344491, "70": 344492,
+      "80": 344497}
+
+    sorteddata = {
+      "---00": 346677844,
+      "0": 34404,
+      "1": 344004,
+      "10": 34484,
+      "11": 34474,
+      "12": 789,
+      "19": 34464,
+      "2": 344774, "20": 34454,
+      "3": 342244, "30": 34141244,
+      "34": 123456,
+      "4": 3412344, "40": 344114,
+      "5": 341232144, "50": 344490,
+      "6": 34214544, "60": 344491,
+      "7": 3434544, "70": 344492,
+      "8": 344544, "80": 344497,
+      "9": 34435644,
+      "90": 343}
+
+  block tableTest1:
+    var t = newTable[tuple[x, y: int], string]()
+    t[(0,0)] = "00"
+    t[(1,0)] = "10"
+    t[(0,1)] = "01"
+    t[(1,1)] = "11"
+    for x in 0..1:
+      for y in 0..1:
+        doAssert t[(x,y)] == $x & $y
+    doAssert t.sortedPairs ==
+      @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")]
+
+  block tableTest2:
+    var t = newTable[string, float]()
+    t["test"] = 1.2345
+    t["111"] = 1.000043
+    t["123"] = 1.23
+    t.del("111")
+
+    t["012"] = 67.9
+    t["123"] = 1.5 # test overwriting
+
+    doAssert t["123"] == 1.5
+    try:
+      echo t["111"] # deleted
+    except KeyError:
+      discard
+    doAssert(not hasKey(t, "111"))
+    doAssert "111" notin t
+
+    for key, val in items(data): t[key] = val.toFloat
+    for key, val in items(data): doAssert t[key] == val.toFloat
+
+
+  block orderedTableTest1:
+    var t = newOrderedTable[string, int](2)
+    for key, val in items(data): t[key] = val
+    for key, val in items(data): doAssert t[key] == val
+    var i = 0
+    # `pairs` needs to yield in insertion order:
+    for key, val in pairs(t):
+      doAssert key == data[i][0]
+      doAssert val == data[i][1]
+      inc(i)
+
+    for key, val in mpairs(t): val = 99
+    for val in mvalues(t): doAssert val == 99
+
+  block countTableTest1:
+    var s = data.toTable
+    var t = newCountTable[string]()
+    var r = newCountTable[string]()
+    for x in [t, r]:
+      for k in s.keys:
+        x.inc(k)
+        doAssert x[k] == 1
+      x.inc("90", 3)
+      x.inc("12", 2)
+      x.inc("34", 1)
+    doAssert t.largest()[0] == "90"
+
+    t.sort()
+    r.sort(SortOrder.Ascending)
+    var ps1 = toSeq t.pairs
+    var ps2 = toSeq r.pairs
+    ps2.reverse()
+    for ps in [ps1, ps2]:
+      var i = 0
+      for (k, v) in ps:
+        case i
+        of 0: doAssert k == "90" and v == 4
+        of 1: doAssert k == "12" and v == 3
+        of 2: doAssert k == "34" and v == 2
+        else: break
+        inc i
+
+  block smallestLargestNamedFieldsTest: # bug #14918
+    const a = [7, 8, 8]
+
+    proc testNamedFields(t: CountTable | CountTableRef) =
+      doAssert t.smallest.key == 7
+      doAssert t.smallest.val == 1
+      doAssert t.largest.key == 8
+      doAssert t.largest.val == 2
+
+    let t1 = toCountTable(a)
+    testNamedFields(t1)
+    let t2 = newCountTable(a)
+    testNamedFields(t2)
+
+  block SyntaxTest:
+    var x = newTable[int, string]({:})
+    discard x
+
+  block nilTest:
+    var i, j: TableRef[int, int] = nil
+    doAssert i == j
+    j = newTable[int, int]()
+    doAssert i != j
+    doAssert j != i
+    i = newTable[int, int]()
+    doAssert i == j
+
+  proc orderedTableSortTest() =
+    var t = newOrderedTable[string, int](2)
+    for key, val in items(data): t[key] = val
+    for key, val in items(data): doAssert t[key] == val
+    proc cmper(x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key)
+    t.sort(cmper)
+    var i = 0
+    # `pairs` needs to yield in sorted order:
+    for key, val in pairs(t):
+      doAssert key == sorteddata[i][0]
+      doAssert val == sorteddata[i][1]
+      inc(i)
+    t.sort(cmper, order=SortOrder.Descending)
+    i = 0
+    for key, val in pairs(t):
+      doAssert key == sorteddata[high(data)-i][0]
+      doAssert val == sorteddata[high(data)-i][1]
+      inc(i)
+
+    # check that lookup still works:
+    for key, val in pairs(t):
+      doAssert val == t[key]
+    # check that insert still works:
+    t["newKeyHere"] = 80
+
+  block anonZipTest:
+    let keys = @['a','b','c']
+    let values = @[1, 2, 3]
+    doAssert zip(keys, values).toTable.sortedPairs == @[('a', 1), ('b', 2), ('c', 3)]
+
+  block clearTableTest:
+    var t = newTable[string, float]()
+    t["test"] = 1.2345
+    t["111"] = 1.000043
+    t["123"] = 1.23
+    doAssert t.len() != 0
+    t.clear()
+    doAssert t.len() == 0
+
+  block clearOrderedTableTest:
+    var t = newOrderedTable[string, int](2)
+    for key, val in items(data): t[key] = val
+    doAssert t.len() != 0
+    t.clear()
+    doAssert t.len() == 0
+
+  block clearCountTableTest:
+    var t = newCountTable[string]()
+    t.inc("90", 3)
+    t.inc("12", 2)
+    t.inc("34", 1)
+    doAssert t.len() != 0
+    t.clear()
+    doAssert t.len() == 0
+
+  orderedTableSortTest()
+  echo "3"
+
+
+block: # https://github.com/nim-lang/Nim/issues/13496
+  template testDel(body) =
+    block:
+      body
+      when t is CountTable|CountTableRef:
+        t.inc(15, 1)
+        t.inc(19, 2)
+        t.inc(17, 3)
+        t.inc(150, 4)
+        t.del(150)
+      else:
+        t[15] = 1
+        t[19] = 2
+        t[17] = 3
+        t[150] = 4
+        t.del(150)
+      doAssert t.len == 3
+      doAssert sortedItems(t.values) == @[1, 2, 3]
+      doAssert sortedItems(t.keys) == @[15, 17, 19]
+      doAssert sortedPairs(t) == @[(15, 1), (17, 3), (19, 2)]
+      var s = newSeq[int]()
+      for v in t.values: s.add(v)
+      doAssert s.len == 3
+      doAssert sortedItems(s) == @[1, 2, 3]
+      when t is OrderedTable|OrderedTableRef:
+        doAssert toSeq(t.keys) == @[15, 19, 17]
+        doAssert toSeq(t.values) == @[1,2,3]
+        doAssert toSeq(t.pairs) == @[(15, 1), (19, 2), (17, 3)]
+
+  testDel(): (var t: Table[int, int])
+  testDel(): (let t = newTable[int, int]())
+  testDel(): (var t: OrderedTable[int, int])
+  testDel(): (let t = newOrderedTable[int, int]())
+  testDel(): (var t: CountTable[int])
+  testDel(): (let t = newCountTable[int]())
+
+
+block testNonPowerOf2:
+  var a = initTable[int, int](7)
+  a[1] = 10
+  doAssert a[1] == 10
+
+  var b = initTable[int, int](9)
+  b[1] = 10
+  doAssert b[1] == 10
+
+block emptyOrdered:
+  var t1: OrderedTable[int, string]
+  var t2: OrderedTable[int, string]
+  doAssert t1 == t2
+
+block: # Table[ref, int]
+  type A = ref object
+    x: int
+  var t: OrderedTable[A, int]
+  let a1 = A(x: 3)
+  let a2 = A(x: 3)
+  t[a1] = 10
+  t[a2] = 11
+  doAssert t[a1] == 10
+  doAssert t[a2] == 11
diff --git a/tests/collections/ttablesthreads.nim b/tests/collections/ttablesthreads.nim
new file mode 100644
index 000000000..2a4e1bf42
--- /dev/null
+++ b/tests/collections/ttablesthreads.nim
@@ -0,0 +1,276 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  output: '''true'''
+"""
+
+import hashes, tables, sharedtables, algorithm, sequtils
+
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+  sorteddata = {
+    "---00": 346677844,
+    "0": 34404,
+    "1": 344004,
+    "10": 34484,
+    "11": 34474,
+    "12": 789,
+    "19": 34464,
+    "2": 344774, "20": 34454,
+    "3": 342244, "30": 34141244,
+    "34": 123456,
+    "4": 3412344, "40": 344114,
+    "5": 341232144, "50": 344490,
+    "6": 34214544, "60": 344491,
+    "7": 3434544, "70": 344492,
+    "8": 344544, "80": 344497,
+    "9": 34435644,
+    "90": 343}
+
+block tableTest1:
+  var t = initTable[tuple[x, y: int], string]()
+  t[(0,0)] = "00"
+  t[(1,0)] = "10"
+  t[(0,1)] = "01"
+  t[(1,1)] = "11"
+  for x in 0..1:
+    for y in 0..1:
+      doAssert t[(x,y)] == $x & $y
+  doAssert t.sortedPairs == @[((x: 0, y: 0), "00"), ((x: 0, y: 1), "01"), ((x: 1, y: 0), "10"), ((x: 1, y: 1), "11")]
+
+block tableTest2:
+  var t = initTable[string, float]()
+  t["test"] = 1.2345
+  t["111"] = 1.000043
+  t["123"] = 1.23
+  t.del("111")
+
+  t["012"] = 67.9
+  t["123"] = 1.5 # test overwriting
+
+  doAssert t["123"] == 1.5
+  try:
+    echo t["111"] # deleted
+  except KeyError:
+    discard
+  doAssert(not hasKey(t, "111"))
+
+  doAssert "123" in t
+  doAssert("111" notin t)
+
+  for key, val in items(data): t[key] = val.toFloat
+  for key, val in items(data): doAssert t[key] == val.toFloat
+
+  doAssert(not t.hasKeyOrPut("456", 4.0))     # test absent key
+  doAssert t.hasKeyOrPut("012", 3.0)          # test present key
+  var x = t.mgetOrPut("111", 1.5)           # test absent key
+  x = x * 2
+  doAssert x == 3.0
+  x = t.mgetOrPut("test", 1.5)              # test present key
+  x = x * 2
+  doAssert x == 2 * 1.2345
+
+block orderedTableTest1:
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): doAssert t[key] == val
+  var i = 0
+  # `pairs` needs to yield in insertion order:
+  for key, val in pairs(t):
+    doAssert key == data[i][0]
+    doAssert val == data[i][1]
+    inc(i)
+
+  for key, val in mpairs(t): val = 99
+  for val in mvalues(t): doAssert val == 99
+
+block orderedTableTest2:
+  var
+    s = initOrderedTable[string, int]()
+    t = initOrderedTable[string, int]()
+  doAssert s == t
+  for key, val in items(data): t[key] = val
+  doAssert s != t
+  for key, val in items(sorteddata): s[key] = val
+  doAssert s != t
+  t.clear()
+  doAssert s != t
+  for key, val in items(sorteddata): t[key] = val
+  doAssert s == t
+
+block countTableTest1:
+  var s = data.toTable
+  var t = initCountTable[string]()
+
+  for k in s.keys: t.inc(k)
+  for k in t.keys: doAssert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  doAssert t.largest()[0] == "90"
+
+  t.sort()
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: doAssert k == "90" and v == 4
+    of 1: doAssert k == "12" and v == 3
+    of 2: doAssert k == "34" and v == 2
+    else: break
+    inc i
+
+block countTableTest2:
+  var
+    s = initCountTable[int]()
+    t = initCountTable[int]()
+  doAssert s == t
+  s.inc(1)
+  doAssert s != t
+  t.inc(2)
+  doAssert s != t
+  t.inc(1)
+  doAssert s != t
+  s.inc(2)
+  doAssert s == t
+  s.inc(1)
+  doAssert s != t
+  t.inc(1)
+  doAssert s == t
+
+block mpairsTableTest1:
+  var t = initTable[string, int]()
+  t["a"] = 1
+  t["b"] = 2
+  t["c"] = 3
+  t["d"] = 4
+  for k, v in t.mpairs:
+    if k == "a" or k == "c":
+      v = 9
+
+  for k, v in t.pairs:
+    if k == "a" or k == "c":
+      doAssert v == 9
+    else:
+      doAssert v != 1 and v != 3
+
+block SyntaxTest:
+  var x = toTable[int, string]({:})
+
+block zeroHashKeysTest:
+  proc doZeroHashValueTest[T, K, V](t: T, nullHashKey: K, value: V) =
+    let initialLen = t.len
+    var testTable = t
+    testTable[nullHashKey] = value
+    doAssert testTable[nullHashKey] == value
+    doAssert testTable.len == initialLen + 1
+    testTable.del(nullHashKey)
+    doAssert testTable.len == initialLen
+
+  # with empty table
+  doZeroHashValueTest(toTable[int,int]({:}), 0, 42)
+  doZeroHashValueTest(toTable[string,int]({:}), "", 23)
+  doZeroHashValueTest(toOrderedTable[int,int]({:}), 0, 42)
+  doZeroHashValueTest(toOrderedTable[string,int]({:}), "", 23)
+
+  # with non-empty table
+  doZeroHashValueTest(toTable[int,int]({1:2}), 0, 42)
+  doZeroHashValueTest(toTable[string,string]({"foo": "bar"}), "", "zero")
+  doZeroHashValueTest(toOrderedTable[int,int]({3:4}), 0, 42)
+  doZeroHashValueTest(toOrderedTable[string,string]({"egg": "sausage"}),
+      "", "spam")
+
+block clearTableTest:
+  var t = data.toTable
+  doAssert t.len() != 0
+  t.clear()
+  doAssert t.len() == 0
+
+block clearOrderedTableTest:
+  var t = data.toOrderedTable
+  doAssert t.len() != 0
+  t.clear()
+  doAssert t.len() == 0
+
+block clearCountTableTest:
+  var t = initCountTable[string]()
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  doAssert t.len() != 0
+  t.clear()
+  doAssert t.len() == 0
+
+block withKeyTest:
+  var t: SharedTable[int, int]
+  t.init()
+  t.withKey(1) do (k: int, v: var int, pairExists: var bool):
+    doAssert(v == 0)
+    pairExists = true
+    v = 42
+  doAssert(t.mget(1) == 42)
+  t.withKey(1) do (k: int, v: var int, pairExists: var bool):
+    doAssert(v == 42)
+    pairExists = false
+  try:
+    discard t.mget(1)
+    doAssert(false, "KeyError expected")
+  except KeyError:
+    discard
+  t.withKey(2) do (k: int, v: var int, pairExists: var bool):
+    pairExists = false
+  try:
+    discard t.mget(2)
+    doAssert(false, "KeyError expected")
+  except KeyError:
+    discard
+
+block takeTest:
+  var t = initTable[string, int]()
+  t["key"] = 123
+
+  var val = 0
+  doAssert(t.take("key", val))
+  doAssert(val == 123)
+
+  val = -1
+  doAssert(not t.take("key", val))
+  doAssert(val == -1)
+
+  doAssert(not t.take("otherkey", val))
+  doAssert(val == -1)
+
+proc orderedTableSortTest() =
+  var t = initOrderedTable[string, int](2)
+  for key, val in items(data): t[key] = val
+  for key, val in items(data): doAssert t[key] == val
+  t.sort(proc (x, y: tuple[key: string, val: int]): int = cmp(x.key, y.key))
+  var i = 0
+  # `pairs` needs to yield in sorted order:
+  for key, val in pairs(t):
+    doAssert key == sorteddata[i][0]
+    doAssert val == sorteddata[i][1]
+    inc(i)
+
+  # check that lookup still works:
+  for key, val in pairs(t):
+    doAssert val == t[key]
+  # check that insert still works:
+  t["newKeyHere"] = 80
+
+
+orderedTableSortTest()
+echo "true"
+
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/compiler/nim.cfg b/tests/compiler/nim.cfg
new file mode 100644
index 000000000..6f49473aa
--- /dev/null
+++ b/tests/compiler/nim.cfg
@@ -0,0 +1,7 @@
+# note: consider moving tests/compilerapi/ to tests/compiler/ since
+# that's more predictable.
+
+# note: without this, tests may succeed locally but fail on CI (it can succeed
+# locally even when compiling via `./bin/nim` because `$HOME/.nimble` is being
+# used).
+--path:"../../" # so we can `import compiler/foo` in this dir
diff --git a/tests/compiler/samplelib.nim b/tests/compiler/samplelib.nim
new file mode 100644
index 000000000..c70971722
--- /dev/null
+++ b/tests/compiler/samplelib.nim
@@ -0,0 +1,2 @@
+# Sample library used by tcmdlineclib.nim
+proc test(): int {.cdecl, exportc, dynlib.} = 123
diff --git a/tests/compiler/t12684.nim b/tests/compiler/t12684.nim
new file mode 100644
index 000000000..a5f33d2c9
--- /dev/null
+++ b/tests/compiler/t12684.nim
@@ -0,0 +1,7 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  errormsg: "undeclared identifier: 'Undeclared'"
+"""
+
+var x: Undeclared
+import compiler/nimeval
diff --git a/tests/compiler/tasciitables.nim b/tests/compiler/tasciitables.nim
new file mode 100644
index 000000000..2f3b7bf2f
--- /dev/null
+++ b/tests/compiler/tasciitables.nim
@@ -0,0 +1,109 @@
+import stdtest/unittest_light
+import std/private/asciitables
+
+import strformat
+
+proc alignTableCustom(s: string, delim = '\t', sep = ","): string =
+  for cell in parseTableCells(s, delim):
+    result.add fmt"({cell.row},{cell.col}): "
+    for i in cell.text.len..<cell.width:
+      result.add " "
+    result.add cell.text
+    if cell.col < cell.ncols-1:
+      result.add sep
+    if cell.col == cell.ncols-1 and cell.row < cell.nrows - 1:
+      result.add '\n'
+
+proc testAlignTable() =
+  block: # test with variable width columns
+    var ret = ""
+    ret.add "12\t143\tbcdef\n"
+    ret.add "2\t14394852020\tbcdef\n"
+    ret.add "45342\t1\tbf\n"
+    ret.add "45342\t1\tbsadfasdfasfdasdff\n"
+    ret.add "453232323232342\t1\tbsadfasdfasfdasdff\n"
+    ret.add "45342\t1\tbf\n"
+    ret.add "45342\t1\tb afasf a ff\n"
+    ret.add "4\t1\tbf\n"
+
+    assertEquals alignTable(ret),
+      """
+12              143         bcdef             
+2               14394852020 bcdef             
+45342           1           bf                
+45342           1           bsadfasdfasfdasdff
+453232323232342 1           bsadfasdfasfdasdff
+45342           1           bf                
+45342           1           b afasf a ff      
+4               1           bf                
+"""
+
+    assertEquals alignTable(ret, fill = '.', sep = ","),
+      """
+12.............,143........,bcdef.............
+2..............,14394852020,bcdef.............
+45342..........,1..........,bf................
+45342..........,1..........,bsadfasdfasfdasdff
+453232323232342,1..........,bsadfasdfasfdasdff
+45342..........,1..........,bf................
+45342..........,1..........,b afasf a ff......
+4..............,1..........,bf................
+"""
+
+    assertEquals alignTableCustom(ret, sep = "  "),
+      """
+(0,0):              12  (0,1):         143  (0,2):              bcdef
+(1,0):               2  (1,1): 14394852020  (1,2):              bcdef
+(2,0):           45342  (2,1):           1  (2,2):                 bf
+(3,0):           45342  (3,1):           1  (3,2): bsadfasdfasfdasdff
+(4,0): 453232323232342  (4,1):           1  (4,2): bsadfasdfasfdasdff
+(5,0):           45342  (5,1):           1  (5,2):                 bf
+(6,0):           45342  (6,1):           1  (6,2):       b afasf a ff
+(7,0):               4  (7,1):           1  (7,2):                 bf
+"""
+
+  block: # test with 1 column
+    var ret = "12\nasdfa\nadf"
+    assertEquals alignTable(ret), """
+12   
+asdfa
+adf  """
+
+  block: # test with empty input
+    var ret = ""
+    assertEquals alignTable(ret), ""
+
+  block: # test with 1 row
+    var ret = "abc\tdef"
+    assertEquals alignTable(ret), """
+abc def"""
+
+  block: # test with 1 row ending in \t
+    var ret = "abc\tdef\t"
+    assertEquals alignTable(ret), """
+abc def """
+
+  block: # test with 1 row starting with \t
+    var ret = "\tabc\tdef\t"
+    assertEquals alignTable(ret), """
+ abc def """
+
+
+  block: # test with variable number of cols per row
+    var ret = """
+a1,a2,a3
+
+b1
+c1,c2
+,d1
+"""
+    assertEquals alignTableCustom(ret, delim = ',', sep = ","),
+      """
+(0,0): a1,(0,1): a2,(0,2): a3
+(1,0):   ,(1,1):   ,(1,2):   
+(2,0): b1,(2,1):   ,(2,2):   
+(3,0): c1,(3,1): c2,(3,2):   
+(4,0):   ,(4,1): d1,(4,2):   
+"""
+
+testAlignTable()
diff --git a/tests/compiler/tasm.nim b/tests/compiler/tasm.nim
new file mode 100644
index 000000000..9f60231e0
--- /dev/null
+++ b/tests/compiler/tasm.nim
@@ -0,0 +1,15 @@
+proc testAsm() =
+  let src = 41
+  var dst = 0
+
+  asm """
+    mov %1, %0\n\t
+    add $1, %0
+    : "=r" (`dst`)
+    : "r" (`src`)"""
+
+  doAssert dst == 42
+
+when defined(gcc) or defined(clang) and not defined(cpp):
+  {.passc: "-std=c99".}
+  testAsm()
\ No newline at end of file
diff --git a/tests/compiler/tbtrees.nim b/tests/compiler/tbtrees.nim
new file mode 100644
index 000000000..973c26420
--- /dev/null
+++ b/tests/compiler/tbtrees.nim
@@ -0,0 +1,84 @@
+discard """
+  output: '''
+www.amazon.com: 207.171.182.16
+www.apple.com: 17.112.152.32
+www.cnn.com: 64.236.16.20
+www.cs.princeton.edu: abc
+www.dell.com: 143.166.224.230
+www.ebay.com: 66.135.192.87
+www.espn.com: 199.181.135.201
+www.google.com: 216.239.41.99
+www.microsoft.com: 207.126.99.140
+www.nytimes.com: 199.239.136.200
+www.princeton.edu: 128.112.128.15
+www.simpsons.com: 209.052.165.60
+www.slashdot.org: 66.35.250.151
+www.weather.com: 63.111.66.11
+www.yahoo.com: 216.109.118.65
+www.yale.edu: 130.132.143.21
+'''
+"""
+
+import compiler/btrees
+
+import random, tables
+
+proc main =
+  var st = initBTree[string, string]()
+  st.add("www.cs.princeton.edu", "abc")
+  st.add("www.princeton.edu",    "128.112.128.15")
+  st.add("www.yale.edu",         "130.132.143.21")
+  st.add("www.simpsons.com",     "209.052.165.60")
+  st.add("www.apple.com",        "17.112.152.32")
+  st.add("www.amazon.com",       "207.171.182.16")
+  st.add("www.ebay.com",         "66.135.192.87")
+  st.add("www.cnn.com",          "64.236.16.20")
+  st.add("www.google.com",       "216.239.41.99")
+  st.add("www.nytimes.com",      "199.239.136.200")
+  st.add("www.microsoft.com",    "207.126.99.140")
+  st.add("www.dell.com",         "143.166.224.230")
+  st.add("www.slashdot.org",     "66.35.250.151")
+  st.add("www.espn.com",         "199.181.135.201")
+  st.add("www.weather.com",      "63.111.66.11")
+  st.add("www.yahoo.com",        "216.109.118.65")
+
+  doAssert st.getOrDefault("www.cs.princeton.edu") == "abc"
+  doAssert st.getOrDefault("www.harvardsucks.com") == ""
+
+  doAssert st.getOrDefault("www.simpsons.com") == "209.052.165.60"
+  doAssert st.getOrDefault("www.apple.com") == "17.112.152.32"
+  doAssert st.getOrDefault("www.ebay.com") == "66.135.192.87"
+  doAssert st.getOrDefault("www.dell.com") == "143.166.224.230"
+  doAssert(st.len == 16)
+
+  for k, v in st:
+    echo k, ": ", v
+
+  when false:
+    var b2 = initBTree[string, string]()
+    const iters = 10_000
+    for i in 1..iters:
+      b2.add($i, $(iters - i))
+    for i in 1..iters:
+      let x = b2.getOrDefault($i)
+      if x != $(iters - i):
+        echo "got ", x, ", but expected ", iters - i
+    echo b2.len
+
+  when true:
+    var b2 = initBTree[int, string]()
+    var t2 = initTable[int, string]()
+    const iters = 100
+    for i in 1..iters:
+      let x = rand(high(int))
+      if not t2.hasKey(x):
+        doAssert b2.getOrDefault(x).len == 0, " what, tree has this element " & $x
+        t2[x] = $x
+        b2.add(x, $x)
+
+    doAssert(b2.len == t2.len, "unique entries " & $b2.len)
+    for k, v in t2:
+      doAssert $k == v
+      doAssert b2.getOrDefault(k) == $k
+
+main()
diff --git a/tests/compiler/tcmdlineclib.nim b/tests/compiler/tcmdlineclib.nim
new file mode 100644
index 000000000..c06d6f103
--- /dev/null
+++ b/tests/compiler/tcmdlineclib.nim
@@ -0,0 +1,3 @@
+proc test(): int {.importc, cdecl.}
+
+doAssert test() == 123
diff --git a/tests/compiler/tcmdlineclib.nims b/tests/compiler/tcmdlineclib.nims
new file mode 100644
index 000000000..f7899d92e
--- /dev/null
+++ b/tests/compiler/tcmdlineclib.nims
@@ -0,0 +1,10 @@
+import os
+
+selfExec "c --app:lib " & (projectDir() / "samplelib.nim")
+switch("clibdir", projectDir())
+--clib:samplelib
+
+# Make test executable can load sample shared library.
+# `-rpath` option doesn't work and ignored on Windows.
+# But the dll file in same directory as executable file is loaded.
+switch("passL", "-Wl,-rpath," & projectDir())
diff --git a/tests/compiler/tcmdlinecpuamd64.nim b/tests/compiler/tcmdlinecpuamd64.nim
new file mode 100644
index 000000000..0265e3d94
--- /dev/null
+++ b/tests/compiler/tcmdlinecpuamd64.nim
@@ -0,0 +1,10 @@
+discard """
+  cmd: "nim $target $options --cpu:amd64 $file"
+  disabled: "32bit"
+"""
+
+import strutils
+
+static:
+  #cpu is set to "i386" in tcpuamd64.nim.cfg, but --cpu:amd64 in command line should override it.
+  doAssert cmpIgnoreCase(hostCPU, "amd64") == 0
diff --git a/tests/compiler/tcmdlinecpuamd64.nim.cfg b/tests/compiler/tcmdlinecpuamd64.nim.cfg
new file mode 100644
index 000000000..f2e5064ad
--- /dev/null
+++ b/tests/compiler/tcmdlinecpuamd64.nim.cfg
@@ -0,0 +1 @@
+cpu:i386
diff --git a/tests/compiler/tcmdlineoswin.nim b/tests/compiler/tcmdlineoswin.nim
new file mode 100644
index 000000000..602671e98
--- /dev/null
+++ b/tests/compiler/tcmdlineoswin.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim $target $options --os:windows $file"
+  disabled: "linux"
+  disabled: "bsd"
+  disabled: "osx"
+  disabled: "unix"
+  disabled: "posix"
+"""
+
+import strutils
+
+static:
+  #os is set to "linux" in toswin.nim.cfg, but --os:windows in command line should override it.
+  doAssert cmpIgnoreCase(hostOS, "windows") == 0
diff --git a/tests/compiler/tcmdlineoswin.nim.cfg b/tests/compiler/tcmdlineoswin.nim.cfg
new file mode 100644
index 000000000..037f87651
--- /dev/null
+++ b/tests/compiler/tcmdlineoswin.nim.cfg
@@ -0,0 +1 @@
+os:linux
diff --git a/tests/compiler/tcppCompileToNamespace.nim b/tests/compiler/tcppCompileToNamespace.nim
new file mode 100644
index 000000000..4e895c38b
--- /dev/null
+++ b/tests/compiler/tcppCompileToNamespace.nim
@@ -0,0 +1,11 @@
+discard """
+cmd: "nim cpp --cppCompileToNamespace:foo $options -r $file"
+"""
+
+# Theoretically nim could just ignore the flag cppCompileToNamespace
+# and this test would pass.  Setting ``ccodeCheck`` for a c++ target
+# doesn't work.
+
+import os
+
+echo "a" / "b"
diff --git a/tests/compiler/tdebugutils.nim b/tests/compiler/tdebugutils.nim
new file mode 100644
index 000000000..50b15cb78
--- /dev/null
+++ b/tests/compiler/tdebugutils.nim
@@ -0,0 +1,38 @@
+discard """
+  joinable: false
+  disabled: true
+"""
+
+#[
+This test illustrates some features of `debugutils` to debug the compiler.
+
+## example
+this shows how to enable compiler logging just for a section of user code,
+without generating tons of unrelated log messages for code you're not interested
+in debugging.
+
+```sh
+# enable some debugging code, e.g. the `when false:` block in `semExpr`
+nim c -o:bin/nim_temp --stacktrace -d:debug -d:nimDebugUtils compiler/nim
+bin/nim_temp c tests/compiler/tdebugutils.nim
+```
+
+(use --filenames:abs for abs files)
+
+## result
+("<", "tdebugutils.nim(16, 3)",  {.define(nimCompilerDebug).}, nil)
+(">", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, {}, nkLetSection)
+(">", "tdebugutils.nim(17, 15)", 2.5 * 3, {efAllowDestructor, efWantValue}, nkInfix)
+(">", "tdebugutils.nim(17, 11)", 2.5, {efAllowStmt, efDetermineType, efOperand}, nkFloatLit)
+("<", "tdebugutils.nim(17, 11)", 2.5, float64)
+(">", "tdebugutils.nim(17, 17)", 3, {efAllowStmt, efDetermineType, efOperand}, nkIntLit)
+("<", "tdebugutils.nim(17, 17)", 3, int literal(3))
+("<", "tdebugutils.nim(17, 15)", 2.5 * 3, float)
+("<", "tdebugutils.nim(17, 3)", let a = 2.5 * 3, nil)
+(">", "tdebugutils.nim(18, 3)",  {.undef(nimCompilerDebug).}, {}, nkPragma)
+]#
+
+proc main =
+  {.define(nimCompilerDebug).}
+  let a = 2.5 * 3
+  {.undef(nimCompilerDebug).}
diff --git a/tests/compiler/tgrammar.nim b/tests/compiler/tgrammar.nim
new file mode 100644
index 000000000..772d0f0cc
--- /dev/null
+++ b/tests/compiler/tgrammar.nim
@@ -0,0 +1,7 @@
+discard """
+  matrix: "-d:nimTestGrammar"
+"""
+
+import compiler/parser
+
+checkSameGrammar()
diff --git a/tests/compiler/tint128.nim b/tests/compiler/tint128.nim
new file mode 100644
index 000000000..a30b1b1cc
--- /dev/null
+++ b/tests/compiler/tint128.nim
@@ -0,0 +1,184 @@
+import compiler/int128
+
+let (a,b) = divMod(Ten,Ten)
+
+doAssert $One == "1"
+doAssert $Ten == "10"
+doAssert $Zero == "0"
+let c = parseDecimalInt128("12345678989876543210123456789")
+doAssert $c == "12345678989876543210123456789"
+
+var d : array[39, Int128]
+d[0] =  parseDecimalInt128("1")
+d[1] =  parseDecimalInt128("10")
+d[2] =  parseDecimalInt128("100")
+d[3] =  parseDecimalInt128("1000")
+d[4] =  parseDecimalInt128("10000")
+d[5] =  parseDecimalInt128("100000")
+d[6] =  parseDecimalInt128("1000000")
+d[7] =  parseDecimalInt128("10000000")
+d[8] =  parseDecimalInt128("100000000")
+d[9] =  parseDecimalInt128("1000000000")
+d[10] = parseDecimalInt128("10000000000")
+d[11] = parseDecimalInt128("100000000000")
+d[12] = parseDecimalInt128("1000000000000")
+d[13] = parseDecimalInt128("10000000000000")
+d[14] = parseDecimalInt128("100000000000000")
+d[15] = parseDecimalInt128("1000000000000000")
+d[16] = parseDecimalInt128("10000000000000000")
+d[17] = parseDecimalInt128("100000000000000000")
+d[18] = parseDecimalInt128("1000000000000000000")
+d[19] = parseDecimalInt128("10000000000000000000")
+d[20] = parseDecimalInt128("100000000000000000000")
+d[21] = parseDecimalInt128("1000000000000000000000")
+d[22] = parseDecimalInt128("10000000000000000000000")
+d[23] = parseDecimalInt128("100000000000000000000000")
+d[24] = parseDecimalInt128("1000000000000000000000000")
+d[25] = parseDecimalInt128("10000000000000000000000000")
+d[26] = parseDecimalInt128("100000000000000000000000000")
+d[27] = parseDecimalInt128("1000000000000000000000000000")
+d[28] = parseDecimalInt128("10000000000000000000000000000")
+d[29] = parseDecimalInt128("100000000000000000000000000000")
+d[30] = parseDecimalInt128("1000000000000000000000000000000")
+d[31] = parseDecimalInt128("10000000000000000000000000000000")
+d[32] = parseDecimalInt128("100000000000000000000000000000000")
+d[33] = parseDecimalInt128("1000000000000000000000000000000000")
+d[34] = parseDecimalInt128("10000000000000000000000000000000000")
+d[35] = parseDecimalInt128("100000000000000000000000000000000000")
+d[36] = parseDecimalInt128("1000000000000000000000000000000000000")
+d[37] = parseDecimalInt128("10000000000000000000000000000000000000")
+d[38] = parseDecimalInt128("100000000000000000000000000000000000000")
+
+for i in 0..<d.len:
+  for j in 0..<d.len:
+    doAssert(cmp(d[i], d[j]) == cmp(i,j))
+    if i + j < d.len:
+      doAssert d[i] * d[j] == d[i+j]
+    if i - j >= 0:
+      doAssert d[i] div d[j] == d[i-j]
+
+var sum: Int128
+
+for it in d:
+  sum += it
+
+doAssert $sum == "111111111111111111111111111111111111111"
+
+for it in d.mitems:
+  it = -it
+
+for i in 0..<d.len:
+  for j in 0..<d.len:
+    doAssert(cmp(d[i], d[j]) == -cmp(i,j))
+    if i + j < d.len:
+      doAssert d[i] * d[j] == -d[i+j]
+    if i - j >= 0:
+      doAssert d[i] div d[j] == -d[i-j]
+
+doAssert $high(Int128) == "170141183460469231731687303715884105727"
+doAssert $low(Int128) == "-170141183460469231731687303715884105728"
+
+var ma = 100'i64
+var mb = 13
+
+doAssert toInt128(ma) * toInt128(0) == toInt128(0)
+doAssert toInt128(-ma) * toInt128(0) == toInt128(0)
+
+# sign correctness
+doAssert divMod(toInt128( ma),toInt128( mb)) == (toInt128( ma div  mb), toInt128( ma mod  mb))
+doAssert divMod(toInt128(-ma),toInt128( mb)) == (toInt128(-ma div  mb), toInt128(-ma mod  mb))
+doAssert divMod(toInt128( ma),toInt128(-mb)) == (toInt128( ma div -mb), toInt128( ma mod -mb))
+doAssert divMod(toInt128(-ma),toInt128(-mb)) == (toInt128(-ma div -mb), toInt128(-ma mod -mb))
+
+doAssert divMod(toInt128( mb),toInt128( mb)) == (toInt128( mb div  mb), toInt128( mb mod  mb))
+doAssert divMod(toInt128(-mb),toInt128( mb)) == (toInt128(-mb div  mb), toInt128(-mb mod  mb))
+doAssert divMod(toInt128( mb),toInt128(-mb)) == (toInt128( mb div -mb), toInt128( mb mod -mb))
+doAssert divMod(toInt128(-mb),toInt128(-mb)) == (toInt128(-mb div -mb), toInt128(-mb mod -mb))
+
+doAssert divMod(toInt128( mb),toInt128( ma)) == (toInt128( mb div  ma), toInt128( mb mod  ma))
+doAssert divMod(toInt128(-mb),toInt128( ma)) == (toInt128(-mb div  ma), toInt128(-mb mod  ma))
+doAssert divMod(toInt128( mb),toInt128(-ma)) == (toInt128( mb div -ma), toInt128( mb mod -ma))
+doAssert divMod(toInt128(-mb),toInt128(-ma)) == (toInt128(-mb div -ma), toInt128(-mb mod -ma))
+
+let e = parseDecimalInt128("70997106675279150998592376708984375")
+
+let strArray = [
+  # toHex(e shr 0), toHex(e shr 1), toHex(e shr 2), toHex(e shr 3)
+  "000dac6d782d266a37300c32591eee37", "0006d636bc1693351b9806192c8f771b", "00036b1b5e0b499a8dcc030c9647bb8d", "0001b58daf05a4cd46e601864b23ddc6",
+  "0000dac6d782d266a37300c32591eee3", "00006d636bc1693351b9806192c8f771", "000036b1b5e0b499a8dcc030c9647bb8", "00001b58daf05a4cd46e601864b23ddc",
+  "00000dac6d782d266a37300c32591eee", "000006d636bc1693351b9806192c8f77", "0000036b1b5e0b499a8dcc030c9647bb", "000001b58daf05a4cd46e601864b23dd",
+  "000000dac6d782d266a37300c32591ee", "0000006d636bc1693351b9806192c8f7", "00000036b1b5e0b499a8dcc030c9647b", "0000001b58daf05a4cd46e601864b23d",
+  "0000000dac6d782d266a37300c32591e", "00000006d636bc1693351b9806192c8f", "000000036b1b5e0b499a8dcc030c9647", "00000001b58daf05a4cd46e601864b23",
+  "00000000dac6d782d266a37300c32591", "000000006d636bc1693351b9806192c8", "0000000036b1b5e0b499a8dcc030c964", "000000001b58daf05a4cd46e601864b2",
+  "000000000dac6d782d266a37300c3259", "0000000006d636bc1693351b9806192c", "00000000036b1b5e0b499a8dcc030c96", "0000000001b58daf05a4cd46e601864b",
+  "0000000000dac6d782d266a37300c325", "00000000006d636bc1693351b9806192", "000000000036b1b5e0b499a8dcc030c9", "00000000001b58daf05a4cd46e601864",
+  "00000000000dac6d782d266a37300c32", "000000000006d636bc1693351b980619", "0000000000036b1b5e0b499a8dcc030c", "000000000001b58daf05a4cd46e60186",
+  "000000000000dac6d782d266a37300c3", "0000000000006d636bc1693351b98061", "00000000000036b1b5e0b499a8dcc030", "0000000000001b58daf05a4cd46e6018",
+  "0000000000000dac6d782d266a37300c", "00000000000006d636bc1693351b9806", "000000000000036b1b5e0b499a8dcc03", "00000000000001b58daf05a4cd46e601",
+  "00000000000000dac6d782d266a37300", "000000000000006d636bc1693351b980", "0000000000000036b1b5e0b499a8dcc0", "000000000000001b58daf05a4cd46e60",
+  "000000000000000dac6d782d266a3730", "0000000000000006d636bc1693351b98", "00000000000000036b1b5e0b499a8dcc", "0000000000000001b58daf05a4cd46e6",
+  "0000000000000000dac6d782d266a373", "00000000000000006d636bc1693351b9", "000000000000000036b1b5e0b499a8dc", "00000000000000001b58daf05a4cd46e",
+  "00000000000000000dac6d782d266a37", "000000000000000006d636bc1693351b", "0000000000000000036b1b5e0b499a8d", "000000000000000001b58daf05a4cd46",
+  "000000000000000000dac6d782d266a3", "0000000000000000006d636bc1693351", "00000000000000000036b1b5e0b499a8", "0000000000000000001b58daf05a4cd4",
+  "0000000000000000000dac6d782d266a", "00000000000000000006d636bc169335", "000000000000000000036b1b5e0b499a", "00000000000000000001b58daf05a4cd",
+  "00000000000000000000dac6d782d266", "000000000000000000006d636bc16933", "0000000000000000000036b1b5e0b499", "000000000000000000001b58daf05a4c",
+  "000000000000000000000dac6d782d26", "0000000000000000000006d636bc1693", "00000000000000000000036b1b5e0b49", "0000000000000000000001b58daf05a4",
+  "0000000000000000000000dac6d782d2", "00000000000000000000006d636bc169", "000000000000000000000036b1b5e0b4", "00000000000000000000001b58daf05a",
+  "00000000000000000000000dac6d782d", "000000000000000000000006d636bc16", "0000000000000000000000036b1b5e0b", "000000000000000000000001b58daf05",
+  "000000000000000000000000dac6d782", "0000000000000000000000006d636bc1", "00000000000000000000000036b1b5e0", "0000000000000000000000001b58daf0",
+  "0000000000000000000000000dac6d78", "00000000000000000000000006d636bc", "000000000000000000000000036b1b5e", "00000000000000000000000001b58daf",
+  "00000000000000000000000000dac6d7", "000000000000000000000000006d636b", "0000000000000000000000000036b1b5", "000000000000000000000000001b58da",
+  "000000000000000000000000000dac6d", "0000000000000000000000000006d636", "00000000000000000000000000036b1b", "0000000000000000000000000001b58d",
+  "0000000000000000000000000000dac6", "00000000000000000000000000006d63", "000000000000000000000000000036b1", "00000000000000000000000000001b58",
+  "00000000000000000000000000000dac", "000000000000000000000000000006d6", "0000000000000000000000000000036b", "000000000000000000000000000001b5",
+  "000000000000000000000000000000da", "0000000000000000000000000000006d", "00000000000000000000000000000036", "0000000000000000000000000000001b",
+  "0000000000000000000000000000000d", "00000000000000000000000000000006", "00000000000000000000000000000003", "00000000000000000000000000000001",
+  "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000",
+  "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000",
+  "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000", "00000000000000000000000000000000",
+]
+
+for i in 0 ..< 128:
+  let str1 = toHex(e shr i)
+  let str2 = strArray[i]
+  doAssert str1 == str2
+
+let strArray2 = [
+  "000dac6d782d266a37300c32591eee37", "001b58daf05a4cd46e601864b23ddc6e", "0036b1b5e0b499a8dcc030c9647bb8dc", "006d636bc1693351b9806192c8f771b8",
+  "00dac6d782d266a37300c32591eee370", "01b58daf05a4cd46e601864b23ddc6e0", "036b1b5e0b499a8dcc030c9647bb8dc0", "06d636bc1693351b9806192c8f771b80",
+  "0dac6d782d266a37300c32591eee3700", "1b58daf05a4cd46e601864b23ddc6e00", "36b1b5e0b499a8dcc030c9647bb8dc00", "6d636bc1693351b9806192c8f771b800",
+  "dac6d782d266a37300c32591eee37000", "b58daf05a4cd46e601864b23ddc6e000", "6b1b5e0b499a8dcc030c9647bb8dc000", "d636bc1693351b9806192c8f771b8000",
+  "ac6d782d266a37300c32591eee370000", "58daf05a4cd46e601864b23ddc6e0000", "b1b5e0b499a8dcc030c9647bb8dc0000", "636bc1693351b9806192c8f771b80000",
+  "c6d782d266a37300c32591eee3700000", "8daf05a4cd46e601864b23ddc6e00000", "1b5e0b499a8dcc030c9647bb8dc00000", "36bc1693351b9806192c8f771b800000",
+  "6d782d266a37300c32591eee37000000", "daf05a4cd46e601864b23ddc6e000000", "b5e0b499a8dcc030c9647bb8dc000000", "6bc1693351b9806192c8f771b8000000",
+  "d782d266a37300c32591eee370000000", "af05a4cd46e601864b23ddc6e0000000", "5e0b499a8dcc030c9647bb8dc0000000", "bc1693351b9806192c8f771b80000000",
+  "782d266a37300c32591eee3700000000", "f05a4cd46e601864b23ddc6e00000000", "e0b499a8dcc030c9647bb8dc00000000", "c1693351b9806192c8f771b800000000",
+  "82d266a37300c32591eee37000000000", "05a4cd46e601864b23ddc6e000000000", "0b499a8dcc030c9647bb8dc000000000", "1693351b9806192c8f771b8000000000",
+  "2d266a37300c32591eee370000000000", "5a4cd46e601864b23ddc6e0000000000", "b499a8dcc030c9647bb8dc0000000000", "693351b9806192c8f771b80000000000",
+  "d266a37300c32591eee3700000000000", "a4cd46e601864b23ddc6e00000000000", "499a8dcc030c9647bb8dc00000000000", "93351b9806192c8f771b800000000000",
+  "266a37300c32591eee37000000000000", "4cd46e601864b23ddc6e000000000000", "99a8dcc030c9647bb8dc000000000000", "3351b9806192c8f771b8000000000000",
+  "66a37300c32591eee370000000000000", "cd46e601864b23ddc6e0000000000000", "9a8dcc030c9647bb8dc0000000000000", "351b9806192c8f771b80000000000000",
+  "6a37300c32591eee3700000000000000", "d46e601864b23ddc6e00000000000000", "a8dcc030c9647bb8dc00000000000000", "51b9806192c8f771b800000000000000",
+  "a37300c32591eee37000000000000000", "46e601864b23ddc6e000000000000000", "8dcc030c9647bb8dc000000000000000", "1b9806192c8f771b8000000000000000",
+  "37300c32591eee370000000000000000", "6e601864b23ddc6e0000000000000000", "dcc030c9647bb8dc0000000000000000", "b9806192c8f771b80000000000000000",
+  "7300c32591eee3700000000000000000", "e601864b23ddc6e00000000000000000", "cc030c9647bb8dc00000000000000000", "9806192c8f771b800000000000000000",
+  "300c32591eee37000000000000000000", "601864b23ddc6e000000000000000000", "c030c9647bb8dc000000000000000000", "806192c8f771b8000000000000000000",
+  "00c32591eee370000000000000000000", "01864b23ddc6e0000000000000000000", "030c9647bb8dc0000000000000000000", "06192c8f771b80000000000000000000",
+  "0c32591eee3700000000000000000000", "1864b23ddc6e00000000000000000000", "30c9647bb8dc00000000000000000000", "6192c8f771b800000000000000000000",
+  "c32591eee37000000000000000000000", "864b23ddc6e000000000000000000000", "0c9647bb8dc000000000000000000000", "192c8f771b8000000000000000000000",
+  "32591eee370000000000000000000000", "64b23ddc6e0000000000000000000000", "c9647bb8dc0000000000000000000000", "92c8f771b80000000000000000000000",
+  "2591eee3700000000000000000000000", "4b23ddc6e00000000000000000000000", "9647bb8dc00000000000000000000000", "2c8f771b800000000000000000000000",
+  "591eee37000000000000000000000000", "b23ddc6e000000000000000000000000", "647bb8dc000000000000000000000000", "c8f771b8000000000000000000000000",
+  "91eee370000000000000000000000000", "23ddc6e0000000000000000000000000", "47bb8dc0000000000000000000000000", "8f771b80000000000000000000000000",
+  "1eee3700000000000000000000000000", "3ddc6e00000000000000000000000000", "7bb8dc00000000000000000000000000", "f771b800000000000000000000000000",
+  "eee37000000000000000000000000000", "ddc6e000000000000000000000000000", "bb8dc000000000000000000000000000", "771b8000000000000000000000000000",
+  "ee370000000000000000000000000000", "dc6e0000000000000000000000000000", "b8dc0000000000000000000000000000", "71b80000000000000000000000000000",
+  "e3700000000000000000000000000000", "c6e00000000000000000000000000000", "8dc00000000000000000000000000000", "1b800000000000000000000000000000",
+  "37000000000000000000000000000000", "6e000000000000000000000000000000", "dc000000000000000000000000000000", "b8000000000000000000000000000000",
+  "70000000000000000000000000000000", "e0000000000000000000000000000000", "c0000000000000000000000000000000", "80000000000000000000000000000000",
+]
+
+for i in 0 ..< 128:
+  let str1 = toHex(e shl i)
+  let str2 = strArray2[i]
+  doAssert str1 == str2
diff --git a/tests/compiler/tnimblecmd.nim b/tests/compiler/tnimblecmd.nim
new file mode 100644
index 000000000..53bce4625
--- /dev/null
+++ b/tests/compiler/tnimblecmd.nim
@@ -0,0 +1,75 @@
+include compiler/[nimblecmd], sets
+
+proc v(s: string): Version = s.newVersion
+
+proc testVersionsComparison =
+  # #head is special in the sense that it's assumed to always be newest.
+  doAssert v"1.0" < v"#head"
+  doAssert v"1.0" < v"1.1"
+  doAssert v"1.0.1" < v"1.1"
+  doAssert v"1" < v"1.1"
+  doAssert v"#aaaqwe" < v"1.1" # We cannot assume that a branch is newer.
+  doAssert v"#a111" < v"#head"
+
+proc testAddPackageWithoutChecksum =
+  ## For backward compatibility it is not required all packages to have a
+  ## sha1 checksum at the end of the name of the Nimble cache directory.
+  ## This way a new compiler will be able to work with an older Nimble.
+
+  let conf = newConfigRef()
+  var rr: PackageInfo
+
+  addPackage conf, rr, "irc-#a111", unknownLineInfo
+  addPackage conf, rr, "irc-#head", unknownLineInfo
+  addPackage conf, rr, "irc-0.1.0", unknownLineInfo
+
+  addPackage conf, rr, "another-0.1", unknownLineInfo
+
+  addPackage conf, rr, "ab-0.1.3", unknownLineInfo
+  addPackage conf, rr, "ab-0.1", unknownLineInfo
+  addPackage conf, rr, "justone-1.0", unknownLineInfo
+
+  doAssert toSeq(rr.chosen).toHashSet ==
+    ["irc-#head", "another-0.1", "ab-0.1.3", "justone-1.0"].toHashSet
+
+proc testAddPackageWithChecksum =
+  let conf = newConfigRef()
+  var rr: PackageInfo
+
+  # in the case of packages with the same version, but different checksums for
+  # now the first one will be chosen
+
+  addPackage conf, rr, "irc-#a111-DBC1F902CB79946E990E38AF51F0BAD36ACFABD9",
+             unknownLineInfo
+  addPackage conf, rr, "irc-#head-042D4BE2B90ED0672E717D71850ABDB0A2D19CD1",
+             unknownLineInfo
+  addPackage conf, rr, "irc-#head-042D4BE2B90ED0672E717D71850ABDB0A2D19CD2",
+             unknownLineInfo
+  addPackage conf, rr, "irc-0.1.0-6EE6DE936B32E82C7DBE526DA3463574F6568FAF",
+             unknownLineInfo
+
+  addPackage conf, rr, "another-0.1", unknownLineInfo
+  addPackage conf, rr, "another-0.1-F07EE6040579F0590608A8FD34F5F2D91D859340",
+             unknownLineInfo
+
+  addPackage conf, rr, "ab-0.1.3-34BC3B72CE46CF5A496D1121CFEA7369385E9EA2",
+             unknownLineInfo
+  addPackage conf, rr, "ab-0.1.3-24BC3B72CE46CF5A496D1121CFEA7369385E9EA2",
+             unknownLineInfo
+  addPackage conf, rr, "ab-0.1-A3CFFABDC4759F7779D541F5E031AED17169390A",
+             unknownLineInfo
+
+  # lower case hex digits is also a valid sha1 checksum
+  addPackage conf, rr, "justone-1.0-f07ee6040579f0590608a8fd34f5f2d91d859340",
+             unknownLineInfo
+
+  doAssert toSeq(rr.chosen).toHashSet == [
+    "irc-#head-042D4BE2B90ED0672E717D71850ABDB0A2D19CD1",
+    "another-0.1",
+    "ab-0.1.3-34BC3B72CE46CF5A496D1121CFEA7369385E9EA2",
+    "justone-1.0-f07ee6040579f0590608a8fd34f5f2d91d859340"
+    ].toHashSet
+
+testVersionsComparison()
+testAddPackageWithoutChecksum()
+testAddPackageWithChecksum()
diff --git a/tests/compiler/tpathutils.nim b/tests/compiler/tpathutils.nim
new file mode 100644
index 000000000..47ff0f06a
--- /dev/null
+++ b/tests/compiler/tpathutils.nim
@@ -0,0 +1,18 @@
+import compiler/pathutils
+import os, strutils
+
+
+doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim"
+doAssert AbsoluteDir"/Users/me" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim"
+doAssert AbsoluteDir"/Users/me/" / RelativeFile"../z.nim" == AbsoluteFile"/Users/z.nim"
+doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim"
+doAssert $RelativeDir"foo/bar" == "foo/bar"
+doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar"
+doAssert RelativeFile"foo/bar".changeFileExt(".txt") == RelativeFile"foo/bar.txt"
+doAssert RelativeFile"foo/bar".addFileExt(".txt") == RelativeFile"foo/bar.txt"
+doAssert not RelativeDir"foo/bar".isEmpty
+doAssert RelativeDir"".isEmpty
+
+when defined(windows):
+  let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim")
+  doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim"
diff --git a/tests/compiler/tprefixmatches.nim b/tests/compiler/tprefixmatches.nim
new file mode 100644
index 000000000..6a3186729
--- /dev/null
+++ b/tests/compiler/tprefixmatches.nim
@@ -0,0 +1,32 @@
+import compiler/prefixmatches
+import macros
+
+macro check(val, body: untyped): untyped =
+  result = newStmtList()
+  expectKind body, nnkStmtList
+  for b in body:
+    expectKind b, nnkTupleConstr
+    expectLen b, 2
+    let p = b[0]
+    let s = b[1]
+    result.add quote do:
+      doAssert prefixMatch(`p`, `s`) == `val`
+
+check PrefixMatch.Prefix:
+  ("abc", "abc")
+  ("a", "abc")
+  ("xyz", "X_yzzzZe")
+
+check PrefixMatch.Substr:
+  ("b", "abc")
+  ("abc", "fooabcabc")
+  ("abC", "foo_AB_c")
+
+check PrefixMatch.Abbrev:
+  ("abc", "AxxxBxxxCxxx")
+  ("xyz", "X_yabcZe")
+
+check PrefixMatch.None:
+  ("foobar", "afkslfjd_as")
+  ("xyz", "X_yuuZuuZe")
+  ("ru", "remotes")
diff --git a/tests/compiler/tunittest_light.nim b/tests/compiler/tunittest_light.nim
new file mode 100644
index 000000000..2951cc664
--- /dev/null
+++ b/tests/compiler/tunittest_light.nim
@@ -0,0 +1,55 @@
+import stdtest/unittest_light
+
+proc testAssertEquals() =
+  assertEquals("foo", "foo")
+  doAssertRaises(AssertionDefect):
+    assertEquals("foo", "foo ")
+
+proc testMismatch() =
+  assertEquals(1+1, 2*1)
+
+  let a = """
+  some test with space at the end of lines    
+
+  can be hard to spot differences when diffing in a terminal   
+  without this helper function
+
+"""
+
+  let b = """
+  some test with space at the end of lines    
+
+  can be hard to spot differences when diffing in a terminal  
+  without this helper function
+
+"""
+
+  let output = mismatch(a, b)
+  let expected = """
+
+lhs:{  some test with space at the end of lines    \n
+\n
+  can be hard to spot differences when diffing in a terminal   \n
+  without this helper function\n
+\n
+}
+rhs:{  some test with space at the end of lines    \n
+\n
+  can be hard to spot differences when diffing in a terminal  \n
+  without this helper function\n
+\n
+}
+lhs.len: 144 rhs.len: 143
+first mismatch index: 110
+lhs[i]: {" "}
+rhs[i]: {"\n"}
+lhs[0..<i]:{  some test with space at the end of lines    \n
+\n
+  can be hard to spot differences when diffing in a terminal  }"""
+
+  if output != expected:
+    echo output
+    doAssert false
+
+testMismatch()
+testAssertEquals()
diff --git a/tests/compilerapi/exposed.nim b/tests/compilerapi/exposed.nim
new file mode 100644
index 000000000..25a858ec9
--- /dev/null
+++ b/tests/compilerapi/exposed.nim
@@ -0,0 +1,3 @@
+
+proc addFloats*(x, y, z: float): float =
+  discard "implementation overridden by tcompilerapi.nim"
diff --git a/tests/compilerapi/invalid.nim b/tests/compilerapi/invalid.nim
new file mode 100644
index 000000000..3c9364402
--- /dev/null
+++ b/tests/compilerapi/invalid.nim
@@ -0,0 +1 @@
+noSuchProc()
diff --git a/tests/compilerapi/myscript.nim b/tests/compilerapi/myscript.nim
new file mode 100644
index 000000000..c5d9fe22a
--- /dev/null
+++ b/tests/compilerapi/myscript.nim
@@ -0,0 +1,14 @@
+
+import exposed
+
+type NumberHolder = object
+  ival: int
+  fval: float
+
+echo "top level statements are executed!"
+echo NumberHolder(ival: 10, fval: 2.0)
+
+proc hostProgramRunsThis*(a, b: float): float =
+  result = addFloats(a, b, 1.0)
+
+let hostProgramWantsThis* = "my secret"
diff --git a/tests/compilerapi/tcompilerapi.nim b/tests/compilerapi/tcompilerapi.nim
new file mode 100644
index 000000000..2d6cfa0ca
--- /dev/null
+++ b/tests/compilerapi/tcompilerapi.nim
@@ -0,0 +1,98 @@
+discard """
+  output: '''top level statements are executed!
+(ival: 10, fval: 2.0)
+2.0
+my secret
+11
+12
+raising VMQuit
+'''
+  joinable: "false"
+"""
+
+## Example program that demonstrates how to use the
+## compiler as an API to embed into your own projects.
+
+import "../../compiler" / [ast, vmdef, vm, nimeval, llstream, lineinfos, options]
+import std / [os]
+
+proc initInterpreter(script: string): Interpreter =
+  let std = findNimStdLibCompileTime()
+  result = createInterpreter(script, [std, parentDir(currentSourcePath),
+    std / "pure", std / "core"])
+
+proc main() =
+  let i = initInterpreter("myscript.nim")
+  i.implementRoutine("nim", "exposed", "addFloats", proc (a: VmArgs) =
+    setResult(a, getFloat(a, 0) + getFloat(a, 1) + getFloat(a, 2))
+  )
+  i.evalScript()
+  let foreignProc = i.selectRoutine("hostProgramRunsThis")
+  if foreignProc == nil:
+    quit "script does not export a proc of the name: 'hostProgramRunsThis'"
+  let res = i.callRoutine(foreignProc, [newFloatNode(nkFloatLit, 0.9),
+                                        newFloatNode(nkFloatLit, 0.1)])
+  doAssert res.kind == nkFloatLit
+  echo res.floatVal
+
+  let foreignValue = i.selectUniqueSymbol("hostProgramWantsThis")
+  if foreignValue == nil:
+    quit "script does not export a global of the name: hostProgramWantsThis"
+  let val = i.getGlobalValue(foreignValue)
+  doAssert val.kind in {nkStrLit..nkTripleStrLit}
+  echo val.strVal
+  i.destroyInterpreter()
+
+main()
+
+block issue9180:
+  proc evalString(code: string, moduleName = "script.nim") =
+    let stream = llStreamOpen(code)
+    let std = findNimStdLibCompileTime()
+    var intr = createInterpreter(moduleName, [std, std / "pure", std / "core"])
+    intr.evalScript(stream)
+    destroyInterpreter(intr)
+    llStreamClose(stream)
+
+  evalString("echo 10+1")
+  evalString("echo 10+2")
+
+block error_hook:
+  type VMQuit = object of CatchableError
+
+  let i = initInterpreter("invalid.nim")
+  i.registerErrorHook proc(config: ConfigRef; info: TLineInfo; msg: string;
+                           severity: Severity) {.gcsafe.} =
+    if severity == Error and config.errorCounter >= config.errorMax:
+      echo "raising VMQuit"
+      raise newException(VMQuit, "Script error")
+
+  doAssertRaises(VMQuit):
+    i.evalScript()
+
+block resetmacrocache:
+  let std = findNimStdLibCompileTime()
+  let intr = createInterpreter("script.nim", [std, std / "pure", std / "core"])
+  proc evalString(intr: Interpreter; code: string) =
+    let stream = llStreamOpen(code)
+    intr.evalScript(stream)
+    llStreamClose(stream)
+  let code = """
+import std/[macrocache, macros]
+static:
+  let counter = CacheCounter"valTest"
+  inc counter
+  assert counter.value == 1
+
+  const mySeq = CacheSeq"addTest"
+  mySeq.add(newLit(5))
+  mySeq.add(newLit("hello ic"))
+  assert mySeq.len == 2
+
+  const mcTable = CacheTable"subTest"
+  mcTable["toAdd"] = newStmtList() #would crash if not empty
+  assert mcTable.len == 1
+"""
+  intr.evalString(code)
+  intr.evalString(code)
+  destroyInterpreter(intr)
\ No newline at end of file
diff --git a/tests/compiles/mstaticlib.nim b/tests/compiles/mstaticlib.nim
new file mode 100644
index 000000000..6ed593691
--- /dev/null
+++ b/tests/compiles/mstaticlib.nim
@@ -0,0 +1 @@
+echo 1234
\ No newline at end of file
diff --git a/tests/compiles/t8630.nim b/tests/compiles/t8630.nim
new file mode 100644
index 000000000..8b447d061
--- /dev/null
+++ b/tests/compiles/t8630.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''
+foo
+bar
+'''
+"""
+
+proc test(strings: seq[string]) =
+  for s in strings:
+    var p3 = addr(s)
+    echo p3[]
+
+test(@["foo", "bar"])
diff --git a/tests/compiles/tcompiles.nim b/tests/compiles/tcompiles.nim
new file mode 100644
index 000000000..1a21315c8
--- /dev/null
+++ b/tests/compiles/tcompiles.nim
@@ -0,0 +1,30 @@
+# test the new 'compiles' feature:
+
+template supports(opr, x: untyped): bool =
+  compiles(opr(x)) or compiles(opr(x, x))
+
+template ok(x) =
+  static:
+    assert(x)
+
+template no(x) =
+  static:
+    assert(not x)
+
+type
+  TObj = object
+
+var
+  myObj {.compileTime.}: TObj
+
+ok supports(`==`, myObj)
+ok supports(`==`, 45)
+
+no supports(`++`, 34)
+ok supports(`not`, true)
+ok supports(`+`, 34)
+
+no compiles(4+5.0 * "hallo")
+
+no compiles(undeclaredIdentifier)
+no compiles(undeclaredIdentifier)
diff --git a/tests/compiles/tevilcompiles.nim b/tests/compiles/tevilcompiles.nim
new file mode 100644
index 000000000..0930507d1
--- /dev/null
+++ b/tests/compiles/tevilcompiles.nim
@@ -0,0 +1,12 @@
+# bug #1055
+import unittest
+type TMatrix*[N,M: static[int], T] = object
+  data*: array[0..N*M-1, T]
+proc `==`*(a: distinct TMatrix; b: distinct TMatrix): bool =
+  result = a.data == b.data
+
+test "c":
+  var a = TMatrix[2,2,int](data: [1,2,3,4])
+  var b = TMatrix[2,2,int](data: [1,2,3,4])
+  check(a == b)
+
diff --git a/tests/compiles/trecursive_generic_in_compiles.nim b/tests/compiles/trecursive_generic_in_compiles.nim
new file mode 100644
index 000000000..ab31ad0f5
--- /dev/null
+++ b/tests/compiles/trecursive_generic_in_compiles.nim
@@ -0,0 +1,94 @@
+discard """
+action: compile
+"""
+
+# bug #3313
+import unittest, sugar
+{.experimental: "notnil".}
+type
+  ListNodeKind = enum
+    lnkNil, lnkCons
+  List*[T] = ref object
+    ## List ADT
+    case kind: ListNodeKind
+    of lnkNil:
+      discard
+    of lnkCons:
+      value: T
+      next: List[T] not nil
+
+proc Cons*[T](head: T, tail: List[T]): List[T] =
+  ## Constructs non empty list
+  List[T](kind: lnkCons, value: head, next: tail)
+
+proc Nil*[T](): List[T] =
+  ## Constructs empty list
+  List[T](kind: lnkNil)
+
+proc head*[T](xs: List[T]): T =
+  ## Returns list's head
+  xs.value
+
+# TODO
+# proc headOption*[T](xs: List[T]): Option[T] = ???
+
+proc tail*[T](xs: List[T]): List[T] =
+  ## Returns list's tail
+  case xs.kind
+  of lnkCons: xs.next
+  else: xs
+
+proc isEmpty*(xs: List): bool =
+  ## Checks  if list is empty
+  xs.kind == lnkNil
+
+proc `==`*[T](xs, ys: List[T]): bool =
+  ## Compares two lists
+  if (xs.isEmpty, ys.isEmpty) == (true, true): true
+  elif (xs.isEmpty, ys.isEmpty) == (false, false): xs.head == ys.head and xs.tail == ys.tail
+  else: false
+
+proc asList*[T](xs: varargs[T]): List[T] =
+  ## Creates list from varargs
+  proc initListImpl(i: int, xs: openArray[T]): List[T] =
+    if i > high(xs):
+      Nil[T]()
+    else:
+      Cons(xs[i], initListImpl(i+1, xs))
+  initListImpl(0, xs)
+
+proc foldRight*[T,U](xs: List[T], z: U, f: (T, U) -> U): U =
+  case xs.isEmpty
+  of true: z
+  else: f(xs.head, xs.tail.foldRight(z, f))
+
+proc dup*[T](xs: List[T]): List[T] =
+  ## Duplicates the list
+  xs.foldRight(Nil[T](), (x: T, xs: List[T]) => Cons(x, xs))
+
+type
+  ListFormat = enum
+    lfADT, lfSTD
+
+proc asString[T](xs: List[T], f = lfSTD): string =
+  proc asAdt(xs: List[T]): string =
+    case xs.isEmpty
+    of true: "Nil"
+    else: "Cons(" & $xs.head & ", " & xs.tail.asAdt & ")"
+
+  proc asStd(xs: List[T]): string =
+    "List(" & xs.foldLeft("", (s: string, v: T) =>
+      (if s == "": $v else: s & ", " & $v)) & ")"
+
+  case f
+  of lfADT: xs.asAdt
+  else: xs.asStd
+
+proc `$`*[T](xs: List[T]): string =
+  ## Converts list to string
+  result = xs.asString
+
+proc foldLeft*[T,U](xs: List[T], z: U, f: (U, T) -> U): U =
+  case xs.isEmpty
+  of true: z
+  else: foldLeft(xs.tail, f(z, xs.head), f)
diff --git a/tests/compiles/tstaticlib.nim b/tests/compiles/tstaticlib.nim
new file mode 100644
index 000000000..a18b59204
--- /dev/null
+++ b/tests/compiles/tstaticlib.nim
@@ -0,0 +1,22 @@
+import std/[os, osproc, strformat]
+
+
+const dir = "tests/compiles"
+const fileName = dir / "mstaticlib.nim"
+const nim = getCurrentCompilerExe()
+
+block: # bug #18578
+  const libName = dir / "tstaticlib1.a"
+  let (_, status) = execCmdEx(fmt"{nim} c -o:{libName} --app:staticlib {fileName}")
+  doAssert status == 0
+  doAssert fileExists(libName)
+  removeFile(libName)
+
+block: # bug #16947
+  const libName = dir / "tstaticlib2.a"
+  writeFile(libName, "echo 124")
+  doAssert fileExists(libName)
+  let (_, status) = execCmdEx(fmt"{nim} c -o:{libName} --app:staticlib {fileName}")
+  doAssert status == 0
+  doAssert fileExists(libName)
+  removeFile(libName)
diff --git a/tests/concepts/libs/trie.nim b/tests/concepts/libs/trie.nim
new file mode 100644
index 000000000..bdd318492
--- /dev/null
+++ b/tests/concepts/libs/trie.nim
@@ -0,0 +1,26 @@
+import
+  hashes, tables, trie_database
+
+type
+  MemDBTable = Table[KeccakHash, string]
+
+  MemDB* = object
+    tbl: MemDBTable
+
+proc hash*(key: KeccakHash): int =
+  hashes.hash(key.data)
+
+proc get*(db: MemDB, key: KeccakHash): string =
+  db.tbl[key]
+
+proc del*(db: var MemDB, key: KeccakHash): bool =
+  if db.tbl.hasKey(key):
+    db.tbl.del(key)
+    return true
+  else:
+    return false
+
+proc put*(db: var MemDB, key: KeccakHash, value: string): bool =
+  db.tbl[key] = value
+  return true
+
diff --git a/tests/concepts/libs/trie_database.nim b/tests/concepts/libs/trie_database.nim
new file mode 100644
index 000000000..a45c64842
--- /dev/null
+++ b/tests/concepts/libs/trie_database.nim
@@ -0,0 +1,12 @@
+type
+  KeccakHash* = object
+    data*: string
+
+  BytesRange* = object
+    bytes*: string
+
+  TrieDatabase* = concept db
+    put(var db, KeccakHash, string) is bool
+    del(var db, KeccakHash) is bool
+    get(db, KeccakHash) is string
+
diff --git a/tests/concepts/matrix.nim b/tests/concepts/matrix.nim
new file mode 100644
index 000000000..47a709f80
--- /dev/null
+++ b/tests/concepts/matrix.nim
@@ -0,0 +1,14 @@
+type
+  Matrix*[M, N: static[int]; T] = object
+    data: array[M*N, T]
+
+proc `[]`*(M: Matrix; m, n: int): M.T =
+  M.data[m * M.N + n]
+
+proc `[]=`*(M: var Matrix; m, n: int; v: M.T) =
+  M.data[m * M.N + n] = v
+
+# Adapt the Matrix type to the concept's requirements
+template Rows*(M: type Matrix): untyped = M.M
+template Cols*(M: type Matrix): untyped = M.N
+template ValueType*(M: type Matrix): typedesc = M.T
diff --git a/tests/concepts/matrixalgo.nim b/tests/concepts/matrixalgo.nim
new file mode 100644
index 000000000..98e5b8b4f
--- /dev/null
+++ b/tests/concepts/matrixalgo.nim
@@ -0,0 +1,28 @@
+import typetraits
+
+type
+  AnyMatrix*[R, C: static[int]; T] = concept m, var mvar, type M
+    M.ValueType is T
+    M.Rows == R
+    M.Cols == C
+
+    m[int, int] is T
+    mvar[int, int] = T
+
+    type TransposedType = stripGenericParams(M)[C, R, T]
+
+  AnySquareMatrix*[N: static[int], T] = AnyMatrix[N, N, T]
+
+  AnyTransform3D* = AnyMatrix[4, 4, float]
+
+proc transposed*(m: AnyMatrix): m.TransposedType =
+  for r in 0 ..< m.R:
+    for c in 0 ..< m.C:
+      result[r, c] = m[c, r]
+
+proc determinant*(m: AnySquareMatrix): int =
+  return 0
+
+proc setPerspectiveProjection*(m: AnyTransform3D) =
+  discard
+
diff --git a/tests/concepts/mvarconcept.nim b/tests/concepts/mvarconcept.nim
new file mode 100644
index 000000000..0f9d0beff
--- /dev/null
+++ b/tests/concepts/mvarconcept.nim
@@ -0,0 +1,13 @@
+type RNG* = concept var rng
+  rng.randomUint32() is uint32
+
+type MersenneTwister* = object
+
+proc randomUint32*(self: var MersenneTwister): uint32 = 5
+
+proc randomInt*(rng: var RNG; max: Positive): Natural = 5
+
+var mersenneTwisterInst = MersenneTwister()
+
+proc randomInt*(max: Positive): Natural =
+  mersenneTwisterInst.randomInt(max)
diff --git a/tests/concepts/t18409.nim b/tests/concepts/t18409.nim
new file mode 100644
index 000000000..0edba2d31
--- /dev/null
+++ b/tests/concepts/t18409.nim
@@ -0,0 +1,37 @@
+discard """
+  action: "compile"
+"""
+
+# A vector space over a field F concept.
+type VectorSpace*[F] = concept x, y, type V
+  vector_add(x, y) is V
+  scalar_mul(x, F) is V
+  dimension(V) is Natural
+
+# Real numbers (here floats) form a vector space.
+func vector_add*(v: float, w: float): float =  v + w
+func scalar_mul*(v: float, s: float): float =   v * s
+func dimension*(x: typedesc[float]): Natural = 1
+
+# 2-tuples of real numbers form a vector space.
+func vector_add*(v, w: (float, float)): (float, float) =
+  (vector_add(v[0], w[0]), vector_add(v[1], w[1]))
+
+func scalar_mul*(v: (float, float), s: float): (float, float) =
+  (scalar_mul(v[0], s), scalar_mul(v[1], s))
+
+func dimension*(x: typedesc[(float, float)]): Natural = 2
+
+# Check concept requirements.
+assert float is VectorSpace
+assert (float, float) is VectorSpace
+
+# Commutivity axiom for vector spaces over the same field.
+func axiom_commutivity*[F](u, v: VectorSpace[F]): bool =
+  vector_add(u, v) == vector_add(v, u)
+
+# This is okay.
+assert axiom_commutivity(2.2, 3.3)
+
+# This is not.
+assert axiom_commutivity((2.2, 3.3), (4.4, 5.5))
diff --git a/tests/concepts/t19730.nim b/tests/concepts/t19730.nim
new file mode 100644
index 000000000..575d45dda
--- /dev/null
+++ b/tests/concepts/t19730.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''1.01.01.01.0
+1.01.01.01.0
+'''
+"""
+
+type
+  Color = concept c
+    c.r is SomeFloat
+    c.g is SomeFloat
+    c.b is SomeFloat
+    c.a is SomeFloat
+
+proc useColor(color: Color) =
+  echo(color.r, color.g, color.b, color.a)
+
+let color = (r: 1.0, g: 1.0, b: 1.0, a: 1.0)
+useColor(color)
+
+useColor((r: 1.0, g: 1.0, b: 1.0, a: 1.0))
diff --git a/tests/concepts/t20237.nim b/tests/concepts/t20237.nim
new file mode 100644
index 000000000..175c7a9d1
--- /dev/null
+++ b/tests/concepts/t20237.nim
@@ -0,0 +1,3 @@
+type Foo* = concept
+  ## doc comment
+  proc foo(x: Self)
diff --git a/tests/concepts/t3330.nim b/tests/concepts/t3330.nim
new file mode 100644
index 000000000..901f8d2f4
--- /dev/null
+++ b/tests/concepts/t3330.nim
@@ -0,0 +1,70 @@
+discard """
+matrix: "--mm:refc"
+errormsg: "type mismatch: got <Bar[system.int]>"
+nimout: '''
+t3330.nim(70, 4) Error: type mismatch: got <Bar[system.int]>
+but expected one of:
+proc test(foo: Foo[int])
+  first type mismatch at position: 1
+  required type for foo: Foo[int]
+  but expression 'bar' is of type: Bar[system.int]
+t3330.nim(55, 8) Hint: Non-matching candidates for add(k, string, T)
+proc add(x: var string; y: char)
+  first type mismatch at position: 1
+  required type for x: var string
+  but expression 'k' is of type: Alias
+proc add(x: var string; y: cstring)
+  first type mismatch at position: 1
+  required type for x: var string
+  but expression 'k' is of type: Alias
+proc add(x: var string; y: string)
+  first type mismatch at position: 1
+  required type for x: var string
+  but expression 'k' is of type: Alias
+proc add[T](x: var seq[T]; y: openArray[T])
+  first type mismatch at position: 1
+  required type for x: var seq[T]
+  but expression 'k' is of type: Alias
+proc add[T](x: var seq[T]; y: sink T)
+  first type mismatch at position: 1
+  required type for x: var seq[T]
+  but expression 'k' is of type: Alias
+
+t3330.nim(55, 8) template/generic instantiation of `add` from here
+t3330.nim(62, 6) Foo: 'bar.value' cannot be assigned to
+t3330.nim(55, 8) template/generic instantiation of `add` from here
+t3330.nim(63, 6) Foo: 'bar.x' cannot be assigned to
+
+expression: test(bar)'''
+"""
+
+
+
+
+
+
+
+
+
+
+
+
+## line 60
+type
+  Foo[T] = concept k
+    add(k, string, T)
+
+  Bar[T] = object
+    value: T
+    x: string
+
+proc add[T](bar: Bar[T], x: string, val: T) =
+  bar.value = val
+  bar.x = x
+
+proc test(foo: Foo[int]) =
+  foo.add("test", 42)
+  echo(foo.x)
+
+var bar = Bar[int]()
+bar.test()
diff --git a/tests/concepts/t4982.nim b/tests/concepts/t4982.nim
new file mode 100644
index 000000000..9d82c83c9
--- /dev/null
+++ b/tests/concepts/t4982.nim
@@ -0,0 +1,18 @@
+discard """
+errormsg: "undeclared identifier: 'x'"
+line: 10
+"""
+
+import typetraits # without this import the program compiles (and echos false)
+
+type
+  SomeTestConcept = concept t
+    x.name is string # typo: t.name was intended (which would result in echo true)
+
+type
+  TestClass = ref object of RootObj
+    name: string
+
+var test = TestClass(name: "mytest")
+echo $(test is SomeTestConcept)
+
diff --git a/tests/concepts/t5888lib/ca.nim b/tests/concepts/t5888lib/ca.nim
new file mode 100644
index 000000000..4a811f797
--- /dev/null
+++ b/tests/concepts/t5888lib/ca.nim
@@ -0,0 +1,4 @@
+type
+  CA* = concept c
+    c.x is int
+
diff --git a/tests/concepts/t5888lib/opt.nim b/tests/concepts/t5888lib/opt.nim
new file mode 100644
index 000000000..65d16addc
--- /dev/null
+++ b/tests/concepts/t5888lib/opt.nim
@@ -0,0 +1,6 @@
+import ca
+
+type
+  Opt* = object
+    x*: int
+
diff --git a/tests/concepts/t8012.nim b/tests/concepts/t8012.nim
new file mode 100644
index 000000000..ec2aa6e5c
--- /dev/null
+++ b/tests/concepts/t8012.nim
@@ -0,0 +1,15 @@
+type
+  MyTypeCon = concept c
+    c.counter is int
+  MyType = object
+    counter: int
+
+proc foo(conc: var MyTypeCon) =
+  conc.counter.inc
+  if conc.counter < 5:
+    foo(conc)
+
+var x: MyType
+
+x.foo
+discard x.repr
diff --git a/tests/concepts/t8558.nim b/tests/concepts/t8558.nim
new file mode 100644
index 000000000..acb2de30e
--- /dev/null
+++ b/tests/concepts/t8558.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''10
+9
+8
+7
+6
+5
+4
+3
+2
+1
+go!
+'''
+"""
+
+type Integral = concept x
+  x == 0 is bool
+  x - 1 is type(x)
+
+proc countToZero(n: Integral) =
+  if n == 0: echo "go!"
+  else:
+    echo n
+    countToZero(n-1)
+
+countToZero(10)
\ No newline at end of file
diff --git a/tests/concepts/t976.nim b/tests/concepts/t976.nim
new file mode 100644
index 000000000..776d53827
--- /dev/null
+++ b/tests/concepts/t976.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''
+Printable
+'''
+joinable: false
+"""
+
+#[
+  The converter is a proper example of a confounding variable
+  Moved to an isolated file
+]#
+
+type
+  Obj1[T] = object
+      v: T
+converter toObj1[T](t: T): Obj1[T] =
+  return Obj1[T](v: t)
+block t976:
+  type
+    int1 = distinct int
+    int2 = distinct int
+    int1g = concept x
+      x is int1
+    int2g = concept x
+      x is int2
+
+  proc take[T: int1g](value: int1) =
+    when T is int2:
+      static: error("killed in take(int1)")
+
+  proc take[T: int2g](vale: int2) =
+    when T is int1:
+      static: error("killed in take(int2)")
+
+  var i1: int1 = 1.int1
+  var i2: int2 = 2.int2
+
+  take[int1](i1)
+  take[int2](i2)
+
+  template reject(e) =
+    static: assert(not compiles(e))
+
+  reject take[string](i2)
+  reject take[int1](i2)
+
+  # bug #6249
+  type
+      Obj2 = ref object
+      PrintAble = concept x
+          $x is string
+
+  proc `$`[T](nt: Obj1[T]): string =
+      when T is PrintAble: result = "Printable"
+      else: result = "Non Printable"
+
+  echo Obj2()
\ No newline at end of file
diff --git a/tests/concepts/tcomparable.nim b/tests/concepts/tcomparable.nim
new file mode 100644
index 000000000..06612a47e
--- /dev/null
+++ b/tests/concepts/tcomparable.nim
@@ -0,0 +1,13 @@
+type
+  Comparable = concept a
+    (a < a) is bool
+
+proc myMax(a, b: Comparable): Comparable =
+  if a < b:
+    return b
+  else:
+    return a
+
+doAssert myMax(5, 10) == 10
+doAssert myMax(31.3, 1.23124) == 31.3
+
diff --git a/tests/concepts/tconceptinclosure.nim b/tests/concepts/tconceptinclosure.nim
new file mode 100644
index 000000000..23c1bf293
--- /dev/null
+++ b/tests/concepts/tconceptinclosure.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''
+10
+20
+int
+20
+3
+'''
+"""
+
+import typetraits
+
+type
+  FonConcept = concept x
+    x.x is int
+
+  GenericConcept[T] = concept x
+    x.x is T
+    const L = T.name.len
+
+  Implementation = object
+    x: int
+
+  Closure = object
+    f: proc()
+
+proc f1(x: FonConcept): Closure =
+  result.f = proc () =
+    echo x.x
+
+proc f2(x: GenericConcept): Closure =
+  result.f = proc () =
+    echo x.x
+    echo GenericConcept.T.name
+
+proc f3[T](x: GenericConcept[T]): Closure =
+  result.f = proc () =
+    echo x.x
+    echo x.L
+
+let x = Implementation(x: 10)
+let y = Implementation(x: 20)
+
+let a = x.f1
+let b = x.f2
+let c = x.f1
+let d = y.f2
+let e = y.f3
+
+a.f()
+d.f()
+e.f()
+
diff --git a/tests/concepts/tconcepts.nim b/tests/concepts/tconcepts.nim
new file mode 100644
index 000000000..ea3ddc401
--- /dev/null
+++ b/tests/concepts/tconcepts.nim
@@ -0,0 +1,451 @@
+discard """
+output: '''
+10
+20
+int
+20
+3
+x as ParameterizedType[T]
+x as ParameterizedType[T]
+x as ParameterizedType[T]
+x as ParameterizedType
+x as ParameterizedType
+x as CustomTypeClass
+1
+2
+3
+4
+5
+6
+a
+b
+t
+e
+s
+t
+z
+e
+1
+2
+3
+20
+10
+5
+9
+'''
+"""
+
+
+import typetraits, strutils
+
+
+block tcomparable:
+  type
+    Comparable = concept a
+      (a < a) is bool
+
+  proc myMax(a, b: Comparable): Comparable =
+    if a < b:
+      return b
+    else:
+      return a
+
+  doAssert myMax(5, 10) == 10
+  doAssert myMax(31.3, 1.23124) == 31.3
+
+
+
+block tconceptinclosure:
+  type
+    FonConcept = concept x
+      x.x is int
+    GenericConcept[T] = concept x
+      x.x is T
+      const L = T.name.len
+    Implementation = object
+      x: int
+    Closure = object
+      f: proc()
+
+  proc f1(x: FonConcept): Closure =
+    result.f = proc () =
+      echo x.x
+
+  proc f2(x: GenericConcept): Closure =
+    result.f = proc () =
+      echo x.x
+      echo GenericConcept.T.name
+
+  proc f3[T](x: GenericConcept[T]): Closure =
+    result.f = proc () =
+      echo x.x
+      echo x.L
+
+  let x = Implementation(x: 10)
+  let y = Implementation(x: 20)
+
+  let a = x.f1
+  let b = x.f2
+  let c = x.f1
+  let d = y.f2
+  let e = y.f3
+
+  a.f()
+  d.f()
+  e.f()
+
+
+
+block overload_precedence:
+  type ParameterizedType[T] = object
+
+  type CustomTypeClass = concept c
+    true
+
+  # 3 competing procs
+  proc a[T](x: ParameterizedType[T]) =
+    echo "x as ParameterizedType[T]"
+
+  proc a(x: ParameterizedType) =
+    echo "x as ParameterizedType"
+
+  proc a(x: CustomTypeClass) =
+    echo "x as CustomTypeClass"
+
+  # the same procs in different order
+  proc b(x: ParameterizedType) =
+    echo "x as ParameterizedType"
+
+  proc b(x: CustomTypeClass) =
+    echo "x as CustomTypeClass"
+
+  proc b[T](x: ParameterizedType[T]) =
+    echo "x as ParameterizedType[T]"
+
+  # and yet another order
+  proc c(x: CustomTypeClass) =
+    echo "x as CustomTypeClass"
+
+  proc c(x: ParameterizedType) =
+    echo "x as ParameterizedType"
+
+  proc c[T](x: ParameterizedType[T]) =
+    echo "x as ParameterizedType[T]"
+
+  # remove the most specific one
+  proc d(x: ParameterizedType) =
+    echo "x as ParameterizedType"
+
+  proc d(x: CustomTypeClass) =
+    echo "x as CustomTypeClass"
+
+  # then shuffle the order again
+  proc e(x: CustomTypeClass) =
+    echo "x as CustomTypeClass"
+
+  proc e(x: ParameterizedType) =
+    echo "x as ParameterizedType"
+
+  # the least specific one is a match
+  proc f(x: CustomTypeClass) =
+    echo "x as CustomTypeClass"
+
+  a(ParameterizedType[int]())
+  b(ParameterizedType[int]())
+  c(ParameterizedType[int]())
+  d(ParameterizedType[int]())
+  e(ParameterizedType[int]())
+  f(ParameterizedType[int]())
+
+
+
+block templates:
+  template typeLen(x): int = x.type.name.len
+
+  template bunchOfChecks(x) =
+    x.typeLen > 3
+    x != 10 is bool
+
+  template stmtListExprTmpl(x: untyped): untyped =
+    x is int
+    x
+
+  type
+    Obj = object
+      x: int
+
+    Gen[T] = object
+      x: T
+
+    Eq = concept x, y
+      (x == y) is bool
+
+    NotEq = concept x, y
+      (x != y) is bool
+
+    ConceptUsingTemplate1 = concept x
+      echo x
+      sizeof(x) is int
+      bunchOfChecks x
+
+    ConceptUsingTemplate2 = concept x
+      stmtListExprTmpl x
+
+  template ok(x) =
+    static: assert(x)
+
+  template no(x) =
+    static: assert(not(x))
+
+  ok int is Eq
+  ok int is NotEq
+  ok string is Eq
+  ok string is NotEq
+  ok Obj is Eq
+  ok Obj is NotEq
+  ok Gen[string] is Eq
+  ok Gen[int] is NotEq
+
+  no int is ConceptUsingTemplate1
+  ok float is ConceptUsingTemplate1
+  no string is ConceptUsingTemplate1
+
+  ok int is ConceptUsingTemplate2
+  no float is ConceptUsingTemplate2
+  no string is ConceptUsingTemplate2
+
+
+
+block titerable:
+  type
+    Iterable[T] = concept x
+      for value in x:
+        type(value) is T
+
+  proc sum[T](iter: Iterable[T]): T =
+    static: echo T.name
+    for element in iter:
+      static: echo element.type.name
+      result += element
+
+  doAssert sum([1, 2, 3, 4, 5]) == 15
+
+
+
+block tmanual:
+  template accept(e) =
+    static: assert compiles(e)
+
+  template reject(e) =
+    static: assert(not compiles(e))
+
+  type
+    Container[T] = concept c
+      c.len is Ordinal
+      items(c) is T
+      for value in c:
+        type(value) is T
+
+  proc takesIntContainer(c: Container[int]) =
+    for e in c: echo e
+
+  takesIntContainer(@[1, 2, 3])
+  reject takesIntContainer(@["x", "y"])
+
+  proc takesContainer(c: Container) =
+    for e in c: echo e
+
+  takesContainer(@[4, 5, 6])
+  takesContainer(@["a", "b"])
+  takesContainer "test"
+  reject takesContainer(10)
+
+
+
+block modifiers_in_place:
+  type
+    VarContainer[T] = concept c
+      put(var c, T)
+    AltVarContainer[T] = concept var c
+      put(c, T)
+    NonVarContainer[T] = concept c
+      put(c, T)
+    GoodContainer = object
+      x: int
+    BadContainer = object
+      x: int
+
+  proc put(x: BadContainer, y: int) = discard
+  proc put(x: var GoodContainer, y: int) = discard
+
+  template ok(x) = assert(x)
+  template no(x) = assert(not(x))
+
+  static:
+    ok GoodContainer is VarContainer[int]
+    ok GoodContainer is AltVarContainer[int]
+    no BadContainer is VarContainer[int]
+    no BadContainer is AltVarContainer[int]
+    ok GoodContainer is NonVarContainer[int]
+    ok BadContainer is NonVarContainer[int]
+
+
+
+block treversable:
+  type
+    Reversable[T] = concept a
+      a[int] is T
+      a.high is int
+      a.len is int
+      a.low is int
+
+  proc get[T](s: Reversable[T], n: int): T =
+    s[n]
+
+  proc hi[T](s: Reversable[T]): int =
+    s.high
+
+  proc lo[T](s: Reversable[T]): int =
+    s.low
+
+  iterator reverse[T](s: Reversable[T]): T =
+    assert hi(s) - lo(s) == len(s) - 1
+    for z in hi(s).countdown(lo(s)):
+      yield s.get(z)
+
+  for s in @["e", "z"].reverse:
+    echo s
+
+
+
+block tmonoid:
+  type Monoid = concept x, y
+    x + y is type(x)
+    type(z(type(x))) is type(x)
+
+  proc z(x: typedesc[int]): int = 0
+
+  doAssert(int is Monoid)
+
+  # https://github.com/nim-lang/Nim/issues/8126
+  type AdditiveMonoid = concept x, y, type T
+    x + y is T
+
+    # some redundant checks to test an alternative approaches:
+    type TT = type(x)
+    x + y is type(x)
+    x + y is TT
+
+  doAssert(1 is AdditiveMonoid)
+
+
+
+block tesqofconcept:
+  type
+    MyConcept = concept x
+      someProc(x)
+    SomeSeq = seq[MyConcept]
+
+  proc someProc(x:int) = echo x
+
+  proc work (s: SomeSeq) =
+    for item in s:
+      someProc item
+
+  var s = @[1, 2, 3]
+  work s
+
+
+
+block tvectorspace:
+  type VectorSpace[K] = concept x, y
+    x + y is type(x)
+    zero(type(x)) is type(x)
+    -x is type(x)
+    x - y is type(x)
+    var k: K
+    k * x is type(x)
+
+  proc zero(T: typedesc): T = 0
+
+  static:
+    assert float is VectorSpace[float]
+    # assert float is VectorSpace[int]
+    # assert int is VectorSpace
+
+
+
+block tstack:
+  template reject(e) =
+    static: assert(not compiles(e))
+
+  type
+    ArrayStack = object
+      data: seq[int]
+
+  proc push(s: var ArrayStack, item: int) =
+    s.data.add item
+
+  proc pop(s: var ArrayStack): int =
+    return s.data.pop()
+
+  type
+    Stack[T] = concept var s
+      s.push(T)
+      s.pop() is T
+
+      type ValueType = T
+      const ValueTypeName = T.name.toUpperAscii
+
+  proc genericAlgorithm[T](s: var Stack[T], y: T) =
+    static:
+      echo "INFERRED ", T.name
+      echo "VALUE TYPE ", s.ValueType.name
+      echo "VALUE TYPE NAME ", s.ValueTypeName
+
+    s.push(y)
+    echo s.pop
+
+  proc implicitGeneric(s: var Stack): auto =
+    static:
+      echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name
+      echo "IMPLICIT VALUE TYPE ", s.ValueType.name, " ", Stack.ValueType.name
+      echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", Stack.ValueTypeName
+
+    return s.pop()
+
+  var s = ArrayStack(data: @[])
+
+  s.push 10
+  s.genericAlgorithm 20
+  echo s.implicitGeneric
+
+  reject s.genericAlgorithm "x"
+  reject s.genericAlgorithm 1.0
+  reject "str".implicitGeneric
+  reject implicitGeneric(10)
+
+
+
+import libs/[trie_database, trie]
+block ttrie:
+  proc takeDb(d: TrieDatabase) = discard
+  var mdb: MemDB
+  takeDb(mdb)
+
+
+
+import mvarconcept
+block tvar:
+  # bug #2346, bug #2404
+  echo randomInt(5)
+
+block tcomment:
+  type
+    Foo = concept
+      ## Some comment
+      proc bar(x: Self)
+
+  proc bar(x: int) = echo x
+  proc foo(x: Foo) = x.bar
+  foo(9)
diff --git a/tests/concepts/tconcepts_issues.nim b/tests/concepts/tconcepts_issues.nim
new file mode 100644
index 000000000..c6d0267c5
--- /dev/null
+++ b/tests/concepts/tconcepts_issues.nim
@@ -0,0 +1,556 @@
+discard """
+  output: '''
+20.0 USD
+true
+true
+true
+true
+true
+f
+0
+10
+10
+5
+()
+false
+10
+true
+true
+true
+true
+p has been called.
+p has been called.
+implicit generic
+generic
+false
+true
+-1
+Meow
+10 0.0
+1 2.0
+'''
+joinable: false
+"""
+
+import macros, typetraits, os, posix
+
+
+block t5983:
+  const currencies = ["USD", "EUR"] # in real code 120 currencies
+
+  type USD = distinct float # in real code 120 types generates using macro
+  type EUR = distinct float
+
+  type CurrencyAmount = concept c
+    type t = c.type
+    const name = c.type.name
+    name in currencies
+
+  proc `$`(x: CurrencyAmount): string =
+    $float(x) & " " & x.name
+
+  let amount = 20.USD
+  echo amount
+
+
+block t3414:
+  type
+    View[T] = concept v
+      v.empty is bool
+      v.front is T
+      popFront v
+
+  proc find(view: View; target: View.T): View =
+    result = view
+
+    while not result.empty:
+      if view.front == target:
+        return
+
+      mixin popFront
+      popFront result
+
+  proc popFront[T](s: var seq[T]) = discard
+  proc empty[T](s: seq[T]): bool = false
+
+  var s1 = @[1, 2, 3]
+  let s2 = s1.find(10)
+
+
+block t1128:
+  type
+    TFooContainer[T] = object
+
+    TContainer[T] = concept var c
+      foo(c, T)
+
+  proc foo[T](c: var TFooContainer[T], val: T) =
+    discard
+
+  proc bar(c: var TContainer) =
+    discard
+
+  var fooContainer: TFooContainer[int]
+  echo fooContainer is TFooContainer # true.
+  echo fooContainer is TFooContainer[int] # true.
+  fooContainer.bar()
+
+
+
+block t5642:
+  type DataTable = concept x
+    x is object
+    for f in fields(x):
+      f is seq
+
+  type Students = object
+    id : seq[int]
+    name : seq[string]
+    age: seq[int]
+
+  proc nrow(dt: DataTable) : Natural =
+    var totalLen = 0
+    for f in fields(dt):
+      totalLen += f.len
+    return totalLen
+
+  let
+    stud = Students(id: @[1,2,3], name: @["Vas", "Pas", "NafNaf"], age: @[10,16,32])
+
+  doAssert nrow(stud) == 9
+
+
+
+import t5888lib/ca, t5888lib/opt
+block t5888:
+  type LocalCA = ca.CA
+
+  proc f(c: CA) =
+    echo "f"
+    echo c.x
+
+  var o = new(Opt)
+
+  echo o is CA
+  echo o is LocalCA
+  echo o is ca.CA
+
+  o.f()
+
+
+
+import json
+block t5968:
+  type
+    Enumerable[T] = concept e
+      for it in e:
+        it is T
+
+  proc cmap[T, G](e: Enumerable[T], fn: proc(t: T): G): seq[G] =
+    result = @[]
+    for it in e: result.add(fn(it))
+
+  var x = %["hello", "world"]
+
+  var z = x.cmap(proc(it: JsonNode): string = it.getStr & "!")
+  assert z == @["hello!", "world!"]
+
+
+
+import sugar
+block t6462:
+  type
+    FilterMixin[T] = ref object
+      test: (T) -> bool
+      trans: (T) -> T
+
+    SeqGen[T] = ref object
+      fil: FilterMixin[T]
+
+    WithFilter[T] = concept a
+      a.fil is FilterMixin[T]
+
+  proc test[T](a: WithFilter[T]): (T) -> bool =
+    a.fil.test
+
+  var s = SeqGen[int](fil: FilterMixin[int](test: nil, trans: nil))
+  doAssert s.test() == nil
+
+
+
+block t6770:
+  type GA = concept c
+    c.a is int
+
+  type A = object
+    a: int
+
+  type AA = object
+    case exists: bool
+    of true:
+      a: int
+    else:
+      discard
+
+  proc print(inp: GA) =
+    echo inp.a
+
+  let failing = AA(exists: true, a: 10)
+  let working = A(a:10)
+  print(working)
+  print(failing)
+
+
+
+block t7952:
+  type
+    HasLen = concept iter
+      len(iter) is int
+
+  proc echoLen(x: HasLen) =
+    echo len(x)
+
+  echoLen([1, 2, 3, 4, 5])
+
+
+
+block t8280:
+  type
+    Iterable[T] = concept x
+      for elem in x:
+        elem is T
+
+  proc max[A](iter: Iterable[A]): A =
+    discard
+
+  type
+    MyType = object
+
+  echo max(@[MyType()])
+
+
+
+import math
+block t3452:
+  type
+    Node = concept n
+      `==`(n, n) is bool
+    Graph1 = concept g
+      type N = Node
+      distance(g, N, N) is float
+    Graph2 = concept g
+      distance(g, Node, Node) is float
+    Graph3 = concept g
+      var x: Node
+      distance(g, x, x) is float
+    XY = tuple[x, y: int]
+    MyGraph = object
+      points: seq[XY]
+
+  static:
+    assert XY is Node
+
+  proc distance( g: MyGraph, a, b: XY): float =
+    sqrt( pow(float(a.x - b.x), 2) + pow(float(a.y - b.y), 2) )
+
+  static:
+    assert MyGraph is Graph1
+    assert MyGraph is Graph2
+    assert MyGraph is Graph3
+
+
+
+block t6691:
+  type
+    ConceptA = concept c
+    ConceptB = concept c
+        c.myProc(ConceptA)
+    Obj = object
+
+  proc myProc(obj: Obj, x: ConceptA) = discard
+
+  echo Obj is ConceptB
+
+
+
+block t6782:
+  type
+    Reader = concept c
+      c.read(openArray[byte], int, int) is int
+    Rdr = concept c
+      c.rd(openArray[byte], int, int) is int
+
+  type TestFile = object
+
+  proc read(r: TestFile, dest: openArray[byte], offset: int, limit: int): int =
+      result = 0
+  proc rd(r: TestFile, dest: openArray[byte], offset: int, limit: int): int =
+      result = 0
+
+  doAssert TestFile is Reader
+  doAssert TestFile is Rdr
+
+
+
+block t7114:
+  type
+    MyConcept = concept x
+      x.close() # error, doesn't work
+    MyConceptImplementer = object
+
+  proc close(self: MyConceptImplementer) = discard
+  proc takeConcept(window: MyConcept) =
+    discard
+
+  takeConcept(MyConceptImplementer())
+
+
+
+block t7510:
+  type
+    A[T] = concept a
+        a.x is T
+    B[T] = object
+        x: T
+  proc getx(v: A): v.T = v.x
+  var v = B[int32](x: 10)
+  echo v.getx
+
+
+
+block misc_issues:
+  # https://github.com/nim-lang/Nim/issues/1147
+  type TTest = object
+    vals: seq[int]
+
+  proc add(self: var TTest, val: int) =
+    self.vals.add(val)
+
+  type CAddable = concept x
+    x[].add(int)
+
+  echo((ref TTest) is CAddable) # true
+
+  # https://github.com/nim-lang/Nim/issues/1570
+  type ConcretePointOfFloat = object
+    x, y: float
+
+  type ConcretePoint[Value] = object
+    x, y: Value
+
+  type AbstractPointOfFloat = concept p
+    p.x is float and p.y is float
+
+  let p1 = ConcretePointOfFloat(x: 0, y: 0)
+  let p2 = ConcretePoint[float](x: 0, y: 0)
+
+  echo p1 is AbstractPointOfFloat      # true
+  echo p2 is AbstractPointOfFloat      # true
+  echo p2.x is float and p2.y is float # true
+
+  # https://github.com/nim-lang/Nim/issues/2018
+  type ProtocolFollower = concept c
+    true # not a particularly involved protocol
+
+  type ImplementorA = object
+  type ImplementorB = object
+
+  proc p[A: ProtocolFollower, B: ProtocolFollower](a: A, b: B) =
+    echo "p has been called."
+
+  p(ImplementorA(), ImplementorA())
+  p(ImplementorA(), ImplementorB())
+
+  # https://github.com/nim-lang/Nim/issues/2423
+  proc put[T](c: seq[T], x: T) = echo "generic"
+  proc put(c: seq) = echo "implicit generic"
+
+  type
+    Container[T] = concept c
+      put(c)
+      put(c, T)
+
+  proc c1(x: Container) = echo "implicit generic"
+  c1(@[1])
+
+  proc c2[T](x: Container[T]) = echo "generic"
+  c2(@[1])
+
+  # https://github.com/nim-lang/Nim/issues/2882
+  type
+    Paper = object
+      name: string
+
+    Bendable = concept x
+      bend(x is Bendable)
+
+  proc bend(p: Paper): Paper = Paper(name: "bent-" & p.name)
+
+  var paper = Paper(name: "red")
+  echo paper is Bendable
+
+  type
+    A = concept self
+      size(self) is int
+
+    B = object
+
+  proc size(self: B): int =
+    return -1
+
+  proc size(self: A): int =
+    return 0
+
+  let b = B()
+  echo b is A
+  echo b.size()
+
+  # https://github.com/nim-lang/Nim/issues/7125
+  type
+    Thing = concept x
+      x.hello is string
+    Cat = object
+
+  proc hello(d: Cat): string = "Meow"
+
+  proc sayHello(c: Thing) = echo(c.hello)
+
+  # used to be 'var a: Thing = Cat()' but that's not valid Nim code
+  # anyway and will be an error soon.
+  var a: Cat = Cat()
+  a.sayHello()
+
+
+# bug #16897
+
+type
+  Fp[N: static int, T] = object
+    big: array[N, T]
+
+type
+  QuadraticExt* = concept x
+    ## Quadratic Extension concept (like complex)
+    type BaseField = auto
+    x.c0 is BaseField
+    x.c1 is BaseField
+var address = pointer(nil)
+proc prod(r: var QuadraticExt, b: QuadraticExt) =
+  if address == nil:
+    address = addr b
+    prod(r, b)
+  else:
+    assert address == addr b
+
+type
+  Fp2[N: static int, T] {.byref.} = object
+    c0, c1: Fp[N, T]
+
+# This should be passed by reference,
+# but concepts do not respect the 24 bytes rule
+# or `byref` pragma.
+var r, b: Fp2[6, uint64]
+
+prod(r, b)
+
+
+block: # bug #21263
+  type
+    DateDayFraction = concept # no T, an atom
+      proc date(a: Self): int
+      proc fraction(b: Self): float
+    Date = distinct int
+    DateDayFractionImpl = object
+      date : int
+      fraction : float
+
+  proc date(a: Date): int = a.int
+  proc fraction(a:Date): float = 0.0
+
+  proc date(a: DateDayFractionImpl): int = a.date
+  proc fraction(b: DateDayFractionImpl): float = b.fraction
+
+
+  proc print(a: DateDayFraction) =
+    echo a.date, " ", a.fraction
+
+  print(10.Date) # ok
+  print(DateDayFractionImpl(date: 1, fraction: 2))  # error
+
+import sets
+import deques
+
+type AnyTree[V] = concept t, type T
+  for v in t.leaves(V):
+    v is V
+
+type BreadthOrder[V] = ref object
+  frontier: Deque[V]
+  visited: HashSet[V]
+
+proc expand[V, T](order: ref BreadthOrder[T], tree: AnyTree[V], node: V, transform: (V) -> (T)) =
+  for leaf in tree.leaves(node):
+    if not order.visited.containsOrIncl(transform(leaf)):
+      order.frontier.addLast(transform(leaf))
+
+proc hasNext[V](order: ref BreadthOrder[V]): bool =
+  order.frontier.len > 0
+
+proc init[V](_: typedesc[BreadthOrder]): ref BreadthOrder[V] =
+  result.new()
+  result[] = BreadthOrder[V](frontier: initDeque[V](), visited: initHashSet[V]())
+
+proc popNext[V](order: ref BreadthOrder[V]): V =
+  order.frontier.popFirst()
+
+type LevelNode[V] = tuple
+  depth: uint
+  node: V
+
+proc depthOf*[V](orderType: typedesc[BreadthOrder], tree: AnyTree[V], root, goal: V): uint =
+  if root == goal:
+    return 0
+  var order = init[LevelNode[V]](orderType)
+  order.expand(tree, root, (leaf) => (1.uint, leaf))
+  while order.hasNext():
+    let depthNode: LevelNode[V] = order.popNext()
+    if depthNode.node == goal:
+      return depthNode.depth
+    order.expand(tree, depthNode.node, (leaf) => (depthNode.depth + 1, leaf))
+
+type CappedStringTree = ref object
+  symbols: string
+  cap: Natural
+
+iterator leaves*(t: CappedStringTree, s: string): string =
+  if s.len < t.cap:
+    for c in t.symbols:
+      yield s & c
+
+block: # bug #12852
+  var tree = CappedStringTree(symbols: "^v><", cap: 5)
+
+  doAssert BreadthOrder.depthOf(tree, "", ">>>") == 3
+
+block: #bug #22723
+  type
+    Node  = concept n, type T 
+      for i in n.children:
+        i is T
+      n.parent is T
+
+    Nd = ref object
+      parent: Nd
+      children: seq[Nd]
+
+  proc addChild(parent, child: Node) =
+    parent.children.add(child)
+    child.parent = parent
+
+  proc foo =
+    var
+      a = Nd()
+      b = Nd()
+    a.addChild(b)
+    doAssert a.children.len == 1
+
+  foo()
diff --git a/tests/concepts/tconcepts_overload_precedence.nim b/tests/concepts/tconcepts_overload_precedence.nim
new file mode 100644
index 000000000..c580d2688
--- /dev/null
+++ b/tests/concepts/tconcepts_overload_precedence.nim
@@ -0,0 +1,69 @@
+discard """
+  output: '''x as ParameterizedType[T]
+x as ParameterizedType[T]
+x as ParameterizedType[T]
+x as ParameterizedType
+x as ParameterizedType
+x as CustomTypeClass'''
+"""
+
+type ParameterizedType[T] = object
+
+type CustomTypeClass = concept c
+  true
+
+# 3 competing procs
+proc a[T](x: ParameterizedType[T]) =
+  echo "x as ParameterizedType[T]"
+
+proc a(x: ParameterizedType) =
+  echo "x as ParameterizedType"
+
+proc a(x: CustomTypeClass) =
+  echo "x as CustomTypeClass"
+
+# the same procs in different order
+proc b(x: ParameterizedType) =
+  echo "x as ParameterizedType"
+
+proc b(x: CustomTypeClass) =
+  echo "x as CustomTypeClass"
+
+proc b[T](x: ParameterizedType[T]) =
+  echo "x as ParameterizedType[T]"
+
+# and yet another order
+proc c(x: CustomTypeClass) =
+  echo "x as CustomTypeClass"
+
+proc c(x: ParameterizedType) =
+  echo "x as ParameterizedType"
+
+proc c[T](x: ParameterizedType[T]) =
+  echo "x as ParameterizedType[T]"
+
+# remove the most specific one
+proc d(x: ParameterizedType) =
+  echo "x as ParameterizedType"
+
+proc d(x: CustomTypeClass) =
+  echo "x as CustomTypeClass"
+
+# then shuffle the order again
+proc e(x: CustomTypeClass) =
+  echo "x as CustomTypeClass"
+
+proc e(x: ParameterizedType) =
+  echo "x as ParameterizedType"
+
+# the least specific one is a match
+proc f(x: CustomTypeClass) =
+  echo "x as CustomTypeClass"
+
+a(ParameterizedType[int]())
+b(ParameterizedType[int]())
+c(ParameterizedType[int]())
+d(ParameterizedType[int]())
+e(ParameterizedType[int]())
+f(ParameterizedType[int]())
+
diff --git a/tests/concepts/templatesinconcepts.nim b/tests/concepts/templatesinconcepts.nim
new file mode 100644
index 000000000..292b97ea6
--- /dev/null
+++ b/tests/concepts/templatesinconcepts.nim
@@ -0,0 +1,56 @@
+import typetraits
+
+template typeLen(x): int = x.type.name.len
+
+template bunchOfChecks(x) =
+  x.typeLen > 3
+  x != 10 is bool
+
+template stmtListExprTmpl(x: untyped): untyped =
+  x is int
+  x
+
+type
+  Obj = object
+    x: int
+
+  Gen[T] = object
+    x: T
+
+  Eq = concept x, y
+    (x == y) is bool
+
+  NotEq = concept x, y
+    (x != y) is bool
+
+  ConceptUsingTemplate1 = concept x
+    echo x
+    sizeof(x) is int
+    bunchOfChecks x
+
+  ConceptUsingTemplate2 = concept x
+    stmtListExprTmpl x
+
+template ok(x) =
+  static: assert(x)
+
+template no(x) =
+  static: assert(not(x))
+
+ok int is Eq
+ok int is NotEq
+ok string is Eq
+ok string is NotEq
+ok Obj is Eq
+ok Obj is NotEq
+ok Gen[string] is Eq
+ok Gen[int] is NotEq
+
+no int is ConceptUsingTemplate1
+ok float is ConceptUsingTemplate1
+no string is ConceptUsingTemplate1
+
+ok int is ConceptUsingTemplate2
+no float is ConceptUsingTemplate2
+no string is ConceptUsingTemplate2
+
diff --git a/tests/concepts/texplain.nim b/tests/concepts/texplain.nim
new file mode 100644
index 000000000..8cf04ae82
--- /dev/null
+++ b/tests/concepts/texplain.nim
@@ -0,0 +1,182 @@
+discard """
+  cmd: "nim c --verbosity:0 --colors:off $file"
+  nimout: '''
+texplain.nim(162, 10) Hint: Non-matching candidates for e(y)
+proc e(i: int): int
+  first type mismatch at position: 1
+  required type for i: int
+  but expression 'y' is of type: MatchingType
+
+texplain.nim(165, 7) Hint: Non-matching candidates for e(10)
+proc e(o: ExplainedConcept): int
+  first type mismatch at position: 1
+  required type for o: ExplainedConcept
+  but expression '10' is of type: int literal(10)
+texplain.nim(128, 6) ExplainedConcept: undeclared field: 'foo'
+texplain.nim(128, 5) ExplainedConcept: concept predicate failed
+texplain.nim(129, 6) ExplainedConcept: undeclared field: 'bar'
+texplain.nim(128, 5) ExplainedConcept: concept predicate failed
+
+texplain.nim(168, 10) Hint: Non-matching candidates for e(10)
+proc e(o: ExplainedConcept): int
+  first type mismatch at position: 1
+  required type for o: ExplainedConcept
+  but expression '10' is of type: int literal(10)
+texplain.nim(128, 6) ExplainedConcept: undeclared field: 'foo'
+texplain.nim(128, 5) ExplainedConcept: concept predicate failed
+texplain.nim(129, 6) ExplainedConcept: undeclared field: 'bar'
+texplain.nim(128, 5) ExplainedConcept: concept predicate failed
+
+texplain.nim(172, 20) Error: type mismatch: got <NonMatchingType>
+but expected one of:
+proc e(i: int): int
+  first type mismatch at position: 1
+  required type for i: int
+  but expression 'n' is of type: NonMatchingType
+proc e(o: ExplainedConcept): int
+  first type mismatch at position: 1
+  required type for o: ExplainedConcept
+  but expression 'n' is of type: NonMatchingType
+texplain.nim(172, 9) template/generic instantiation of `assert` from here
+texplain.nim(128, 5) ExplainedConcept: concept predicate failed
+
+expression: e(n)
+texplain.nim(173, 20) Error: type mismatch: got <NonMatchingType>
+but expected one of:
+proc r(i: string): int
+  first type mismatch at position: 1
+  required type for i: string
+  but expression 'n' is of type: NonMatchingType
+proc r(o: RegularConcept): int
+  first type mismatch at position: 1
+  required type for o: RegularConcept
+  but expression 'n' is of type: NonMatchingType
+texplain.nim(173, 9) template/generic instantiation of `assert` from here
+texplain.nim(132, 5) RegularConcept: concept predicate failed
+proc r[T](a: SomeNumber; b: T; c: auto)
+  first type mismatch at position: 1
+  required type for a: SomeNumber
+  but expression 'n' is of type: NonMatchingType
+
+expression: r(n)
+texplain.nim(174, 20) Hint: Non-matching candidates for r(y)
+proc r(i: string): int
+  first type mismatch at position: 1
+  required type for i: string
+  but expression 'y' is of type: MatchingType
+proc r[T](a: SomeNumber; b: T; c: auto)
+  first type mismatch at position: 1
+  required type for a: SomeNumber
+  but expression 'y' is of type: MatchingType
+
+texplain.nim(182, 2) Error: type mismatch: got <MatchingType>
+but expected one of:
+proc f(o: NestedConcept)
+  first type mismatch at position: 1
+  required type for o: NestedConcept
+  but expression 'y' is of type: MatchingType
+texplain.nim(132, 6) RegularConcept: undeclared field: 'foo'
+texplain.nim(132, 5) RegularConcept: concept predicate failed
+texplain.nim(133, 6) RegularConcept: undeclared field: 'bar'
+texplain.nim(132, 5) RegularConcept: concept predicate failed
+texplain.nim(136, 5) NestedConcept: concept predicate failed
+
+expression: f(y)'''
+  errormsg: "type mismatch: got <MatchingType>"
+"""
+
+
+
+# proc r[T](a: SomeNumber; b: T; c: auto)
+# proc r(i: string): int
+# proc r(o: RegularConcept): int
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# line 124 HERE
+
+type
+  ExplainedConcept {.explain.} = concept o
+    o.foo is int
+    o.bar is string
+
+  RegularConcept = concept o
+    o.foo is int
+    o.bar is string
+
+  NestedConcept = concept o
+    o.foo is RegularConcept
+
+  NonMatchingType = object
+    foo: int
+    bar: int
+
+  MatchingType = object
+    foo: int
+    bar: string
+
+proc e(o: ExplainedConcept): int = 1
+proc e(i: int): int = i
+
+proc r[T](a: SomeNumber, b: T, c: auto) = discard
+proc r(o: RegularConcept): int = 1
+proc r(i: string): int = 1
+
+proc f(o: NestedConcept) = discard
+
+var n = NonMatchingType(foo: 10, bar: 20)
+var y = MatchingType(foo: 10, bar: "bar")
+
+# no diagnostic here:
+discard e(y)
+
+# explain that e(int) doesn't match
+discard e(y) {.explain.}
+
+# explain that e(ExplainedConcept) doesn't match
+echo(e(10) {.explain.}, 20)
+
+# explain that e(ExplainedConcept) doesn't again
+discard e(10)
+
+static:
+  # provide diagnostics why the compile block failed
+  assert(compiles(e(n)) {.explain.} == false)
+  assert(compiles(r(n)) {.explain.} == false)
+  assert(compiles(r(y)) {.explain.} == true)
+
+  # these should not produce any output
+  assert(compiles(r(10)) == false)
+  assert(compiles(e(10)) == true)
+
+# finally, provide multiple nested explanations for failed matching
+# of regular concepts, even when the explain pragma is not used
+f(y)
diff --git a/tests/concepts/titerable.nim b/tests/concepts/titerable.nim
new file mode 100644
index 000000000..b18658b2a
--- /dev/null
+++ b/tests/concepts/titerable.nim
@@ -0,0 +1,20 @@
+discard """
+  nimout: "int\nint"
+  output: 15
+"""
+
+import typetraits
+
+type
+  Iterable[T] = concept x
+    for value in x:
+      type(value) is T
+
+proc sum*[T](iter: Iterable[T]): T =
+  static: echo T.name
+  for element in iter:
+    static: echo element.type.name
+    result += element
+
+echo sum([1, 2, 3, 4, 5])
+
diff --git a/tests/concepts/tmanual.nim b/tests/concepts/tmanual.nim
new file mode 100644
index 000000000..c917f5022
--- /dev/null
+++ b/tests/concepts/tmanual.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+6
+a
+b
+t
+e
+s
+t
+'''
+"""
+
+template accept(e) =
+  static: assert compiles(e)
+
+template reject(e) =
+  static: assert(not compiles(e))
+
+type
+  Container[T] = concept c
+    c.len is Ordinal
+    items(c) is T
+    for value in c:
+      type(value) is T
+
+proc takesIntContainer(c: Container[int]) =
+  for e in c: echo e
+
+takesIntContainer(@[1, 2, 3])
+reject takesIntContainer(@["x", "y"])
+
+proc takesContainer(c: Container) =
+  for e in c: echo e
+
+takesContainer(@[4, 5, 6])
+takesContainer(@["a", "b"])
+takesContainer "test"
+reject takesContainer(10)
diff --git a/tests/concepts/tmapconcept.nim b/tests/concepts/tmapconcept.nim
new file mode 100644
index 000000000..cc99737df
--- /dev/null
+++ b/tests/concepts/tmapconcept.nim
@@ -0,0 +1,102 @@
+discard """
+output: '''10
+10
+
+1'''
+nimout: '''
+K=string V=int
+K=int64 V=string
+K=int V=int
+'''
+"""
+
+import tables, typetraits
+
+template ok(check) = assert check
+template no(check) = assert(not check)
+
+type
+  Enumerable[T] = concept e
+    for v in e:
+      v is T
+
+  Map[K, V] = concept m, var mvar
+    m[K] is V
+    mvar[K] = V
+    m.contains(K) is bool
+    m.valuesSeq is Enumerable[V]
+
+  TreeMap[K, V] = object
+    root: int
+
+  SparseSeq = object
+    data: seq[int]
+
+  JudyArray = object
+    data: SparseSeq
+
+static:
+  ok seq[int] is Enumerable[int]
+  ok seq[string] is Enumerable
+  ok seq[int] is Enumerable[SomeNumber]
+  ok SparseSeq.data is Enumerable
+  no seq[string] is Enumerable[int]
+  no int is Enumerable
+  no int is Enumerable[int]
+
+# Complete the map concept implementation for the Table type
+proc valuesSeq[K, V](t: Table[K, V]): seq[V]  =
+  result = @[]
+  for k, v in t:
+    result.add v
+
+# Map concept inplementation for TreeMap
+proc valuesSeq(t: TreeMap): array[1, TreeMap.V] =
+  var v: t.V
+  result = [v]
+
+proc contains[K, V](t: TreeMap[K, V], key: K): bool = true
+
+proc `[]=`[K, V](t: var TreeMap[K, V], key: K, val: V) = discard
+proc `[]`(t: TreeMap, key: t.K): TreeMap.V = discard
+
+# Map concept implementation for the non-generic JudyArray
+proc valuesSeq(j: JudyArray): SparseSeq = j.data
+
+proc contains(t: JudyArray, key: int): bool = true
+
+proc `[]=`(t: var JudyArray, key, val: int) = discard
+proc `[]`(t: JudyArray, key: int): int = discard
+
+iterator items(s: SparseSeq): int =
+  for i in s.data: yield i
+
+# Generic proc defined over map
+proc getFirstValue[K,V](m : Map[K,V]): V =
+  static: echo "K=", K.name, " V=", V.name
+
+  for i in m.valuesSeq:
+    return i
+
+  raise newException(RangeDefect, "no values")
+
+proc useConceptProcInGeneric[K, V](t: Table[K, V]): V =
+  return t.getFirstValue
+
+var t = initTable[string, int]()
+t["test"] = 10
+
+echo t.getFirstValue
+echo t.useConceptProcInGeneric
+
+var tm = TreeMap[int64, string](root: 0)
+echo getFirstValue(tm)
+
+var j = JudyArray(data: SparseSeq(data: @[1, 2, 3]))
+echo getFirstValue(j)
+
+static:
+  ok Table[int, float] is Map
+  ok Table[int, string] is Map[SomeNumber, string]
+  no JudyArray is Map[string, int]
+
diff --git a/tests/concepts/tmatrixconcept.nim b/tests/concepts/tmatrixconcept.nim
new file mode 100644
index 000000000..ca31f5942
--- /dev/null
+++ b/tests/concepts/tmatrixconcept.nim
@@ -0,0 +1,81 @@
+discard """
+output: "0\n0\n0"
+nimout: '''
+R=3 C=3 TE=9 FF=14 FC=20 T=int
+R=3 C=3 T=int
+'''
+"""
+
+import typetraits
+
+template ok(x) = assert x
+template no(x) = assert(not x)
+
+const C = 10
+
+type
+  Matrix[Rows, Cols, TotalElements, FromFoo, FromConst: static[int]; T] = concept m, var mvar, type M
+    M.M == Rows
+    Cols == M.N
+    M.T is T
+
+    m[int, int] is T
+    mvar[int, int] = T
+
+    FromConst == C * 2
+
+    # more complicated static param inference cases
+    m.data is array[TotalElements, T]
+    m.foo(array[0..FromFoo, type m[int, 10]])
+
+  MyMatrix[M, K: static[int]; T] = object
+    data: array[M*K, T]
+
+# adaptor for the concept's non-matching expectations
+template N(M: type MyMatrix): untyped = M.K
+
+proc `[]`(m: MyMatrix; r, c: int): m.T =
+  m.data[r * m.K + c]
+
+proc `[]=`(m: var MyMatrix; r, c: int, v: m.T) =
+  m.data[r * m.K + c] = v
+
+proc foo(x: MyMatrix, arr: array[15, x.T]) = discard
+
+proc genericMatrixProc[R, C, TE, FF, FC, T](m: Matrix[R, C, TE, FF, FC, T]): T =
+  static:
+    echo "R=", R, " C=", C, " TE=", TE, " FF=", FF, " FC=", FC, " T=", T.name
+
+  m[0, 0]
+
+proc implicitMatrixProc(m: Matrix): m.T =
+  static:
+    echo "R=", m.Rows,
+        " C=", m.Cols,
+        # XXX: fix these
+        #" TE=", m.TotalElements,
+        #" FF=", m.FromFoo,
+        #" FC=", m.FromConst,
+        " T=", m.T.name
+
+  m[0, 0]
+
+proc myMatrixProc(x: MyMatrix): MyMatrix.T = genericMatrixProc(x)
+
+var x: MyMatrix[3, 3, int]
+
+static:
+  # ok x is Matrix
+  ok x is Matrix[3, 3, 9, 14, 20, int]
+
+  no x is Matrix[3, 3, 8, 15, 20, int]
+  no x is Matrix[3, 3, 9, 10, 20, int]
+  no x is Matrix[3, 3, 9, 15, 21, int]
+  no x is Matrix[3, 3, 9, 15, 20, float]
+  no x is Matrix[4, 3, 9, 15, 20, int]
+  no x is Matrix[3, 4, 9, 15, 20, int]
+
+echo x.myMatrixProc
+echo x.genericMatrixProc
+echo x.implicitMatrixProc
+
diff --git a/tests/concepts/tmatrixlib.nim b/tests/concepts/tmatrixlib.nim
new file mode 100644
index 000000000..a4ab04061
--- /dev/null
+++ b/tests/concepts/tmatrixlib.nim
@@ -0,0 +1,31 @@
+discard """
+output: "0"
+"""
+
+import matrix, matrixalgo
+
+import typetraits # XXX: this should be removed
+
+var m: Matrix[3, 3, int]
+var projectionMatrix: Matrix[4, 4, float]
+
+echo m.transposed.determinant
+setPerspectiveProjection projectionMatrix
+
+template ok(x) = assert x
+template no(x) = assert(not x)
+
+static:
+  ok projectionMatrix is AnyTransform3D
+  no m is AnyTransform3D
+  
+  type SquareStringMatrix = Matrix[5, 5, string]
+  
+  ok SquareStringMatrix is AnyMatrix
+  ok SquareStringMatrix is AnySquareMatrix
+  no SquareStringMatrix is AnyTransform3D
+  
+  ok Matrix[5, 10, int] is AnyMatrix
+  no Matrix[7, 15, float] is AnySquareMatrix
+  no Matrix[4, 4, int] is AnyTransform3D
+
diff --git a/tests/concepts/tmodifiersinplace.nim b/tests/concepts/tmodifiersinplace.nim
new file mode 100644
index 000000000..db5583929
--- /dev/null
+++ b/tests/concepts/tmodifiersinplace.nim
@@ -0,0 +1,30 @@
+type
+  VarContainer[T] = concept c
+    put(var c, T)
+
+  AltVarContainer[T] = concept var c
+    put(c, T)
+
+  NonVarContainer[T] = concept c
+    put(c, T)
+
+  GoodContainer = object
+    x: int
+
+  BadContainer = object
+    x: int
+
+proc put(x: BadContainer, y: int) = discard
+proc put(x: var GoodContainer, y: int) = discard
+
+template ok(x) = assert(x)
+template no(x) = assert(not(x))
+
+static:
+  ok GoodContainer is VarContainer[int]
+  ok GoodContainer is AltVarContainer[int]
+  no BadContainer is VarContainer[int]
+  no BadContainer is AltVarContainer[int]
+  ok GoodContainer is NonVarContainer[int]
+  ok BadContainer is NonVarContainer[int]
+
diff --git a/tests/concepts/tmonoid.nim b/tests/concepts/tmonoid.nim
new file mode 100644
index 000000000..e0e19adbc
--- /dev/null
+++ b/tests/concepts/tmonoid.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''true'''
+"""
+
+# bug #3686
+
+type Monoid = concept x, y
+  x + y is type(x)
+  type(z(type(x))) is type(x)
+
+proc z(x: typedesc[int]): int = 0
+
+echo(int is Monoid)
+
+# https://github.com/nim-lang/Nim/issues/8126
+type AdditiveMonoid* = concept x, y, type T
+  x + y is T
+
+  # some redundant checks to test an alternative approaches:
+  type TT = type(x)
+  x + y is type(x)
+  x + y is TT
+
+doAssert(1 is AdditiveMonoid)
+
diff --git a/tests/concepts/trandomvars.nim b/tests/concepts/trandomvars.nim
new file mode 100644
index 000000000..1f04b9ecf
--- /dev/null
+++ b/tests/concepts/trandomvars.nim
@@ -0,0 +1,63 @@
+discard """
+output: '''
+true
+true
+true
+3
+18.0
+324.0
+'''
+"""
+
+type RNG = object
+
+proc random(rng: var RNG): float = 1.0
+
+type
+  RandomVar[A] = concept x
+    var rng: RNG
+    rng.sample(x) is A
+
+  Constant[A] = object
+    value: A
+
+  Uniform = object
+    a, b: float
+
+  ClosureVar[A] = proc(rng: var RNG): A
+
+proc sample[A](rng: var RNG, c: Constant[A]): A = c.value
+
+proc sample(rng: var RNG, u: Uniform): float = u.a + (u.b - u.a) * rng.random()
+
+proc sample[A](rng: var RNG, c: ClosureVar[A]): A = c(rng)
+
+proc constant[A](a: A): Constant[A] = Constant[A](value: a)
+
+proc uniform(a, b: float): Uniform = Uniform(a: a, b: b)
+
+proc lift1[A, B](f: proc(a: A): B, r: RandomVar[A]): ClosureVar[B] =
+  proc inner(rng: var RNG): B = f(rng.sample(r))
+
+  return inner
+
+
+proc main() =
+  proc sq(x: float): float = x * x
+
+  let
+    c = constant(3)
+    u = uniform(2, 18)
+    t = lift1(sq, u)
+
+  var rng: RNG
+
+  echo(c is RandomVar[int])
+  echo(u is RandomVar[float])
+  echo(t is RandomVar[float])
+
+  echo rng.sample(c)
+  echo rng.sample(u)
+  echo rng.sample(t)
+
+main()
diff --git a/tests/concepts/trandomvars2.nim b/tests/concepts/trandomvars2.nim
new file mode 100644
index 000000000..861e876a7
--- /dev/null
+++ b/tests/concepts/trandomvars2.nim
@@ -0,0 +1,42 @@
+discard """
+output: "11.0"
+"""
+
+type
+  # A random number generator
+  Random = object
+    random: proc(): float
+  # A generic typeclass for a random var
+  RandomVar[A] = concept x
+    var rng: Random
+    rng.sample(x) is A
+  # A few concrete instances
+  Uniform = object
+    a, b: float
+  ClosureVar[A] = object
+    f: proc(rng: var Random): A
+
+# How to sample from various concrete instances
+proc sample(rng: var Random, u: Uniform): float = u.a + (u.b - u.a) * rng.random()
+
+proc sample[A](rng: var Random, c: ClosureVar[A]): A = c.f(rng)
+
+proc uniform(a, b: float): Uniform = Uniform(a: a, b: b)
+
+# How to lift a function on values to a function on random variables
+proc map[A, B](x: RandomVar[A], f: proc(a: A): B): ClosureVar[B] =
+  proc inner(rng: var Random): B =
+    f(rng.sample(x))
+
+  result.f = inner
+
+import sugar
+
+proc fakeRandom(): Random =
+  result.random = () => 0.5
+
+let x = uniform(1, 10).map((x: float) => 2 * x)
+
+var rng = fakeRandom()
+
+echo rng.sample(x)
diff --git a/tests/concepts/treversable.nim b/tests/concepts/treversable.nim
new file mode 100644
index 000000000..d30ba0a3c
--- /dev/null
+++ b/tests/concepts/treversable.nim
@@ -0,0 +1,31 @@
+# issue 7705, 7703, 7702
+discard """
+  output: '''
+z
+e
+'''
+"""
+
+type
+  Reversable*[T] = concept a
+    a[int] is T
+    a.high is int
+    a.len is int
+    a.low is int
+
+proc get[T](s: Reversable[T], n: int): T =
+  s[n]
+
+proc hi[T](s: Reversable[T]): int =
+  s.high
+
+proc lo[T](s: Reversable[T]): int =
+  s.low
+
+iterator reverse*[T](s: Reversable[T]): T =
+  assert hi(s) - lo(s) == len(s) - 1
+  for z in hi(s).countdown(lo(s)):
+    yield s.get(z)
+
+for s in @["e", "z"].reverse:
+  echo s
diff --git a/tests/concepts/tseqofconcept.nim b/tests/concepts/tseqofconcept.nim
new file mode 100644
index 000000000..5e44117ea
--- /dev/null
+++ b/tests/concepts/tseqofconcept.nim
@@ -0,0 +1,19 @@
+discard """
+output: "1\n2\n3"
+"""
+
+type
+  MyConcept = concept x
+    someProc(x)
+
+  SomeSeq = seq[MyConcept]
+
+proc someProc(x:int) = echo x
+
+proc work (s: SomeSeq) =
+  for item in s:
+    someProc item
+
+var s = @[1, 2, 3]
+work s
+
diff --git a/tests/concepts/tspec.nim b/tests/concepts/tspec.nim
new file mode 100644
index 000000000..52f13a40a
--- /dev/null
+++ b/tests/concepts/tspec.nim
@@ -0,0 +1,105 @@
+discard """
+  output: '''4
+0
+4
+4
+1
+2
+3
+yes int
+string int'''
+  joinable: false
+"""
+
+import hashes
+
+type
+  Comparable = concept # no T, an atom
+    proc cmp(a, b: Self): int
+
+  ToStringable = concept
+    proc `$`(a: Self): string
+
+  Hashable = concept   ## the most basic of identity assumptions
+    proc hash(x: Self): int
+    proc `==`(x, y: Self): bool
+
+  Swapable = concept
+    proc swap(x, y: var Self)
+
+
+proc h(x: Hashable) =
+  echo x
+
+h(4)
+
+when true:
+  proc compare(a: Comparable) =
+    echo cmp(a, a)
+
+  compare(4)
+
+proc dollar(x: ToStringable) =
+  echo x
+
+when true:
+  dollar 4
+  dollar "4"
+
+#type D = distinct int
+
+#dollar D(4)
+
+when true:
+  type
+    Iterable[Ix] = concept
+      iterator items(c: Self): Ix
+
+  proc g[Tu](it: Iterable[Tu]) =
+    for x in it:
+      echo x
+
+  g(@[1, 2, 3])
+
+proc hs(x: Swapable) =
+  var y = x
+  swap y, y
+
+hs(4)
+
+type
+  Indexable[T] = concept # has a T, a collection
+    proc `[]`(a: Self; index: int): T # we need to describe how to infer 'T'
+    # and then we can use the 'T' and it must match:
+    proc `[]=`(a: var Self; index: int; value: T)
+    proc len(a: Self): int
+
+proc indexOf[T](a: Indexable[T]; value: T) =
+  echo "yes ", T
+
+block:
+  var x = @[1, 2, 3]
+  indexOf(x, 4)
+
+import tables, typetraits
+
+type
+  Dict[K, V] = concept
+    proc `[]`(s: Self; k: K): V
+    proc `[]=`(s: var Self; k: K; v: V)
+
+proc d[K2, V2](x: Dict[K2, V2]) =
+  echo K2, " ", V2
+
+var x = initTable[string, int]()
+d(x)
+
+
+type Monoid = concept
+  proc `+`(x, y: Self): Self
+  proc z(t: typedesc[Self]): Self
+
+proc z(x: typedesc[int]): int = 0
+
+doAssert int is Monoid
+
diff --git a/tests/concepts/tstackconcept.nim b/tests/concepts/tstackconcept.nim
new file mode 100644
index 000000000..fb6032732
--- /dev/null
+++ b/tests/concepts/tstackconcept.nim
@@ -0,0 +1,62 @@
+discard """
+output: "20\n10"
+nimout: '''
+INFERRED int
+VALUE TYPE int
+VALUE TYPE NAME INT
+IMPLICIT INFERRED int int
+IMPLICIT VALUE TYPE int int
+IMPLICIT VALUE TYPE NAME INT INT
+'''
+"""
+
+import typetraits, strutils
+
+template reject(e) =
+  static: assert(not compiles(e))
+
+type
+  ArrayStack = object
+    data: seq[int]
+
+proc push(s: var ArrayStack, item: int) =
+  s.data.add item
+
+proc pop(s: var ArrayStack): int =
+  return s.data.pop()
+
+type
+  Stack[T] = concept var s
+    s.push(T)
+    s.pop() is T
+
+    type ValueType = T
+    const ValueTypeName = T.name.toUpperAscii
+
+proc genericAlgorithm[T](s: var Stack[T], y: T) =
+  static:
+    echo "INFERRED ", T.name
+    echo "VALUE TYPE ", s.ValueType.name
+    echo "VALUE TYPE NAME ", s.ValueTypeName
+
+  s.push(y)
+  echo s.pop
+
+proc implicitGeneric(s: var Stack): auto =
+  static:
+    echo "IMPLICIT INFERRED ", s.T.name, " ", Stack.T.name
+    echo "IMPLICIT VALUE TYPE ", s.ValueType.name, " ", Stack.ValueType.name
+    echo "IMPLICIT VALUE TYPE NAME ", s.ValueTypeName, " ", Stack.ValueTypeName
+
+  return s.pop()
+
+var s = ArrayStack(data: @[])
+
+s.push 10
+s.genericAlgorithm 20
+echo s.implicitGeneric
+
+reject s.genericAlgorithm "x"
+reject s.genericAlgorithm 1.0
+reject "str".implicitGeneric
+reject implicitGeneric(10)
diff --git a/tests/concepts/tswizzle.nim b/tests/concepts/tswizzle.nim
new file mode 100644
index 000000000..07205d454
--- /dev/null
+++ b/tests/concepts/tswizzle.nim
@@ -0,0 +1,80 @@
+discard """
+  output: '''3
+[1, 3]
+[2, 1, 2]
+'''
+  disabled: "true"
+"""
+
+import macros, strutils
+
+template accept(e: expr) =
+  static: assert(compiles(e))
+
+template reject(e: expr) =
+  static: assert(not compiles(e))
+
+proc swizzleIdx(c: char): int =
+  return case c
+    of 'x': 0
+    of 'y': 1
+    of 'z': 2
+    of 'w': 3
+    of 'r': 0
+    of 'g': 1
+    of 'b': 2
+    of 'a': 3
+    else: 0
+
+proc isSwizzle(s: string): bool {.compileTime.} =
+  template trySet(name, set) =
+    block search:
+      for c in s:
+        if c notin set:
+          break search
+      return true
+
+  trySet coords, {'x', 'y', 'z', 'w'}
+  trySet colors, {'r', 'g', 'b', 'a'}
+
+  return false
+
+type
+  StringIsSwizzle = concept value
+    value.isSwizzle
+
+  SwizzleStr = static[string] and StringIsSwizzle
+
+proc foo(x: SwizzleStr) =
+  echo "sw"
+
+#foo("xx")
+reject foo("xe")
+
+type
+  Vec[N: static[int]; T] = array[N, T]
+
+when false:
+  proc card(x: Vec): int = x.N
+  proc `$`(x: Vec): string = x.repr.strip
+
+  macro `.`(x: Vec, swizzle: SwizzleStr): expr =
+    var
+      cardinality = swizzle.len
+      values = newNimNode(nnkBracket)
+      v = genSym()
+
+    for c in swizzle:
+      values.add newNimNode(nnkBracketExpr).add(
+        v, c.swizzleIdx.newIntLitNode)
+
+    return quote do:
+      let `v` = `x`
+      Vec[`cardinality`, `v`.T](`values`)
+
+var z = Vec([1, 2, 3])
+
+#echo z.card
+#echo z.xz
+#echo z.yxy
+
diff --git a/tests/concepts/ttrieconcept.nim b/tests/concepts/ttrieconcept.nim
new file mode 100644
index 000000000..a26e6b146
--- /dev/null
+++ b/tests/concepts/ttrieconcept.nim
@@ -0,0 +1,7 @@
+import libs/[trie_database, trie]
+
+proc takeDb(d: TrieDatabase) = discard
+var mdb: MemDB
+
+takeDb(mdb)
+
diff --git a/tests/concepts/tusertypeclasses.nim b/tests/concepts/tusertypeclasses.nim
new file mode 100644
index 000000000..83e2b176e
--- /dev/null
+++ b/tests/concepts/tusertypeclasses.nim
@@ -0,0 +1,131 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''Sortable
+Sortable
+Container
+TObj
+int
+111 111
+(id: @[1, 2, 3], name: @["Vas", "Pas", "NafNaf"], age: @[10, 16, 18])
+'''
+"""
+
+# todo wait for https://github.com/nim-lang/Nim/pull/20380
+
+import typetraits
+
+template reject(expr) = assert(not compiles(x))
+
+type
+  TObj = object
+    x: int
+
+  JSonValue = object
+    val: string
+
+  Sortable = concept x, y
+    (x < y) is bool
+
+  ObjectContainer = concept C
+    C.len is Ordinal
+    for v in items(C):
+      v.type is tuple|object
+
+proc foo(c: ObjectContainer) =
+  echo "Container"
+
+proc foo(x: Sortable) =
+  echo "Sortable"
+
+foo 10
+foo "test"
+foo(@[TObj(x: 10), TObj(x: 20)])
+
+proc intval(x: int): int = 10
+
+type
+  TFoo = concept o, type T, ref r, var v, ptr p, static s
+    o.x
+    y(o) is int
+
+    var str: string
+    var intref: ref int
+
+    refproc(ref T, ref int)
+    varproc(var T)
+    ptrproc(ptr T, str)
+
+    staticproc(static[T])
+
+    typeproc T
+    T.typeproc
+    typeproc o.type
+    o.type.typeproc
+
+    o.to(type string)
+    o.to(type JsonValue)
+
+    refproc(r, intref)
+    varproc(v)
+    p.ptrproc(string)
+    staticproc s
+    typeproc(T)
+
+    const TypeName = T.name
+    type MappedType = type(o.y)
+
+    intval y(o)
+    let z = intval(o.y)
+
+    static:
+      assert T.name.len == 4
+      reject o.name
+      reject o.typeproc
+      reject staticproc(o)
+      reject o.varproc
+      reject T.staticproc
+      reject p.staticproc
+
+proc y(x: TObj): int = 10
+
+proc varproc(x: var TObj) = discard
+proc refproc(x: ref TObj, y: ref int) = discard
+proc ptrproc(x: ptr TObj, y: string) = discard
+proc staticproc(x: static[TObj]) = discard
+proc typeproc(t: type TObj) = discard
+proc to(x: TObj, t: type string) = discard
+proc to(x: TObj, t: type JSonValue) = discard
+
+proc testFoo(x: TFoo) =
+  echo x.TypeName
+  echo x.MappedType.name
+
+testFoo(TObj(x: 10))
+
+# bug #7092
+
+type stringTest = concept x
+  x is string
+
+let usedToFail: stringTest = "111"
+let working: string = "111"
+
+echo usedToFail, " ", working
+
+# bug #5868
+
+type TaggedType[T; Key: static[string]] = T
+
+proc setKey*[DT](dt: DT, key: static[string]): TaggedType[DT, key] =
+  result = cast[type(result)](dt)
+
+type Students = object
+   id : seq[int]
+   name : seq[string]
+   age: seq[int]
+
+let
+  stud = Students(id : @[1,2,3], name : @["Vas", "Pas", "NafNaf"], age : @[10,16,18])
+  stud2 = stud.setkey("id")
+
+echo stud2
diff --git a/tests/concepts/tusertypeclasses2.nim b/tests/concepts/tusertypeclasses2.nim
new file mode 100644
index 000000000..6132bc2d8
--- /dev/null
+++ b/tests/concepts/tusertypeclasses2.nim
@@ -0,0 +1,63 @@
+discard """
+  targets: "c js"
+"""
+
+block:
+  type
+    hasFieldX = concept z
+      z.x is int
+
+    obj_x = object
+      x: int
+
+    ref_obj_x = ref object
+      x: int
+
+    ref_to_obj_x = ref obj_x
+
+    p_o_x = ptr obj_x
+    v_o_x = var obj_x
+
+  template check(x) =
+    static: assert(x)
+
+  check obj_x is hasFieldX
+  check ref_obj_x is hasFieldX
+  check ref_to_obj_x is hasFieldX
+  check p_o_x is hasFieldX
+  check v_o_x is hasFieldX
+
+block:
+  type
+    Foo = concept x
+      x.isFoo
+    Bar = distinct float
+  template isFoo(x: Bar): untyped = true
+  proc foo(x: var Foo) =
+    float(x) = 1.0
+  proc foo2(x: var Bar) =
+    float(x) = 1.0
+  proc foo3(x: var (Bar|SomeNumber)) =
+    float(x) = 1.0
+  proc foo4(x: var any) =
+    float(x) = 1.0
+  var x: Bar
+  foo(x)
+  foo2(x)
+  foo3(x)
+  foo4(x)
+
+block: # bug #9550
+  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']
+
+  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/concepts/tvarconcept.nim b/tests/concepts/tvarconcept.nim
new file mode 100644
index 000000000..203ef3cdc
--- /dev/null
+++ b/tests/concepts/tvarconcept.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "5"
+"""
+
+# bug #2346, bug #2404
+
+import mvarconcept
+
+echo randomInt(5)
diff --git a/tests/concepts/tvectorspace.nim b/tests/concepts/tvectorspace.nim
new file mode 100644
index 000000000..7a18c1762
--- /dev/null
+++ b/tests/concepts/tvectorspace.nim
@@ -0,0 +1,19 @@
+discard """
+  joinable: false
+"""
+
+type VectorSpace[K] = concept x, y
+  x + y is type(x)
+  zero(type(x)) is type(x)
+  -x is type(x)
+  x - y is type(x)
+  var k: K
+  k * x is type(x)
+
+proc zero(T: typedesc): T = 0
+
+static:
+  assert float is VectorSpace[float]
+  # assert float is VectorSpace[int]
+  # assert int is VectorSpace
+
diff --git a/tests/concepts/twrapconcept.nim b/tests/concepts/twrapconcept.nim
new file mode 100644
index 000000000..c3dea2ff9
--- /dev/null
+++ b/tests/concepts/twrapconcept.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "type mismatch: got <string>"
+  nimout: "twrapconcept.nim(10, 5) Foo: concept predicate failed"
+"""
+
+# https://github.com/nim-lang/Nim/issues/5127
+
+type
+  Foo = concept foo
+    foo.get is int
+
+  FooWrap[F: Foo] = object
+    foo: F
+
+proc get(x: int): int = x
+
+proc wrap[F: Foo](foo: F): FooWrap[F] = FooWrap[F](foo: foo)
+
+let x = wrap(12)
+let y = wrap "string"
+
diff --git a/tests/config.nims b/tests/config.nims
new file mode 100644
index 000000000..0b2b66d81
--- /dev/null
+++ b/tests/config.nims
@@ -0,0 +1,49 @@
+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")
+
+switch("define", "nimLegacyTypeMismatch")
+
+hint("Processing", off)
+  # dots can cause annoyances; instead, a single test can test `hintProcessing`
+
+# uncomment to enable all flaky tests disabled by this flag
+# (works through process calls, e.g. tests that invoke nim).
+# switch("define", "nimTestsEnableFlaky")
+
+# switch("hint", "ConvFromXtoItselfNotNeeded")
+# switch("warningAsError", "InheritFromException") # would require fixing a few tests
+
+# experimental APIs are enabled in testament, refs https://github.com/timotheecour/Nim/issues/575
+# sync with `kochdocs.docDefines` or refactor.
+switch("define", "nimExperimentalLinenoiseExtra")
+
+# preview APIs are expected to be the new default in upcoming versions
+switch("define", "nimPreviewFloatRoundtrip")
+#switch("define", "nimPreviewDotLikeOps") # deprecated?
+switch("define", "nimPreviewJsonutilsHoleyEnum")
+switch("define", "nimPreviewHashRef")
+switch("define", "nimPreviewRangeDefault")
+switch("define", "nimPreviewNonVarDestructor")
+
+switch("warningAserror", "UnnamedBreak")
+when not defined(testsConciseTypeMismatch):
+  switch("legacy", "verboseTypeMismatch")
+switch("experimental", "vtables")
+switch("experimental", "openSym")
diff --git a/tests/constructors/a.nim b/tests/constructors/a.nim
new file mode 100644
index 000000000..03788fc57
--- /dev/null
+++ b/tests/constructors/a.nim
@@ -0,0 +1,2 @@
+type A* = object
+  a: uint8
\ No newline at end of file
diff --git a/tests/constructors/b.nim b/tests/constructors/b.nim
new file mode 100644
index 000000000..437dd0550
--- /dev/null
+++ b/tests/constructors/b.nim
@@ -0,0 +1,2 @@
+type B* = object
+proc A*(a, b: float): B = discard
\ No newline at end of file
diff --git a/tests/constructors/t18990.nim b/tests/constructors/t18990.nim
new file mode 100644
index 000000000..2f60f3c2c
--- /dev/null
+++ b/tests/constructors/t18990.nim
@@ -0,0 +1,3 @@
+import a, b
+discard A(1f, 1f) # works
+proc x(b = A(1f, 1f)) = discard # doesn't work
\ No newline at end of file
diff --git a/tests/constructors/t5965_1.nim b/tests/constructors/t5965_1.nim
new file mode 100644
index 000000000..abf07b21c
--- /dev/null
+++ b/tests/constructors/t5965_1.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "incorrect object construction syntax"
+  file: "t5965_1.nim"
+  line: 10
+"""
+
+type Foo = object
+  a, b, c: int
+
+discard Foo(a: 1, 2)
diff --git a/tests/constructors/t5965_2.nim b/tests/constructors/t5965_2.nim
new file mode 100644
index 000000000..e04f1b715
--- /dev/null
+++ b/tests/constructors/t5965_2.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "incorrect object construction syntax"
+  file: "t5965_2.nim"
+  line: 10
+"""
+
+type Foo = object
+  a: int
+
+discard Foo(a: 1, 2)
diff --git a/tests/tconstr1.nim b/tests/constructors/tconstr1.nim
index 488170350..a169bf453 100755..100644
--- a/tests/tconstr1.nim
+++ b/tests/constructors/tconstr1.nim
@@ -1,23 +1,28 @@
-# Test array, record constructors

-

-type

-  TComplexRecord = tuple[

-    s: string,

-    x, y: int,

-    z: float,

-    chars: set[Char]]

-

-proc testSem =

-  var

-    things: array [0..1, TComplexRecord] = [

-      (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

-      (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a', 'b', 'c'})]

-  write(stdout, things[0].x)

-

-const

-  things: array [0..1, TComplexRecord] = [

-    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

-    (s: "hi", x: 69, y: 45, z: 1.0)] #ERROR

-  otherThings = [  # the same

-    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

-    (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]

+discard """
+  errormsg: "type mismatch"
+  file: "tconstr1.nim"
+  line: 25
+"""
+# Test array, record constructors
+
+type
+  TComplexRecord = tuple[
+    s: string,
+    x, y: int,
+    z: float,
+    chars: set[char]]
+
+proc testSem =
+  var
+    things: array[0..1, TComplexRecord] = [
+      (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
+      (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a', 'b', 'c'})]
+  write(stdout, things[0].x)
+
+const
+  things: array[0..1, TComplexRecord] = [
+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
+    (s: "hi", x: 69, y: 45, z: 1.0)] #ERROR
+  otherThings = [  # the same
+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
+    (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]
diff --git a/tests/tconstr2.nim b/tests/constructors/tconstr2.nim
index 7687a416c..2557d7db9 100755..100644
--- a/tests/tconstr2.nim
+++ b/tests/constructors/tconstr2.nim
@@ -1,20 +1,22 @@
-# Test array, record constructors

-

-type

-  TComplexRecord = tuple[

-    s: string,

-    x, y: int,

-    z: float,

-    chars: set[char]]

-

-const

-  things: array [0..1, TComplexRecord] = [

-    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

-    (s: "hi", x: 69, y: 45, z: 1.0, chars: {})] 

-  otherThings = [  # the same

-    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),

-    (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]

-

-write(stdout, things[0].x)

-#OUT 69

-

+discard """
+  output: "69"
+"""
+# Test array, record constructors
+
+type
+  TComplexRecord = tuple[
+    s: string,
+    x, y: int,
+    z: float,
+    chars: set[char]]
+
+const
+  things: array[0..1, TComplexRecord] = [
+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
+    (s: "hi", x: 69, y: 45, z: 1.0, chars: {})]
+  otherThings = [  # the same
+    (s: "hi", x: 69, y: 45, z: 0.0, chars: {'a', 'b', 'c'}),
+    (s: "hi", x: 69, y: 45, z: 1.0, chars: {'a'})]
+
+writeLine(stdout, things[0].x)
+#OUT 69
diff --git a/tests/constructors/tinvalid_construction.nim b/tests/constructors/tinvalid_construction.nim
new file mode 100644
index 000000000..4b372d68a
--- /dev/null
+++ b/tests/constructors/tinvalid_construction.nim
@@ -0,0 +1,439 @@
+template accept(x) =
+  static: assert compiles(x)
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+{.experimental: "notnil".}
+
+type
+  TRefObj = ref object
+    x: int
+
+  IllegalToConstruct = object
+    x: cstring not nil
+
+  THasNotNils = object of RootObj
+    a: TRefObj not nil
+    b: TRefObj not nil
+    c: TRefObj
+
+  THasNotNilsRef = ref THasNotNils
+
+  TRefObjNotNil = TRefObj not nil
+
+  TChoice = enum A, B, C, D, E, F
+
+  TBaseHasNotNils = object of THasNotNils
+    case choice: TChoice
+    of A:
+      moreNotNils: THasNotNils
+    of B:
+      indirectNotNils: ref THasNotNils
+    else:
+      discard
+
+  PartialRequiresInit = object
+    a {.requiresInit.}: int
+    b: string
+
+  PartialRequiresInitRef = ref PartialRequiresInit
+
+  FullRequiresInit {.requiresInit.} = object
+    a: int
+    b: int
+
+  FullRequiresInitRef = ref FullRequiresInit
+
+  FullRequiresInitWithParent {.requiresInit.} = object of THasNotNils
+    e: int
+    d: int
+
+  TObj = object
+    case choice: TChoice
+    of A:
+      a: int
+    of B, C:
+      bc: int
+    of D:
+      d: TRefObj
+    of E:
+      e1: TRefObj
+      e2: int
+    else:
+      f: string
+
+  TNestedChoices = object
+    case outerChoice: bool
+    of true:
+      truthy: int
+    else:
+      case innerChoice: TChoice
+      of A:
+        a: int
+      of B:
+        b: int
+      else:
+        notnil: TRefObj not nil
+
+var x = D
+var nilRef: TRefObj
+let notNilRef = TRefObjNotNil(x: 20)
+
+proc makeHasNotNils: ref THasNotNils =
+  (ref THasNotNils)(a: TRefObj(x: 10),
+                    b: TRefObj(x: 20))
+
+proc userDefinedDefault(T: typedesc): T =
+  # We'll use that to make sure the user cannot cheat
+  # with constructing requiresInit types
+  discard
+
+proc genericDefault(T: typedesc): T =
+  result = default(T)
+
+reject IllegalToConstruct()
+reject:
+  var x: IllegalToConstruct
+
+accept TObj()
+accept TObj(choice: A)
+reject TObj(choice: A, bc: 10)  # bc is in the wrong branch
+accept TObj(choice: B, bc: 20)
+reject TObj(a: 10)              # branch selected without providing discriminator
+reject TObj(choice: x, a: 10)   # the discrimantor must be a compile-time value when a branch is selected
+accept TObj(choice: x)          # it's OK to use run-time value when a branch is not selected
+accept TObj(choice: F, f: "")   # match an else clause
+reject TObj(f: "")              # the discriminator must still be provided for an else clause
+reject TObj(a: 10, f: "")       # conflicting fields
+accept TObj(choice: E, e1: TRefObj(x: 10), e2: 10)
+
+accept THasNotNils(a: notNilRef, b: notNilRef, c: nilRef)
+reject THasNotNils(a: notNilRef, b: nilRef, c: nilRef)      # `b` shouldn't be nil
+reject THasNotNils(b: notNilRef, c: notNilRef)              # there is a missing not nil field
+reject THasNotNils()                                        # again, missing fields
+accept THasNotNils(a: notNilRef, b: notNilRef)              # it's OK to omit a non-mandatory field
+# produces only warning: reject default(THasNotNils)
+# produces only warning: reject userDefinedDefault(THasNotNils)
+
+# produces only warning: reject default(TRefObjNotNil)
+# produces only warning: reject userDefinedDefault(TRefObjNotNil)
+# produces only warning: reject genericDefault(TRefObjNotNil)
+
+# missing not nils in base
+reject TBaseHasNotNils()
+# produces only warning: reject default(TBaseHasNotNils)
+# produces only warning: reject userDefinedDefault(TBaseHasNotNils)
+# produces only warning: reject genericDefault(TBaseHasNotNils)
+
+# once you take care of them, it's ok
+accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: D)
+
+# this one is tricky!
+# it has to be rejected, because choice gets value A by default (0) and this means
+# that the THasNotNils field will be active (and it will demand more initialized fields).
+reject TBaseHasNotNils(a: notNilRef, b: notNilRef)
+
+# you can select a branch without mandatory fields
+accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B)
+accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: nil)
+
+# but once you select a branch with mandatory fields, you must specify them
+reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A)
+reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A, indirectNotNils: nil)
+reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A, moreNotNils: THasNotNils())
+accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: A, moreNotNils: THasNotNils(a: notNilRef, b: notNilRef))
+
+# all rules apply to sub-objects as well
+accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: makeHasNotNils())
+reject TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: THasNotNilsRef())
+accept TBaseHasNotNils(a: notNilRef, b: notNilRef, choice: B, indirectNotNils: THasNotNilsRef(a: notNilRef, b: notNilRef))
+
+# Accept only instances where the `a` field is present
+accept PartialRequiresInit(a: 10, b: "x")
+accept PartialRequiresInit(a: 20)
+reject PartialRequiresInit(b: "x")
+reject PartialRequiresInit()
+accept PartialRequiresInitRef(a: 10, b: "x")
+accept PartialRequiresInitRef(a: 20)
+reject PartialRequiresInitRef(b: "x")
+reject PartialRequiresInitRef()
+accept((ref PartialRequiresInit)(a: 10, b: "x"))
+accept((ref PartialRequiresInit)(a: 20))
+reject((ref PartialRequiresInit)(b: "x"))
+reject((ref PartialRequiresInit)())
+
+# produces only warning: reject default(PartialRequiresInit)
+# produces only warning: reject userDefinedDefault(PartialRequiresInit)
+reject:
+  var obj: PartialRequiresInit
+
+accept FullRequiresInit(a: 10, b: 20)
+reject FullRequiresInit(a: 10)
+reject FullRequiresInit(b: 20)
+reject FullRequiresInit()
+accept FullRequiresInitRef(a: 10, b: 20)
+reject FullRequiresInitRef(a: 10)
+reject FullRequiresInitRef(b: 20)
+reject FullRequiresInitRef()
+accept((ref FullRequiresInit)(a: 10, b: 20))
+reject((ref FullRequiresInit)(a: 10))
+reject((ref FullRequiresInit)(b: 20))
+reject((ref FullRequiresInit)())
+
+# produces only warning: reject default(FullRequiresInit)
+# produces only warning: reject userDefinedDefault(FullRequiresInit)
+reject:
+  var obj: FullRequiresInit
+
+accept FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: notNilRef, e: 10, d: 20)
+accept FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10, d: 20)
+reject FullRequiresInitWithParent(a: notNilRef, b: nil, c: nil, e: 10, d: 20) # b should not be nil
+reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, e: 10, d: 20)   # c should not be missing
+reject FullRequiresInitWithParent(a: notNilRef, b: notNilRef, c: nil, e: 10)  # d should not be missing
+reject FullRequiresInitWithParent()
+# produces only warning: reject default(FullRequiresInitWithParent)
+# produces only warning: reject userDefinedDefault(FullRequiresInitWithParent)
+reject:
+  var obj: FullRequiresInitWithParent
+
+# this will be accepted, because the false outer branch will be taken and the inner A branch
+accept TNestedChoices()
+accept default(TNestedChoices)
+accept:
+  var obj: TNestedChoices
+
+#[# produces only warning:
+reject:
+  # This proc is illegal, because it tries to produce
+  # a default object of a type that requires initialization:
+  proc defaultHasNotNils: THasNotNils =
+    discard
+#]#
+
+#[# produces only warning:
+reject:
+  # You cannot cheat by using the result variable to specify
+  # only some of the fields
+  proc invalidPartialTHasNotNils: THasNotNils =
+    result.c = nilRef
+#]#
+
+#[# produces only warning:
+reject:
+  # The same applies for requiresInit types
+  proc invalidPartialRequiersInit: PartialRequiresInit =
+    result.b = "x"
+#]#
+
+#[# produces only warning:
+# All code paths must return a value when the result requires initialization:
+reject:
+  proc ifWithoutAnElse: THasNotNils =
+    if stdin.readLine == "":
+      return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef)
+#]#
+
+accept:
+  # All code paths must return a value when the result requires initialization:
+  proc wellFormedIf: THasNotNils =
+    if stdin.readLine == "":
+      return THasNotNils(a: notNilRef, b: notNilRef, c: nilRef)
+    else:
+      return THasNotNIls(a: notNilRef, b: notNilRef)
+
+#[# produces only warning:
+reject:
+  proc caseWithoutAllCasesCovered: FullRequiresInit =
+    # Please note that these is no else branch here:
+    case stdin.readLine
+    of "x":
+      return FullRequiresInit(a: 10, b: 20)
+    of "y":
+      return FullRequiresInit(a: 30, b: 40)
+#]#
+
+accept:
+  proc wellFormedCase: FullRequiresInit =
+    case stdin.readLine
+    of "x":
+      result = FullRequiresInit(a: 10, b: 20)
+    else:
+      # Mixing result and return is fine:
+      return FullRequiresInit(a: 30, b: 40)
+
+# but if we supply a run-time value for the inner branch, the compiler won't be able to prove
+# that the notnil field was initialized
+reject TNestedChoices(outerChoice: false, innerChoice: x) # XXX: The error message is not very good here
+reject TNestedChoices(outerChoice: true,  innerChoice: A) # XXX: The error message is not very good here
+
+accept TNestedChoices(outerChoice: false, innerChoice: B)
+
+reject TNestedChoices(outerChoice: false, innerChoice: C)
+accept TNestedChoices(outerChoice: false, innerChoice: C, notnil: notNilRef)
+reject TNestedChoices(outerChoice: false, innerChoice: C, notnil: nil)
+
+# Tests involving generics and sequences:
+#
+block:
+  # This test aims to show that it's possible to instantiate and
+  # use a sequence with a requiresInit type:
+
+  var legalSeq: seq[IllegalToConstruct]
+  legalSeq.add IllegalToConstruct(x: "one")
+  var two = IllegalToConstruct(x: "two")
+  legalSeq.add two
+  var one = legalSeq[0]
+  var twoAgain = legalSeq.pop
+
+  #[# produces only warning:
+  # It's not possible to tell the sequence to create elements
+  # for us though:
+  reject:
+    var illegalSeq = newSeq[IllegalToConstruct](10)
+  #]#
+
+  #[# produces only warning:
+  reject:
+    var illegalSeq: seq[IllegalToConstruct]
+    newSeq(illegalSeq, 10)
+  #]#
+
+  #[# produces only warning:
+  reject:
+    var illegalSeq: seq[IllegalToConstruct]
+    illegalSeq.setLen 10
+  #]#
+
+  # You can still use newSeqOfCap to write efficient code:
+  var anotherLegalSequence = newSeqOfCap[IllegalToConstruct](10)
+  for i in 0..9:
+    anotherLegalSequence.add IllegalToConstruct(x: "x")
+
+type DefaultConstructible[yesOrNo: static[bool]] = object
+  when yesOrNo:
+    x: string
+  else:
+    x: cstring not nil
+
+block:
+  # Constructability may also depend on the generic parameters of the type:
+  accept:
+    var a: DefaultConstructible[true]
+    var b = DefaultConstructible[true]()
+    var c = DefaultConstructible[true](x: "test")
+    var d = DefaultConstructible[false](x: "test")
+
+  reject:
+    var y: DefaultConstructible[false]
+
+  reject:
+    var y = DefaultConstructible[false]()
+
+block:
+  type
+    Hash = int
+
+    HashTableSlotType = enum
+      Free    = Hash(0)
+      Deleted = Hash(1)
+      HasKey  = Hash(2)
+
+    KeyValuePair[A, B] = object
+      key: A
+      case hash: HashTableSlotType
+      of Free, Deleted:
+        discard
+      else:
+        value: B
+
+  # The above KeyValuePair is an interesting type because it
+  # may become unconstructible depending on the generic parameters:
+  accept KeyValuePair[int, string](hash: Deleted)
+  accept KeyValuePair[int, IllegalToConstruct](hash: Deleted)
+
+  accept KeyValuePair[int, string](hash: HasKey)
+  reject KeyValuePair[int, IllegalToConstruct](hash: HasKey)
+
+  # Since all the above variations don't have a non-constructible
+  # field in the default branch of the case object, we can construct
+  # such values:
+  accept KeyValuePair[int, string]()
+  accept KeyValuePair[int, IllegalToConstruct]()
+  accept KeyValuePair[DefaultConstructible[true], string]()
+  accept KeyValuePair[DefaultConstructible[true], IllegalToConstruct]()
+
+  var a: KeyValuePair[int, string]
+  var b: KeyValuePair[int, IllegalToConstruct]
+  var c: KeyValuePair[DefaultConstructible[true], string]
+  var d: KeyValuePair[DefaultConstructible[true], IllegalToConstruct]
+  var s1 = newSeq[KeyValuePair[int, IllegalToConstruct]](10)
+  var s2 = newSeq[KeyValuePair[DefaultConstructible[true], IllegalToConstruct]](10)
+
+  # But let's put the non-constructible values as keys:
+  reject KeyValuePair[IllegalToConstruct, int](hash: Deleted)
+  reject KeyValuePair[IllegalToConstruct, int]()
+
+  type IllegalPair = KeyValuePair[DefaultConstructible[false], string]
+
+  reject:
+    var x: IllegalPair
+
+  #[# produces only warning:
+  reject:
+    var s = newSeq[IllegalPair](10)
+  #]#
+
+# Specific issues:
+#
+block:
+  # https://github.com/nim-lang/Nim/issues/11428
+  type
+    Enum = enum A, B, C
+    Thing = object
+      case kind: Enum
+      of A: discard
+      of B: s: string
+      of C: r: range[1..1] # DateTime
+
+  # Fine to not initialize 'r' because this is implicitly initialized and known to be branch 'A'.
+  var x = Thing()
+  discard x
+
+block:
+  # https://github.com/nim-lang/Nim/issues/4907
+  type
+    Foo = ref object
+    Bar = object
+
+    Thing[A, B] = ref object
+      a: A not nil
+      b: ref B
+      c: ref B not nil
+
+  proc allocNotNil(T: typedesc): T not nil =
+    new result
+
+  proc mutateThing(t: var Thing[Foo, Bar]) =
+    let fooNotNil = allocNotNil(Foo)
+    var foo: Foo
+
+    let barNotNil = allocNotNil(ref Bar)
+    var bar: ref Bar
+
+    t.a = fooNotNil
+    t.b = bar
+    t.b = barNotNil
+    t.c = barNotNil
+
+    reject:
+      t.a = foo
+
+    reject:
+      t.c = bar
+
+  var thing = Thing[Foo, Bar](a: allocNotNil(Foo),
+                              b: allocNotNil(ref Bar),
+                              c: allocNotNil(ref Bar))
+  mutateThing thing
+
diff --git a/tests/tblock1.nim b/tests/controlflow/tblock1.nim
index 0bea7ae7f..70c844513 100755..100644
--- a/tests/tblock1.nim
+++ b/tests/controlflow/tblock1.nim
@@ -1,11 +1,16 @@
-# check for forward label and

-# for failure when label is not declared

-

-proc main =

-  block endLess:

-    write(stdout, "Muaahh!\N")

-    break endLess

-

-  break ha #ERROR

-

-main()

+discard """
+  errormsg: "undeclared identifier: \'ha\'"
+  file: "tblock1.nim"
+  line: 14
+"""
+# check for forward label and
+# for failure when label is not declared
+
+proc main =
+  block endLess:
+    write(stdout, "Muaahh!\N")
+    break endLess
+
+  break ha #ERROR
+
+main()
diff --git a/tests/controlflow/tcontrolflow.nim b/tests/controlflow/tcontrolflow.nim
new file mode 100644
index 000000000..dd21a2bb6
--- /dev/null
+++ b/tests/controlflow/tcontrolflow.nim
@@ -0,0 +1,116 @@
+discard """
+  output: '''
+10
+true true
+true false
+false true
+false false
+i == 2
+'''
+"""
+
+
+block tbreak:
+  var
+    x = false
+    run = true
+
+  while run:
+    run = false
+    block myblock:
+      if true:
+        break myblock
+      echo "leaving myblock"
+    x = true
+  doAssert(x)
+
+  # bug #1418
+  iterator foo: int =
+    for x in 0 .. 9:
+      for y in [10,20,30,40,50,60,70,80,90]:
+        yield x + y
+
+  for p in foo():
+    echo p
+    break
+
+  iterator permutations: int =
+    yield 10
+
+  for p in permutations():
+    break
+
+  # regression:
+  proc main =
+    for x in [true, false]:
+      for y in [true, false]:
+        echo x, " ", y
+
+  main()
+
+
+
+block tcontinue:
+  var i = 0
+  while i < 400:
+
+    if i == 10: break
+    elif i == 3:
+      inc i
+      continue
+    inc i
+
+  var f = "failure"
+  var j = 0
+  while j < 300:
+    for x in 0..34:
+      if j < 300: continue
+      if x == 10:
+        echo "failure: should never happen"
+        break
+    f = "came here"
+    break
+
+  if i == 10:
+    doAssert f == "came here"
+  else:
+    echo "failure"
+
+
+
+block tnestif:
+  var
+      x, y: int
+  x = 2
+  if x == 0:
+      write(stdout, "i == 0")
+      if y == 0:
+          writeLine(stdout, x)
+      else:
+          writeLine(stdout, y)
+  elif x == 1:
+      writeLine(stdout, "i == 1")
+  elif x == 2:
+      writeLine(stdout, "i == 2")
+  else:
+      writeLine(stdout, "looks like Python")
+  #OUT i == 2
+
+# bug https://github.com/nim-lang/RFCs/issues/451
+for i in 1..2: # works
+  break
+
+block: # works
+  for i in 1..2:
+    break
+
+block: # works
+  block:
+    discard 12 + 3
+  for i in 1..2:
+    break
+
+block named: # works
+  if true:
+    break named
+  doAssert false, "not reached"
diff --git a/tests/controlflow/tstatret.nim b/tests/controlflow/tstatret.nim
new file mode 100644
index 000000000..a3558e6f4
--- /dev/null
+++ b/tests/controlflow/tstatret.nim
@@ -0,0 +1,9 @@
+discard """
+  nimout: '''
+tstatret.nim(9, 7) Warning: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
+'''
+"""
+# no statement after return
+proc main() =
+  return
+  echo("huch?") #ERROR_MSG statement not allowed after
diff --git a/tests/controlflow/tunamedbreak.nim b/tests/controlflow/tunamedbreak.nim
new file mode 100644
index 000000000..46113cabc
--- /dev/null
+++ b/tests/controlflow/tunamedbreak.nim
@@ -0,0 +1,15 @@
+
+discard """
+  cmd: "nim check $file"
+  action: "reject"
+  nimout: '''
+tunamedbreak.nim(12, 5) Error: Using an unnamed break in a block is deprecated; Use a named block with a named break instead [UnnamedBreak]
+tunamedbreak.nim(15, 3) Error: Using an unnamed break in a block is deprecated; Use a named block with a named break instead [UnnamedBreak]
+  '''
+"""
+for i in 1..2: # errors
+  block:
+    break
+
+block: # errors
+  break
diff --git a/tests/controlflow/tunreachable.nim b/tests/controlflow/tunreachable.nim
new file mode 100644
index 000000000..06321ce8a
--- /dev/null
+++ b/tests/controlflow/tunreachable.nim
@@ -0,0 +1,79 @@
+discard """
+  cmd: "nim check --warningAsError:UnreachableCode $file"
+  action: "reject"
+  nimout: '''
+tunreachable.nim(26, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
+tunreachable.nim(33, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
+tunreachable.nim(42, 3) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
+tunreachable.nim(65, 5) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
+tunreachable.nim(77, 5) Error: unreachable code after 'return' statement or '{.noReturn.}' proc [UnreachableCode]
+'''
+"""
+  
+# bug #9839
+template myquit1():untyped=
+  ## foo
+  quit(1)
+template myquit2():untyped=
+  echo 123
+  myquit1()
+
+proc main1()=
+
+  # BUG: uncommenting this doesn't give `Error: unreachable statement`
+  myquit2()
+
+  echo "after"
+
+main1()
+
+proc main2() =
+  myquit1()
+
+  echo "after"
+
+main2()
+
+proc main3() =
+  if true:
+    return
+  else:
+    return
+  echo "after"
+
+main3()
+
+
+block:
+  # Cases like strings are not checked for exhaustiveness unless they have an else
+  proc main4(x: string) =
+    case x
+    of "a":
+      return
+    # reachable
+    echo "after"
+
+  main4("a")
+
+  proc main5(x: string) =
+    case x
+    of "a":
+      return
+    else:
+      return
+    # unreachable
+    echo "after"
+
+  main5("a")
+
+block:
+  # In this case no else is needed because it's exhaustive
+  proc exhaustive(x: bool) =
+    case x
+    of true:
+      return
+    of false:
+      return
+    echo "after"
+
+  exhaustive(true)
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/converter/m18986.nim b/tests/converter/m18986.nim
new file mode 100644
index 000000000..0ebf343ae
--- /dev/null
+++ b/tests/converter/m18986.nim
@@ -0,0 +1,3 @@
+import std/macros
+
+converter Lit*(x: uint): NimNode = newLit(x)
diff --git a/tests/converter/mdontleak.nim b/tests/converter/mdontleak.nim
new file mode 100644
index 000000000..e55c3f87c
--- /dev/null
+++ b/tests/converter/mdontleak.nim
@@ -0,0 +1,3 @@
+
+converter toBool(x: uint32): bool = x != 0
+# Note: This convertes is not exported!
diff --git a/tests/converter/t18986.nim b/tests/converter/t18986.nim
new file mode 100644
index 000000000..ef300fa49
--- /dev/null
+++ b/tests/converter/t18986.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "Found a 0"
+"""
+
+import m18986 except Lit
+import std/macros
+
+# bug #18986
+var x = 0.uint
+echo "Found a ", x
diff --git a/tests/converter/t21531.nim b/tests/converter/t21531.nim
new file mode 100644
index 000000000..b0198684d
--- /dev/null
+++ b/tests/converter/t21531.nim
@@ -0,0 +1,10 @@
+import std/typetraits
+
+type Foo* = distinct string
+
+converter toBase*(headers: var Foo): var string =
+  headers.distinctBase
+
+proc bar*(headers: var Foo) =
+  for x in headers: discard
+    
diff --git a/tests/converter/t7097.nim b/tests/converter/t7097.nim
new file mode 100644
index 000000000..d8e953080
--- /dev/null
+++ b/tests/converter/t7097.nim
@@ -0,0 +1,38 @@
+type
+  Byte* = uint8
+  Bytes* = seq[Byte]
+  
+  BytesRange* = object
+    bytes: Bytes
+    ibegin, iend: int
+
+proc initBytesRange*(s: var Bytes, ibegin = 0, iend = -1): BytesRange =
+  let e = if iend < 0: s.len + iend + 1
+          else: iend
+  assert ibegin > 0 and e <= s.len
+  when defined(gcRefc):
+    shallow(s)
+  result.bytes = s
+  result.ibegin = ibegin
+  result.iend = e
+
+template `[]=`*(r: var BytesRange, i: int, v: Byte) =
+  r.bytes[r.ibegin + i] = v
+
+converter fromSeq*(s: Bytes): BytesRange =
+  var seqCopy = s
+  return initBytesRange(seqCopy)
+
+type
+  Reader* = object
+    data: BytesRange
+    position: int
+
+proc readerFromHex*(input: string): Reader =
+  let totalBytes = input.len div 2
+  var backingStore = newSeq[Byte](totalBytes)
+  result.data = initBytesRange(backingStore)
+
+  for i in 0 ..< totalBytes:
+    var nextByte = 0
+    result.data[i] = Byte(nextByte) # <-------- instantiated from here
diff --git a/tests/converter/t7098.nim b/tests/converter/t7098.nim
new file mode 100644
index 000000000..30c9c1e25
--- /dev/null
+++ b/tests/converter/t7098.nim
@@ -0,0 +1,35 @@
+discard """
+action: compile
+"""
+
+type
+  Byte* = uint8
+  Bytes* = seq[Byte]
+
+  BytesRange* = object
+    bytes: Bytes
+    ibegin, iend: int
+
+proc initBytesRange*(s: var Bytes, ibegin = 0, iend = -1): BytesRange =
+  let e = if iend < 0: s.len + iend + 1
+          else: iend
+  assert ibegin >= 0 and e <= s.len
+  when defined(gcRefc):
+    shallow(s)
+  result.bytes = s
+  result.ibegin = ibegin
+  result.iend = e
+
+converter fromSeq*(s: Bytes): BytesRange =
+  var seqCopy = s
+  return initBytesRange(seqCopy)
+
+type
+  Reader* = object
+    data: BytesRange
+    position: int
+
+proc readerFromBytes*(input: BytesRange): Reader =
+  discard
+
+let r = readerFromBytes(@[])
diff --git a/tests/converter/t9165.nim b/tests/converter/t9165.nim
new file mode 100644
index 000000000..d0225ffbc
--- /dev/null
+++ b/tests/converter/t9165.nim
@@ -0,0 +1,11 @@
+type ustring = distinct string
+
+converter toUString(s: string): ustring = ustring(s)
+converter toString(s: ustring): string = string(s)
+
+proc `[]=`*(s: var ustring, slice: Slice[int], replacement: ustring) {.inline.} =
+  s = replacement
+
+var s = ustring("123")
+s[1..2] = "3"
+doAssert s == "3"
\ No newline at end of file
diff --git a/tests/converter/tconvcolors.nim b/tests/converter/tconvcolors.nim
new file mode 100644
index 000000000..7b440cabd
--- /dev/null
+++ b/tests/converter/tconvcolors.nim
@@ -0,0 +1,7 @@
+discard """
+output: "16777215A"
+"""
+
+import colors
+
+echo int32(colWhite), 'A'
diff --git a/tests/converter/tconvert.nim b/tests/converter/tconvert.nim
new file mode 100644
index 000000000..5eee2a92d
--- /dev/null
+++ b/tests/converter/tconvert.nim
@@ -0,0 +1,44 @@
+
+converter FloatConversion64(x: int): float64 = return toFloat(x)
+converter FloatConversion32(x: int): float32 = return toFloat(x)
+converter FloatConversionPlain(x: int): float = return toFloat(x)
+
+const width = 500
+const height = 500
+
+proc ImageSurfaceCreate(w, h: float) = discard
+
+ImageSurfaceCreate(width, height)
+
+type TFoo = object
+
+converter toPtr*(some: var TFoo): ptr TFoo = (addr some)
+
+
+proc zoot(x: ptr TFoo) = discard
+var x: Tfoo
+zoot(x)
+
+# issue #6544
+converter withVar(b: var string): int = ord(b[1])
+
+block:
+  var x = "101"
+  var y: int = x # instantiate withVar
+  doAssert(y == ord('0'))
+
+
+######################
+# bug #3503
+type Foo = object
+  r: float
+
+converter toFoo(r: float): Foo =
+  result.r = r
+
+proc `+=`*(x: var Foo, r: float) =
+  x.r += r
+
+var a: Foo
+a.r += 3.0
+
diff --git a/tests/converter/tconverter.nim b/tests/converter/tconverter.nim
new file mode 100644
index 000000000..0bf067c55
--- /dev/null
+++ b/tests/converter/tconverter.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''fooo fooo'''
+"""
+
+converter intToString[T](i: T): string = "fooo"
+
+let
+  foo: string = 1
+  bar: string = intToString(2)
+
+echo foo, " ", bar
\ No newline at end of file
diff --git a/tests/converter/tconverter_unique_ptr.nim b/tests/converter/tconverter_unique_ptr.nim
new file mode 100644
index 000000000..6902f9e9e
--- /dev/null
+++ b/tests/converter/tconverter_unique_ptr.nim
@@ -0,0 +1,149 @@
+
+discard """
+  targets: "c cpp"
+  output: ""
+"""
+
+## Bugs 9698 and 9699
+
+type
+  UniquePtr*[T] = object
+    ## non copyable pointer to object T, exclusive ownership of the object is assumed
+    val: ptr T
+
+  MyLen* = distinct int
+
+  MySeq* = object
+    ## Vectorized matrix
+    len: MyLen  # scalar size
+    data: ptr UncheckedArray[float]
+
+proc `$`(x: MyLen): string {.borrow.}
+proc `==`(x1, x2: MyLen): bool {.borrow.}
+
+
+proc `=destroy`*(m: MySeq) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+
+proc `=copy`*(m: var MySeq, m2: MySeq) =
+  if m.data == m2.data: return
+  if m.data != nil:
+    `=destroy`(m)
+
+  m.len = m2.len
+  let bytes = m.len.int * sizeof(float)
+  if bytes > 0:
+    m.data = cast[ptr UncheckedArray[float]](allocShared(bytes))
+    copyMem(m.data, m2.data, bytes)
+
+proc `=sink`*(m: var MySeq, m2: MySeq) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*(m: MySeq): MyLen {.inline.} = m.len
+
+proc lenx*(m: var MySeq): MyLen {.inline.} = m.len
+
+proc `[]`*(m: MySeq; i: MyLen): float {.inline.} =
+  m.data[i.int]
+
+proc `[]`*(m: var MySeq; i: MyLen): var float {.inline.} =
+  m.data[i.int]
+
+proc `[]=`*(m: var MySeq; i: MyLen, val: float) {.inline.} =
+  m.data[i.int] = val
+
+proc setTo(s: var MySeq, val: float) =
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeq =
+  result.len = size.MyLen
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+
+  result.setTo(initial_value)
+
+converter literalToLen*(x: int{lit}): MyLen =
+  x.MyLen
+
+
+#-------------------------------------------------------------
+# Unique pointer implementation
+#-------------------------------------------------------------
+
+proc `=destroy`*[T](p: UniquePtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+
+proc `=copy`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newUniquePtr*[T](val: sink T): UniquePtr[T] =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertPtrToObj*[T](p: UniquePtr[T]): var T =
+  result = p.val[]
+
+var pu = newUniquePtr(newMySeq(5, 1.0))
+let pu2 = newUniquePtr(newMySeq(5, 1.0))
+doAssert: pu.len == 5
+doAssert: pu2.len == 5
+doAssert: pu.lenx == 5
+doAssert: pu2.lenx == 5
+
+pu[0] = 2.0
+pu2[0] = 2.0
+doAssert pu[0] == 2.0
+doAssert: pu2[0] == 2.0
+
+##-----------------------------------------------------------------------------------------
+## Bugs #9735 and #9736
+type
+  ConstPtr*[T] = object
+    ## This pointer makes it impossible to change underlying value
+    ## as it returns only `lent T`
+    val: ptr T
+
+proc `=destroy`*[T](p: ConstPtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+
+proc `=copy`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newConstPtr*[T](val: sink T): ConstPtr[T] =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertConstPtrToObj*[T](p: ConstPtr[T]): lent T =
+  result = p.val[]
+
+var pc = newConstPtr(newMySeq(3, 1.0))
+let pc2 = newConstPtr(newMySeq(3, 1.0))
+doAssert: pc.len == 3
+doAssert: pc.len == 3
+doAssert: compiles(pc.lenx == 2) == false
+doAssert: compiles(pc2.lenx == 2) == false
+doAssert: compiles(pc[0] = 2.0) == false
+doAssert: compiles(pc2[0] = 2.0) == false
+
+doAssert: pc[0] == 1.0
+doAssert: pc2[0] == 1.0
diff --git a/tests/converter/tconverter_with_constraint.nim b/tests/converter/tconverter_with_constraint.nim
new file mode 100644
index 000000000..ce5135586
--- /dev/null
+++ b/tests/converter/tconverter_with_constraint.nim
@@ -0,0 +1,20 @@
+
+discard """
+  errormsg: "type mismatch: got <int>"
+  file: "tconverter_with_constraint.nim"
+  line: 20
+"""
+
+type
+  MyType = distinct int
+
+converter to_mytype(m: int{lit}): MyType =
+  m.MyType
+
+proc myproc(m: MyType) =
+  echo m.int, ".MyType"
+
+myproc(1) # call by literal is ok
+
+var x: int = 12
+myproc(x) # should fail
diff --git a/tests/converter/tconverter_with_varargs.nim b/tests/converter/tconverter_with_varargs.nim
new file mode 100644
index 000000000..fae83221b
--- /dev/null
+++ b/tests/converter/tconverter_with_varargs.nim
@@ -0,0 +1,18 @@
+
+# bug #888
+
+type
+  PyRef = object
+  PPyRef* = ref PyRef
+
+converter to_py*(i: int) : PPyRef = nil
+
+when false:
+  proc to_tuple*(vals: openArray[PPyRef]): PPyRef =
+    discard
+
+proc abc(args: varargs[PPyRef]) =
+  #let args_tup = to_tuple(args)
+  discard
+
+abc(1, 2)
diff --git a/tests/converter/tdontleak.nim b/tests/converter/tdontleak.nim
new file mode 100644
index 000000000..4965fa90a
--- /dev/null
+++ b/tests/converter/tdontleak.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''5'''
+joinable: false
+"""
+
+import mdontleak
+# bug #19213
+
+let a = 5'u32
+echo a
diff --git a/tests/converter/texplicit_conversion.nim b/tests/converter/texplicit_conversion.nim
new file mode 100644
index 000000000..e36d78ad5
--- /dev/null
+++ b/tests/converter/texplicit_conversion.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "234"
+"""
+
+# bug #4432
+
+import strutils
+
+converter toInt(s: string): int =
+  result = parseInt(s)
+
+let x = (int)"234"
+echo x
+
+block: # Test for nkconv
+  proc foo(o: var int) =
+    assert o == 0
+  var a = 0
+  foo(int(a))
\ No newline at end of file
diff --git a/tests/converter/tgenericconverter.nim b/tests/converter/tgenericconverter.nim
new file mode 100644
index 000000000..cbbd2e1b0
--- /dev/null
+++ b/tests/converter/tgenericconverter.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''666
+666'''
+"""
+
+# test the new generic converters:
+
+type
+  TFoo2[T] = object
+    x: T
+
+  TFoo[T] = object
+    data: array[0..100, T]
+
+converter toFoo[T](a: TFoo2[T]): TFoo[T] =
+  result.data[0] = a.x
+
+proc p(a: TFoo[int]) =
+  echo a.data[0]
+
+proc q[T](a: TFoo[T]) =
+  echo a.data[0]
+
+
+var
+  aa: TFoo2[int]
+aa.x = 666
+
+p aa
+q aa
+
+
+#-------------------------------------------------------------
+# issue #16651
+type
+  PointTup = tuple
+    x: float32
+    y: float32
+
+converter tupleToPoint[T1, T2: SomeFloat](self: tuple[x: T1, y: T2]): PointTup =
+  result = (self.x.float32, self.y.float32)
+
+proc tupleToPointX(self: tuple[x: SomeFloat, y: SomeFloat]): PointTup =
+  result = (self.x.float32, self.y.float32)
+
+proc tupleToPointX2(self: tuple[x: SomeFloat, y: distinct SomeFloat]): PointTup =
+  result = (self.x.float32, self.y.float32)
+
+var t1: PointTup = tupleToPointX((1.0, 0.0))
+var t2: PointTup = tupleToPointX2((1.0, 0.0))
+var t3: PointTup = tupleToPointX2((1.0'f32, 0.0))
+var t4: PointTup = tupleToPointX2((1.0, 0.0'f32))
+
+var x2: PointTup = (1.0, 0.0)
\ No newline at end of file
diff --git a/tests/converter/tgenericconverter2.nim b/tests/converter/tgenericconverter2.nim
new file mode 100644
index 000000000..97b7846c1
--- /dev/null
+++ b/tests/converter/tgenericconverter2.nim
@@ -0,0 +1,85 @@
+# bug #3799
+
+import strutils
+
+const output = splitLines("""
+00000000000000000000000000000000000000000
+00000000000001111111111111110000000000000
+00000000001111111111111111111110000000000
+00000000111111111111111111111111100000000
+00000011111222222221111111111111111000000
+00000111122222222222221111111111111100000
+00001112222333333459432111111111111110000
+00011122355544344463533221111111111111000
+00111124676667556896443322211111111111100
+00111126545561919686543322221111111111100
+01111123333346967807554322222211111111110
+01111122233334455582015332222221111111110
+01111122222333344567275432222222111111110
+01111112222222334456075443222222211111110
+01111111222222233459965444332222221111110
+01111111122222223457486554433322222111110
+01111111112222222367899655543333322111110
+01111111111122222344573948465444332111110
+00111111111112222334467987727667762111100
+00111111111111122233474655557836432111100
+00011111111111112233 454433334 4321111000
+00001111111111111122354333322222211110000
+00000111111111111111222222222222111100000
+00000001111111111111111122222111110000000
+00000000111111111111111111111111100000000
+00000000000111111111111111111100000000000
+00000000000000111111111111100000000000000
+""")
+
+const nmax = 500
+
+type
+  Complex*[T] = object
+    re*: T
+    im*: T
+
+converter toComplex*[T](x: tuple[re, im: T]): Complex[T] =
+  result.re = x.re
+  result.im = x.im
+
+
+proc julia*[T](z0, c: Complex[T], er2: T, nmax: int): int =
+  result = 0
+  var z = z0
+  var sre = z0.re * z0.re
+  var sim = z0.im * z0.im
+  while (result < nmax) and (sre + sim < er2):
+    z.im = z.re * z.im
+    z.im = z.im + z.im
+    z.im = z.im + c.im
+    z.re = sre - sim + c.re
+    sre = z.re * z.re
+    sim = z.im * z.im
+    inc result
+
+template dendriteFractal*[T](z0: Complex[T], er2: T, nmax: int): int =
+  julia(z0, (T(0.0), T(1.0)), er2, nmax)
+
+iterator stepIt[T](start, step: T, iterations: int): (int, T) =
+  for i in 0 .. iterations:
+    yield (i, start + T(i) * step)
+
+var errors = 0
+
+let c = (0.36237, 0.32)
+for j, y in stepIt(2.0, -0.0375 * 4, 107 div 4):
+  var row = ""
+  for i, x in stepIt(-2.0, 0.025 * 4, 160 div 4):
+    #let n = julia((x, y), c, 4.0, nmax)         ### this works
+    let n = dendriteFractal((x, y), 4.0, nmax)
+    let c = char(int('0') + n mod 10)
+    let e = output[j][i]  # expected
+    if c != e:
+      errors += 1
+    row.add(c)
+
+  # Printing apparently makes the test fail when joined.
+  # echo row
+
+doAssert errors < 10, "total errors: " & $errors
diff --git a/tests/converter/tor_in_converter.nim b/tests/converter/tor_in_converter.nim
new file mode 100644
index 000000000..df2334647
--- /dev/null
+++ b/tests/converter/tor_in_converter.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''test
+test'''
+"""
+# bug #4537
+
+# nim js -d:nodejs
+
+type
+  Str = distinct string
+
+when true:
+  # crashes
+  converter convert(s: string | cstring): Str = Str($s)
+else:
+  # works!
+  converter convert(s: string): Str = Str($s)
+  converter convert(s: cstring): Str = Str($s)
+
+proc echoStr(s: Str) = echo s.string
+
+echoStr("test")
+echoStr("test".cstring)
diff --git a/tests/converter/ttypeconverter1.nim b/tests/converter/ttypeconverter1.nim
new file mode 100644
index 000000000..39eb6eff1
--- /dev/null
+++ b/tests/converter/ttypeconverter1.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''foo
+true'''
+"""
+
+converter p(i: int): bool = return i != 0
+
+if 1:
+  echo if 4: "foo" else: "barr"
+while 0:
+  echo "bar"
+
+var a: array[3, bool]
+a[0] = 3
+echo a[0]
diff --git a/tests/coroutines/texceptions.nim b/tests/coroutines/texceptions.nim
new file mode 100644
index 000000000..31feffdff
--- /dev/null
+++ b/tests/coroutines/texceptions.nim
@@ -0,0 +1,29 @@
+discard """
+  targets: "c"
+  disabled: true
+"""
+
+import coro
+var
+  stackCheckValue = 1100220033
+  numbers = newSeqOfCap[int](10)
+
+proc testExceptions(id: int, sleep: float) =
+  try:
+    numbers.add(id)
+    suspend(sleep)
+    numbers.add(id)
+    raise (ref ValueError)()
+  except:
+    suspend(sleep)
+    numbers.add(id)
+    suspend(sleep)
+    numbers.add(id)
+  suspend(sleep)
+  numbers.add(id)
+
+start(proc() = testExceptions(1, 0.01))
+start(proc() = testExceptions(2, 0.011))
+coro.run()
+doAssert(stackCheckValue == 1100220033, "Thread stack got corrupted")
+doAssert(numbers == @[1, 2, 1, 2, 1, 2, 1, 2, 1, 2], "Coroutines executed in incorrect order")
diff --git a/tests/coroutines/texceptions.nim.cfg b/tests/coroutines/texceptions.nim.cfg
new file mode 100644
index 000000000..b011bc585
--- /dev/null
+++ b/tests/coroutines/texceptions.nim.cfg
@@ -0,0 +1 @@
+-d:nimCoroutines
diff --git a/tests/coroutines/tgc.nim b/tests/coroutines/tgc.nim
new file mode 100644
index 000000000..770d413f5
--- /dev/null
+++ b/tests/coroutines/tgc.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--gc:refc; --gc:arc; --gc:orc"
+  targets: "c"
+"""
+
+when compileOption("gc", "refc") or not defined(openbsd):
+  # xxx openbsd gave: stdlib_coro.nim.c:406:22: error: array type 'jmp_buf' (aka 'long [11]') is not assignable (*dest).execContext = src.execContext;
+  import coro
+
+  var maxOccupiedMemory = 0
+
+  proc testGC() =
+    var numbers = newSeq[int](100)
+    maxOccupiedMemory = max(maxOccupiedMemory, getOccupiedMem())
+    suspend(0)
+
+  start(testGC)
+  start(testGC)
+  run()
+
+  GC_fullCollect()
+  doAssert(getOccupiedMem() < maxOccupiedMemory, "GC did not free any memory allocated in coroutines")
diff --git a/tests/coroutines/tgc.nim.cfg b/tests/coroutines/tgc.nim.cfg
new file mode 100644
index 000000000..b011bc585
--- /dev/null
+++ b/tests/coroutines/tgc.nim.cfg
@@ -0,0 +1 @@
+-d:nimCoroutines
diff --git a/tests/coroutines/titerators.nim b/tests/coroutines/titerators.nim
new file mode 100644
index 000000000..1ea134811
--- /dev/null
+++ b/tests/coroutines/titerators.nim
@@ -0,0 +1,31 @@
+discard """
+  targets: "c"
+disabled: true
+"""
+
+# Timers are always flakey on the testing servers.
+
+import coro
+include system/timers
+
+var
+  stackCheckValue = 1100220033
+  numbers = newSeqOfCap[int](10)
+
+iterator theIterator(id: int, sleep: float): int =
+  for i in 0..<5:
+    yield 10 * id + i
+    suspend(sleep)
+
+proc theCoroutine(id: int, sleep: float32) =
+  for n in theIterator(id, sleep):
+    numbers.add(n)
+
+var start = getTicks()
+start(proc() = theCoroutine(1, 0.01))
+start(proc() = theCoroutine(2, 0.011))
+run()
+
+var executionTime = getTicks() - start
+doAssert(stackCheckValue == 1100220033, "Thread stack got corrupted")
+doAssert(numbers == @[10, 20, 11, 21, 12, 22, 13, 23, 14, 24], "Coroutines executed in incorrect order")
diff --git a/tests/coroutines/titerators.nim.cfg b/tests/coroutines/titerators.nim.cfg
new file mode 100644
index 000000000..b011bc585
--- /dev/null
+++ b/tests/coroutines/titerators.nim.cfg
@@ -0,0 +1 @@
+-d:nimCoroutines
diff --git a/tests/coroutines/twait.nim b/tests/coroutines/twait.nim
new file mode 100644
index 000000000..2edfcf675
--- /dev/null
+++ b/tests/coroutines/twait.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "Exit 1\nExit 2"
+  matrix: "--gc:refc; --gc:arc; --gc:orc"
+  targets: "c"
+"""
+
+when compileOption("gc", "refc") or not defined(openbsd):
+  # xxx openbsd failed, see tgc.nim
+  import coro
+
+  var coro1: CoroutineRef
+
+  proc testCoroutine1() =
+    for i in 0..<10:
+      suspend(0)
+    echo "Exit 1"
+
+  proc testCoroutine2() =
+    coro1.wait()
+    echo "Exit 2"
+
+  coro1 = coro.start(testCoroutine1)
+  coro.start(testCoroutine2)
+  run()
+else:
+  # workaround
+  echo "Exit 1"
+  echo "Exit 2"
diff --git a/tests/coroutines/twait.nim.cfg b/tests/coroutines/twait.nim.cfg
new file mode 100644
index 000000000..b011bc585
--- /dev/null
+++ b/tests/coroutines/twait.nim.cfg
@@ -0,0 +1 @@
+-d:nimCoroutines
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/amodule.nim b/tests/cpp/amodule.nim
new file mode 100644
index 000000000..2f3e34051
--- /dev/null
+++ b/tests/cpp/amodule.nim
@@ -0,0 +1,10 @@
+import os
+
+proc findlib: string =
+  let path = getEnv("MYLIB_DOES_NOT_EXIST_PATH")
+  if path.len > 0 and dirExists(path):
+    path / "alib_does_not_matter.dll"
+  else:
+    "alib_does_not_matter.dll"
+
+proc imported_func*(a: cint): cstring {.importc, dynlib: findlib().}
\ No newline at end of file
diff --git a/tests/cpp/enum.hpp b/tests/cpp/enum.hpp
new file mode 100644
index 000000000..268999d68
--- /dev/null
+++ b/tests/cpp/enum.hpp
@@ -0,0 +1,3 @@
+namespace namespaced {
+enum Enum { A, B, C };
+}
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/foo.c b/tests/cpp/foo.c
new file mode 100644
index 000000000..84fbbccd0
--- /dev/null
+++ b/tests/cpp/foo.c
@@ -0,0 +1,4 @@
+
+char* myFunc() {
+  return "Hello world";
+}
diff --git a/tests/cpp/mexportc.nim b/tests/cpp/mexportc.nim
new file mode 100644
index 000000000..dee51f157
--- /dev/null
+++ b/tests/cpp/mexportc.nim
@@ -0,0 +1,9 @@
+{.used.} # ideally, would not be needed
+
+var fun0 {.exportc.} = 10
+proc fun1() {.exportc.} = discard
+proc fun2() {.exportc: "$1".} = discard
+proc fun3() {.exportc: "fun3Bis".} = discard
+
+when defined cpp:
+  proc funx1() {.exportcpp.} = discard
diff --git a/tests/cpp/t10148.nim b/tests/cpp/t10148.nim
new file mode 100644
index 000000000..e8dd3098f
--- /dev/null
+++ b/tests/cpp/t10148.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''Expected successful exit'''
+  joinable: false
+"""
+
+import os
+
+proc another_proc: string =
+  ## trigger many GC allocations
+  var x = @[""]
+  for i in 0..100:
+   x.add $i
+  result = "not_existent_path"
+
+proc findlib2: string =
+  let path = getEnv("MYLIB2_DOES_NOT_EXIST_PATH")
+  let another_path = another_proc()
+  GC_fullCollect()
+
+  if path.len > 0 and dirExists(path):
+    path / "alib_does_not_matter.dll"
+  elif fileExists(another_path):
+    another_path
+  else:
+    quit("Expected successful exit", 0)
+
+proc imported_func*(a: cint): cstring {.importc, dynlib: findlib2().}
+
+echo imported_func(0)
diff --git a/tests/cpp/t10241.nim b/tests/cpp/t10241.nim
new file mode 100644
index 000000000..21d6a0f4e
--- /dev/null
+++ b/tests/cpp/t10241.nim
@@ -0,0 +1,19 @@
+discard """
+  targets: "cpp"
+  action: "compile"
+"""
+
+type
+  String* {.importcpp: "std::string", header: "string".} = object
+
+proc initString*(): String
+    {.importcpp: "std::string()", header: "string".}
+
+proc append*(this: var String, str: String): var String
+    {.importcpp: "append", header: "string", discardable.}
+
+var
+  s1 = initString()
+  s2 = initString()
+
+s1.append s2
diff --git a/tests/cpp/t12946.nim b/tests/cpp/t12946.nim
new file mode 100644
index 000000000..79cd56251
--- /dev/null
+++ b/tests/cpp/t12946.nim
@@ -0,0 +1,8 @@
+discard """
+  targets: "c cpp"
+"""
+
+import std/atomics
+type Futex = distinct Atomic[int32]
+
+var x: Futex
diff --git a/tests/cpp/t22679.nim b/tests/cpp/t22679.nim
new file mode 100644
index 000000000..81defcb58
--- /dev/null
+++ b/tests/cpp/t22679.nim
@@ -0,0 +1,50 @@
+discard """
+  cmd: "nim cpp $file"
+  output:'''
+cppNZ.x = 123
+cppNZInit.x = 123
+hascpp.cppnz.x = 123
+hasCppInit.cppnz.x = 123
+hasCppCtor.cppnz.x = 123
+'''
+"""
+{.emit:"""/*TYPESECTION*/
+struct CppNonZero {
+  int x = 123;
+};
+""".}
+
+import sugar
+type
+  CppNonZero {.importcpp, inheritable.} = object
+    x: cint
+
+  HasCpp = object
+    cppnz: CppNonZero
+
+proc initCppNonZero: CppNonZero =
+  CppNonZero()
+
+proc initHasCpp: HasCpp =
+  HasCpp()
+
+proc ctorHasCpp: HasCpp {.constructor.} =
+  discard
+
+proc main =
+  var cppNZ: CppNonZero
+  dump cppNZ.x
+
+  var cppNZInit = initCppNonZero()
+  dump cppNZInit.x
+
+  var hascpp: HasCpp
+  dump hascpp.cppnz.x
+
+  var hasCppInit = initHasCpp()
+  dump hasCppInit.cppnz.x
+
+  var hasCppCtor = ctorHasCpp()
+  dump hasCppCtor.cppnz.x
+
+main()
\ No newline at end of file
diff --git a/tests/cpp/t22680.nim b/tests/cpp/t22680.nim
new file mode 100644
index 000000000..80f1a8319
--- /dev/null
+++ b/tests/cpp/t22680.nim
@@ -0,0 +1,50 @@
+discard """
+  cmd: "nim cpp $file"
+  output:'''
+cppNZ.x = 123
+cppNZInit.x = 123
+inheritCpp.x = 123
+inheritCppInit.x = 123
+inheritCppCtor.x = 123
+'''
+"""
+import std/sugar
+
+{.emit:"""/*TYPESECTION*/
+struct CppNonZero {
+  int x = 123;
+};
+""".}
+
+type
+  CppNonZero {.importcpp, inheritable.} = object
+    x: cint
+
+  InheritCpp = object of CppNonZero
+
+proc initCppNonZero: CppNonZero =
+  CppNonZero()
+
+proc initInheritCpp: InheritCpp =
+  InheritCpp()
+
+proc ctorInheritCpp: InheritCpp {.constructor.} =
+  discard
+
+proc main =
+  var cppNZ: CppNonZero
+  dump cppNZ.x
+
+  var cppNZInit = initCppNonZero()
+  dump cppNZInit.x
+
+  var inheritCpp: InheritCpp
+  dump inheritCpp.x
+
+  var inheritCppInit = initInheritCpp()
+  dump inheritCppInit.x
+
+  var inheritCppCtor = ctorInheritCpp()
+  dump inheritCppCtor.x
+
+main()
\ No newline at end of file
diff --git a/tests/cpp/t22712.nim b/tests/cpp/t22712.nim
new file mode 100644
index 000000000..34ef67ac8
--- /dev/null
+++ b/tests/cpp/t22712.nim
@@ -0,0 +1,15 @@
+discard """
+targets: "cpp"
+errormsg: "constructor in an imported type needs importcpp pragma"
+line: 14
+"""
+{.emit: """/*TYPESECTION*/
+struct CppStruct {
+  CppStruct();
+};
+""".}
+
+type CppStruct {.importcpp.} = object
+
+proc makeCppStruct(): CppStruct {.constructor.} = 
+  discard
\ No newline at end of file
diff --git a/tests/cpp/t23306.nim b/tests/cpp/t23306.nim
new file mode 100644
index 000000000..ebb4edb8d
--- /dev/null
+++ b/tests/cpp/t23306.nim
@@ -0,0 +1,12 @@
+discard """
+targets: "cpp"
+"""
+
+type K = object
+  h: iterator(f: K): K
+
+iterator d(g: K): K {.closure.} =
+  defer:
+    discard
+
+discard K(h: d)
\ No newline at end of file
diff --git a/tests/cpp/t23434.nim b/tests/cpp/t23434.nim
new file mode 100644
index 000000000..04a83227e
--- /dev/null
+++ b/tests/cpp/t23434.nim
@@ -0,0 +1,17 @@
+discard """
+cmd:"nim cpp $file"
+errormsg: "type mismatch: got <proc (self: SomeObject){.member, gcsafe.}>"
+line: 17
+"""
+type SomeObject = object
+    value: int
+
+proc printValue(self: SomeObject) {.virtual.} =
+    echo "The value is ", self.value
+
+proc callAProc(p: proc(self: SomeObject){.noconv.}) =
+    let someObj = SomeObject(value: 4)
+    echo "calling param proc"
+    p(someObj)
+
+callAProc(printValue)
\ No newline at end of file
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/t4834.nim b/tests/cpp/t4834.nim
new file mode 100644
index 000000000..0275b1b70
--- /dev/null
+++ b/tests/cpp/t4834.nim
@@ -0,0 +1,17 @@
+discard """
+  targets: "cpp"
+"""
+
+# issue #4834
+block:
+  defer:
+    let x = 0
+
+
+proc main() =
+  block:
+    defer:
+      raise newException(Exception, "foo")
+
+doAssertRaises(Exception):
+  main()
diff --git a/tests/cpp/t6986.nim b/tests/cpp/t6986.nim
new file mode 100644
index 000000000..16e455c3b
--- /dev/null
+++ b/tests/cpp/t6986.nim
@@ -0,0 +1,19 @@
+discard """
+  targets: "cpp"
+  action: "compile"
+"""
+
+import sequtils, strutils
+
+when defined(nimPreviewSlimSystem):
+  import std/syncio
+
+
+let rules = toSeq(lines("input"))
+  .mapIt(it.split(" => ").mapIt(it.replace("/", "")))
+  .mapIt((it[0], it[1]))
+
+
+proc pp(s: string): auto =
+  toSeq(lines(s)).mapIt(it.split(" => ").mapIt(it.replace("/", ""))).mapIt((it[0], it[1]))
+echo pp("input")
diff --git a/tests/cpp/t8241.nim b/tests/cpp/t8241.nim
new file mode 100644
index 000000000..9aed13fcb
--- /dev/null
+++ b/tests/cpp/t8241.nim
@@ -0,0 +1,32 @@
+discard """
+  targets: "cpp"
+  action: "compile"
+"""
+
+proc foo(): cstring {.importcpp: "", dynlib: "".}
+echo foo()
+
+
+## bug #9222
+import os
+import amodule
+proc findlib2: string =
+  let path = getEnv("MYLIB2_DOES_NOT_EXIST_PATH")
+  if path.len > 0 and dirExists(path):
+    path / "alib_does_not_matter.dll"
+  else:
+    "alib_does_not_matter.dll"
+
+proc imported_func2*(a: cint): cstring {.importc, dynlib: findlib2().}
+
+echo imported_func(1)
+echo imported_func2(1)
+
+# issue #8946
+
+from json import JsonParsingError
+import marshal
+
+const nothing = ""
+doAssertRaises(JsonParsingError):
+  var bar = marshal.to[int](nothing)
diff --git a/tests/cpp/t9013.nim b/tests/cpp/t9013.nim
new file mode 100644
index 000000000..6103cf2e7
--- /dev/null
+++ b/tests/cpp/t9013.nim
@@ -0,0 +1,9 @@
+discard """
+  targets: "cpp"
+  cmd: "nim $target --debugger:native $options $file"
+"""
+
+# The --debugger switch is needed in order to enable the defined(nimTypeNames)
+# code path in hti.nim
+import typeinfo
+var tt: Any
diff --git a/tests/cpp/tasync_cpp.nim b/tests/cpp/tasync_cpp.nim
new file mode 100644
index 000000000..3f4ec6208
--- /dev/null
+++ b/tests/cpp/tasync_cpp.nim
@@ -0,0 +1,15 @@
+discard """
+  targets: "cpp"
+  output: "hello"
+  cmd: "nim cpp --clearNimblePath --nimblePath:build/deps/pkgs2 $file"
+"""
+
+# bug #3299
+
+import jester
+import asyncdispatch, asyncnet
+
+# bug #5081
+#import nre
+
+echo "hello"
diff --git a/tests/cpp/tcasts.nim b/tests/cpp/tcasts.nim
new file mode 100644
index 000000000..80527efff
--- /dev/null
+++ b/tests/cpp/tcasts.nim
@@ -0,0 +1,20 @@
+discard """
+  cmd: "nim cpp $file"
+  targets: "cpp"
+"""
+
+block: #5979
+  var a = 'a'
+  var p: pointer = cast[pointer](a)
+  var c = cast[char](p)
+  doAssert(c == 'a')
+
+
+#----------------------------------------------------
+# bug #9739
+import tables
+
+var t = initTable[string, string]()
+discard t.hasKeyOrPut("123", "123")
+discard t.mgetOrPut("vas", "kas")
+doAssert t.len == 2
diff --git a/tests/cpp/tcodegendecl.nim b/tests/cpp/tcodegendecl.nim
new file mode 100644
index 000000000..e128c5eb7
--- /dev/null
+++ b/tests/cpp/tcodegendecl.nim
@@ -0,0 +1,17 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: "3"
+"""
+
+{.emit:"""/*TYPESECTION*/
+  int operate(int x, int y, int (*func)(const int&, const int&)){
+    return func(x, y);
+  };
+""".}
+
+proc operate(x, y: int32, fn: proc(x, y: int32 ): int32 {.cdecl.}): int32 {.importcpp:"$1(@)".}
+
+proc add(a {.codegenDecl:"const $#& $#".}, b {.codegenDecl:"const $# $#", byref.}: int32): int32  {.cdecl.} = a + b
+
+echo operate(1, 2, add)
\ No newline at end of file
diff --git a/tests/cpp/tconstructor.nim b/tests/cpp/tconstructor.nim
new file mode 100644
index 000000000..922ee54fd
--- /dev/null
+++ b/tests/cpp/tconstructor.nim
@@ -0,0 +1,131 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: '''
+1
+0
+123
+0
+123
+___
+0
+777
+10
+123
+0
+777
+10
+123
+()
+'''
+"""
+
+{.emit:"""/*TYPESECTION*/
+struct CppClass {
+  int x;
+  int y;
+  CppClass(int inX, int inY) {
+    this->x = inX;
+    this->y = inY;
+  }
+  //CppClass() = default;
+};
+""".}
+
+type  CppClass* {.importcpp, inheritable.} = object
+  x: int32
+  y: int32
+
+proc makeCppClass(x, y: int32): CppClass {.importcpp: "CppClass(@)", constructor.}
+#test globals are init with the constructor call
+var shouldCompile {.used.} = makeCppClass(1, 2)
+
+proc newCpp*[T](): ptr T {.importcpp:"new '*0()".}
+
+#creation
+type NimClassNoNarent* = object
+  x: int32
+
+proc makeNimClassNoParent(x:int32): NimClassNoNarent {. constructor.} =
+  result.x = x
+  discard
+
+let nimClassNoParent = makeNimClassNoParent(1)
+echo nimClassNoParent.x #acess to this just fine. Notice the field will appear last because we are dealing with constructor calls here
+
+var nimClassNoParentDef {.used.}: NimClassNoNarent  #test has a default constructor. 
+
+#inheritance 
+type NimClass* = object of CppClass
+
+proc makeNimClass(x:int32): NimClass {. constructor:"NimClass('1 #1) : CppClass(0, #1) ".} =
+  result.x = x
+
+#optinially define the default constructor so we get rid of the cpp warn and we can declare the obj (note: default constructor of 'tyObject_NimClass__apRyyO8cfRsZtsldq1rjKA' is implicitly deleted because base class 'CppClass' has no default constructor)
+proc makeCppClass(): NimClass {. constructor: "NimClass() : CppClass(0, 0) ".} = 
+  result.x = 1
+
+let nimClass = makeNimClass(1)
+var nimClassDef {.used.}: NimClass  #since we explictly defined the default constructor we can declare the obj
+
+#bug: 22662
+type
+  BugClass* = object
+    x: int          # Not initialized
+
+proc makeBugClass(): BugClass {.constructor.} =
+  discard
+
+proc main =
+  for i in 0 .. 1:
+    var n = makeBugClass()
+    echo n.x
+    n.x = 123
+    echo n.x
+
+main()
+#bug:
+echo "___"
+type
+  NimClassWithDefault = object
+    x: int
+    y = 777
+    case kind: bool = true
+    of true:
+      z: int = 10
+    else: discard
+
+proc makeNimClassWithDefault(): NimClassWithDefault {.constructor.} =
+  result = NimClassWithDefault()
+
+proc init =
+  for i in 0 .. 1:
+    var n = makeNimClassWithDefault()
+    echo n.x
+    echo n.y
+    echo n.z
+    n.x = 123
+    echo n.x
+
+init()
+
+#tests that the ctor is not declared with nodecl. 
+#nodelc also prevents the creation of a default one when another is created.
+type Foo {.exportc.} = object
+
+proc makeFoo(): Foo {.used, constructor, nodecl.} = discard
+
+echo $Foo()
+
+type Boo = object
+proc `=copy`(dest: var Boo; src: Boo) = discard
+
+proc makeBoo(): Boo {.constructor.} = Boo()
+proc makeBoo2(): Boo  = Boo()
+
+block:
+  proc main =
+    var b = makeBoo()
+    var b2 = makeBoo2()
+
+  main()
\ No newline at end of file
diff --git a/tests/cpp/tcovariancerules.nim b/tests/cpp/tcovariancerules.nim
new file mode 100644
index 000000000..9d49f2cbd
--- /dev/null
+++ b/tests/cpp/tcovariancerules.nim
@@ -0,0 +1,417 @@
+discard """
+targets: "cpp"
+output: '''
+cat
+cat
+dog
+dog
+cat
+cat
+dog
+dog X
+cat
+cat
+dog
+dog
+dog
+dog
+dog 1
+dog 2
+'''
+"""
+
+template accept(x) =
+  static: assert(compiles(x))
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+import macros
+
+macro skipElse(n: untyped): untyped = n[0]
+
+template acceptWithCovariance(x, otherwise): untyped =
+  when defined nimEnableCovariance:
+    x
+  else:
+    reject(x)
+    skipElse(otherwise)
+
+type
+  Animal = object of RootObj
+    x: string
+
+  Dog = object of Animal
+    y: int
+
+  Cat = object of Animal
+    z: int
+
+  AnimalRef = ref Animal
+  AnimalPtr = ptr Animal
+
+  RefAlias[T] = ref T
+
+var dog = new(Dog)
+dog.x = "dog"
+
+var cat = new(Cat)
+cat.x = "cat"
+
+proc makeDerivedRef(x: string): ref Dog =
+  new(result)
+  result.x = x
+
+proc makeDerived(x: string): Dog =
+  result.x = x
+
+var covariantSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
+var nonCovariantSeq = @[makeDerived("dog 1"), makeDerived("dog 2")]
+var covariantArr = [makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
+var nonCovariantArr = [makeDerived("dog 1"), makeDerived("dog 2")]
+
+proc wantsCovariantSeq1(s: seq[ref Animal]) =
+  for a in s: echo a.x
+
+proc wantsCovariantSeq2(s: seq[AnimalRef]) =
+  for a in s: echo a.x
+
+proc wantsCovariantSeq3(s: seq[RefAlias[Animal]]) =
+  for a in s: echo a.x
+
+proc wantsCovariantOpenArray(s: openArray[ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantOpenArray(s: var openArray[ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesDerivedOpenArray(s: var openArray[ref Dog]) =
+  for a in s: echo a.x
+
+proc wantsNonCovariantOpenArray(s: openArray[Animal]) =
+  for a in s: echo a.x
+
+proc wantsCovariantArray(s: array[2, ref Animal]) =
+  for a in s: echo a.x
+
+proc wantsNonCovariantSeq(s: seq[Animal]) =
+  for a in s: echo a.x
+
+proc wantsNonCovariantArray(s: array[2, Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantSeq(s: var seq[ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantArray(s: var array[2, ref Animal]) =
+  for a in s: echo a.x
+
+proc modifiesCovariantSeq(s: ptr seq[ref Animal]) =
+  for a in s[]: echo a.x
+
+proc modifiesCovariantArray(s: ptr array[2, ref Animal]) =
+  for a in s[]: echo a.x
+
+proc modifiesDerivedSeq(s: var seq[ref Dog]) =
+  for a in s: echo a.x
+
+proc modifiesDerivedArray(s: var array[2, ref Dog]) =
+  for a in s: echo a.x
+
+proc modifiesDerivedSeq(s: ptr seq[ref Dog]) =
+  for a in s[]: echo a.x
+
+proc modifiesDerivedArray(s: ptr array[2, ref Dog]) =
+  for a in s[]: echo a.x
+
+accept:
+  wantsCovariantArray([AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantArray([AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantArray([AnimalRef(cat), dog])
+
+  # there is a special rule that detects the base
+  # type of polymorphic arrays
+  wantsCovariantArray([cat, dog])
+
+acceptWithCovariance:
+  wantsCovariantArray([cat, cat])
+else:
+  echo "cat"
+  echo "cat"
+
+var animalRefArray: array[2, ref Animal]
+
+accept:
+  animalRefArray = [AnimalRef(dog), AnimalRef(dog)]
+  animalRefArray = [AnimalRef(cat), dog]
+
+acceptWithCovariance:
+  animalRefArray = [dog, dog]
+  wantsCovariantArray animalRefArray
+else:
+  echo "dog"
+  echo "dog"
+
+accept:
+  var animal: AnimalRef = dog
+  animal = cat
+
+var vdog: Dog
+vdog.x = "dog value"
+var vcat: Cat
+vcat.x = "cat value"
+
+reject:
+  vcat = vdog
+
+# XXX: The next two cases seem inconsistent, perhaps we should change the rules
+accept:
+  # truncating copies are allowed
+  var vanimal: Animal = vdog
+  vanimal = vdog
+
+reject:
+  # truncating copies are not allowed with arrays
+  var vanimalArray: array[2, Animal]
+  var vdogArray = [vdog, vdog]
+  vanimalArray = vdogArray
+
+accept:
+  # a more explicit version of a truncating copy that
+  # should probably always remain allowed
+  var vnextnimal: Animal = Animal(vdog)
+
+proc wantsRefSeq(x: seq[AnimalRef]) = discard
+
+accept:
+  wantsCovariantSeq1(@[AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantSeq1(@[AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantSeq1(@[AnimalRef(cat), dog])
+  wantsCovariantSeq1(@[cat, dog])
+
+  wantsCovariantSeq2(@[AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantSeq2(@[AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantSeq2(@[AnimalRef(cat), dog])
+  wantsCovariantSeq2(@[cat, dog])
+
+  wantsCovariantSeq3(@[AnimalRef(dog), AnimalRef(dog)])
+  wantsCovariantSeq3(@[AnimalRef(cat), AnimalRef(dog)])
+  wantsCovariantSeq3(@[AnimalRef(cat), dog])
+  wantsCovariantSeq3(@[cat, dog])
+
+  wantsCovariantOpenArray([cat, dog])
+
+acceptWithCovariance:
+  wantsCovariantSeq1(@[cat, cat])
+  wantsCovariantSeq2(@[dog, makeDerivedRef("dog X")])
+  # XXX: wantsCovariantSeq3(@[cat, cat])
+
+  wantsCovariantOpenArray(@[cat, cat])
+  wantsCovariantOpenArray([dog, dog])
+else:
+  echo "cat"
+  echo "cat"
+  echo "dog"
+  echo "dog X"
+  echo "cat"
+  echo "cat"
+  echo "dog"
+  echo "dog"
+
+var dogRefs = @[dog, dog]
+var dogRefsArray = [dog, dog]
+var animalRefs = @[dog, cat]
+
+accept:
+  modifiesDerivedArray(dogRefsArray)
+  modifiesDerivedSeq(dogRefs)
+
+reject modifiesCovariantSeqd(ogRefs)
+reject modifiesCovariantSeq(addr(dogRefs))
+reject modifiesCovariantSeq(dogRefs.addr)
+
+reject modifiesCovariantArray([dog, dog])
+reject modifiesCovariantArray(dogRefsArray)
+reject modifiesCovariantArray(addr(dogRefsArray))
+reject modifiesCovariantArray(dogRefsArray.addr)
+
+var dogValues = @[vdog, vdog]
+var dogValuesArray = [vdog, vdog]
+when false:
+  var animalValues = @[Animal(vdog), Animal(vcat)]
+  var animalValuesArray = [Animal(vdog), Animal(vcat)]
+
+  wantsNonCovariantSeq animalValues
+  wantsNonCovariantArray animalValuesArray
+
+reject wantsNonCovariantSeq(dogRefs)
+reject modifiesCovariantOpenArray(dogRefs)
+reject wantsNonCovariantArray(dogRefsArray)
+reject wantsNonCovariantSeq(dogValues)
+reject wantsNonCovariantArray(dogValuesArray)
+reject modifiesValueArray()
+
+modifiesDerivedOpenArray dogRefs
+reject modifiesDerivedOpenArray(dogValues)
+reject modifiesDerivedOpenArray(animalRefs)
+
+reject wantsNonCovariantOpenArray(animalRefs)
+reject wantsNonCovariantOpenArray(dogRefs)
+reject wantsNonCovariantOpenArray(dogValues)
+
+var animalRefSeq: seq[ref Animal]
+
+accept:
+  animalRefSeq = @[AnimalRef(dog), AnimalRef(dog)]
+  animalRefSeq = @[AnimalRef(cat), dog]
+
+acceptWithCovariance:
+  animalRefSeq = @[makeDerivedRef("dog 1"), makeDerivedRef("dog 2")]
+  wantsCovariantSeq1(animalRefSeq)
+else:
+  echo "dog 1"
+  echo "dog 2"
+
+var pdog: ptr Dog
+var pcat: ptr Cat
+
+proc wantsPointer(x: ptr Animal) =
+  discard
+
+accept:
+  wantsPointer pdog
+  wantsPointer pcat
+
+# covariance should be disabled when var is involved
+proc wantsVarPointer1(x: var ptr Animal) =
+  discard
+
+proc wantsVarPointer2(x: var AnimalPtr) =
+  discard
+
+reject wantsVarPointer1(pdog)
+reject wantsVarPointer2(pcat)
+
+# covariance may be allowed for certain extern types
+
+{.emit: """/*TYPESECTION*/
+template <class T> struct FN { typedef void (*type)(T); };
+template <class T> struct ARR { typedef T DataType[2]; DataType data; };
+""".}
+
+type
+  MyPtr[out T] {.importcpp: "'0 *"}  = object
+
+  MySeq[out T] {.importcpp: "ARR<'0>", nodecl}  = object
+    data: array[2, T]
+
+  MyAction[in T] {.importcpp: "FN<'0>::type"}  = object
+
+var
+  cAnimal: MyPtr[Animal]
+  cDog: MyPtr[Dog]
+  cCat: MyPtr[Cat]
+
+  cAnimalFn: MyAction[Animal]
+  cCatFn: MyAction[Cat]
+  cDogFn: MyAction[Dog]
+
+  cRefAnimalFn: MyAction[ref Animal]
+  cRefCatFn: MyAction[ref Cat]
+  cRefDogFn: MyAction[ref Dog]
+
+accept:
+  cAnimal = cDog
+  cAnimal = cCat
+
+  cDogFn = cAnimalFn
+  cCatFn = cAnimalFn
+
+  cRefDogFn = cRefAnimalFn
+  cRefCatFn = cRefAnimalFn
+
+reject: cDogFn = cRefAnimalFn
+reject: cCatFn = cRefAnimalFn
+
+reject: cCat = cDog
+reject: cAnimalFn = cDogFn
+reject: cAnimalFn = cCatFn
+reject: cRefAnimalFn = cRefDogFn
+reject: cRefAnimalFn = cRefCatFn
+reject: cRefAnimalFn = cDogFn
+
+var
+  ptrPtrDog: ptr ptr Dog
+  ptrPtrAnimal: ptr ptr Animal
+
+reject: ptrPtrDog = ptrPtrAnimal
+
+# Try to break the rules by introducing some tricky
+# double indirection types:
+var
+  cPtrRefAnimal: MyPtr[ref Animal]
+  cPtrRefDog: MyPtr[ref Dog]
+
+  cPtrAliasRefAnimal: MyPtr[RefAlias[Animal]]
+  cPtrAliasRefDog: MyPtr[RefAlias[Dog]]
+
+  cDoublePtrAnimal: MyPtr[MyPtr[Animal]]
+  cDoublePtrDog: MyPtr[MyPtr[Dog]]
+
+reject: cPtrRefAnimal = cPtrRefDog
+reject: cDoublePtrAnimal = cDoublePtrDog
+reject: cRefAliasPtrAnimal = cRefAliasPtrDog
+reject: cPtrRefAnimal = cRefAliasPtrDog
+reject: cPtrAliasRefAnimal = cPtrRefDog
+
+var
+  # Array and Sequence types are covariant only
+  # when instantiated with ref or ptr types:
+  cAnimals: MySeq[ref Animal]
+  cDogs: MySeq[ref Dog]
+
+  # "User-defined" pointer types should be OK too:
+  cAnimalPtrSeq: MySeq[MyPtr[Animal]]
+  cDogPtrSeq: MySeq[MyPtr[Dog]]
+
+  # Value types shouldn't work:
+  cAnimalValues: MySeq[Animal]
+  cDogValues: MySeq[Dog]
+
+  # Double pointer types should not work either:
+  cAnimalRefPtrSeq: MySeq[ref MyPtr[Animal]]
+  cDogRefPtrSeq: MySeq[ref MyPtr[Dog]]
+  cAnimalPtrPtrSeq: MySeq[ptr ptr Animal]
+  cDogPtrPtrSeq: MySeq[ptr ptr Dog]
+
+accept:
+  cAnimals = cDogs
+  cAnimalPtrSeq = cDogPtrSeq
+
+reject: cAnimalValues = cDogValues
+reject: cAnimalRefPtrSeq = cDogRefPtrSeq
+reject: cAnimalPtrPtrSeq = cDogPtrPtrSeq
+
+proc wantsAnimalSeq(x: MySeq[Animal]) = discard
+proc wantsAnimalRefSeq(x: MySeq[ref Animal]) = discard
+proc modifiesAnimalRefSeq(x: var MySeq[ref Animal]) = discard
+proc usesAddressOfAnimalRefSeq(x: ptr MySeq[ref Animal]) = discard
+
+accept wantsAnimalSeq(cAnimalValues)
+reject wantsAnimalSeq(cDogValues)
+reject wantsAnimalSeq(cAnimals)
+
+reject wantsAnimalRefSeq(cAnimalValues)
+reject wantsAnimalRefSeq(cDogValues)
+accept wantsAnimalRefSeq(cAnimals)
+accept wantsAnimalRefSeq(cDogs)
+
+reject modifiesAnimalRefSeq(cAnimalValues)
+reject modifiesAnimalRefSeq(cDogValues)
+accept modifiesAnimalRefSeq(cAnimals)
+reject modifiesAnimalRefSeq(cDogs)
+
+reject usesAddressOfAnimalRefSeq(addr cAnimalValues)
+reject usesAddressOfAnimalRefSeq(addr cDogValues)
+accept usesAddressOfAnimalRefSeq(addr cAnimals)
+reject usesAddressOfAnimalRefSeq(addr cDogs)
diff --git a/tests/cpp/tcppraise.nim b/tests/cpp/tcppraise.nim
new file mode 100644
index 000000000..f03956d4c
--- /dev/null
+++ b/tests/cpp/tcppraise.nim
@@ -0,0 +1,71 @@
+discard """
+  targets: "cpp"
+  output: '''foo
+bar
+Need odd and >= 3 digits##
+baz
+caught
+--------
+Triggered raises2
+Raising ValueError
+'''
+"""
+
+# bug #1888
+echo "foo"
+try:
+  echo "bar"
+  raise newException(ValueError, "Need odd and >= 3 digits")
+#  echo "baz"
+except ValueError:
+  echo getCurrentExceptionMsg(), "##"
+echo "baz"
+
+
+# bug 7232
+try:
+ discard
+except KeyError, ValueError:
+  echo "except handler" # should not be invoked
+
+
+#bug 7239
+try:
+  try:
+    raise newException(ValueError, "asdf")
+  except KeyError, ValueError:
+    raise
+except:
+  echo "caught"
+
+
+# issue 5549
+
+var strs: seq[string] = @[]
+
+try:
+  discard
+finally:
+  for foobar in strs:
+    discard
+
+
+# issue #11118
+echo "--------"
+proc raises() =
+  raise newException(ValueError, "Raising ValueError")
+
+proc raises2() =
+  try:
+    raises()
+  except ValueError as e:
+    echo "Triggered raises2"
+    raise e
+
+try:
+  raises2()
+except:
+  echo getCurrentExceptionMsg()
+  discard
+
+doAssert: getCurrentException() == nil
diff --git a/tests/cpp/tdont_init_instantiation.nim b/tests/cpp/tdont_init_instantiation.nim
new file mode 100644
index 000000000..a13a3f6b4
--- /dev/null
+++ b/tests/cpp/tdont_init_instantiation.nim
@@ -0,0 +1,29 @@
+discard """
+  targets: "cpp"
+  output: ''''''
+  disabled: true
+"""
+
+# bug #5140
+{.emit:"""
+#import <cassert>
+
+template <typename X> class C {
+  public:
+    int d;
+
+    C(): d(1) { }
+
+    C<X>& operator=(const C<X> other) {
+      assert(d == 1);
+    }
+};
+""".}
+
+type C[X] {.importcpp, header: "<stdio.h>", nodecl.} = object
+proc mkC[X]: C[X] {.importcpp: "C<'*0>()", constructor, nodecl.}
+
+proc foo(): C[int] =
+  result = mkC[int]()
+
+let gl = foo()
diff --git a/tests/cpp/tembarrassing_generic_bug.nim b/tests/cpp/tembarrassing_generic_bug.nim
new file mode 100644
index 000000000..4b5050948
--- /dev/null
+++ b/tests/cpp/tembarrassing_generic_bug.nim
@@ -0,0 +1,9 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp --threads:on $file"
+"""
+
+# bug #5142
+
+var ci: Channel[int]
+ci.open
diff --git a/tests/cpp/temitlist.nim b/tests/cpp/temitlist.nim
new file mode 100644
index 000000000..9170be079
--- /dev/null
+++ b/tests/cpp/temitlist.nim
@@ -0,0 +1,38 @@
+discard """
+  targets: "cpp"
+  output: '''
+6.0
+0'''
+disabled: "windows" # pending bug #18011
+"""
+
+# bug #4730
+
+type Vector*[T] {.importcpp: "std::vector", header: "<vector>".} = object
+
+template `[]=`*[T](v: var Vector[T], key: int, val: T) =
+  {.emit: [v, "[", key, "] = ", val, ";"].}
+
+proc setLen*[T](v: var Vector[T]; size: int) {.importcpp: "resize", nodecl.}
+proc `[]`*[T](v: var Vector[T], key: int): T {.importcpp: "(#[#])", nodecl.}
+
+proc main =
+  var v: Vector[float]
+  v.setLen 1
+  v[0] = 6.0
+  echo v[0]
+
+main()
+
+#------------
+
+#bug #6837
+type StdString {.importCpp: "std::string", header: "<string>", byref.} = object
+proc initString(): StdString {.constructor, importCpp: "std::string(@)", header: "<string>".}
+proc size(this: var StdString): csize_t {.importCpp: "size", header: "<string>".}
+
+proc f(): csize_t =
+  var myString: StdString = initString()
+  return myString.size()
+
+echo f()
diff --git a/tests/cpp/tempty_generic_obj.nim b/tests/cpp/tempty_generic_obj.nim
new file mode 100644
index 000000000..6125190b4
--- /dev/null
+++ b/tests/cpp/tempty_generic_obj.nim
@@ -0,0 +1,47 @@
+discard """
+  targets: "cpp"
+  output: '''
+int
+float'''
+disabled: "windows" # pending bug #18011
+"""
+
+import typetraits
+
+# bug #4625
+type
+  Vector[T] {.importcpp: "std::vector<'0 >", header: "vector".} = object
+
+proc initVector[T](): Vector[T] {.importcpp: "'0(@)", header: "vector", constructor.}
+
+proc doSomething[T](v: var Vector[T]) =
+  echo T.name
+
+var v = initVector[int]()
+v.doSomething()
+
+var vf = initVector[float]()
+vf.doSomething() # Nim uses doSomething[int] here in C++
+
+# Alternative definition:
+# https://github.com/nim-lang/Nim/issues/7653
+
+type VectorAlt*[T] {.importcpp: "std::vector", header: "<vector>", nodecl.} = object
+proc mkVector*[T]: VectorAlt[T] {.importcpp: "std::vector<'*0>()", header: "<vector>", constructor, nodecl.}
+
+proc foo(): VectorAlt[cint] =
+  mkVector[cint]()
+
+proc bar(): VectorAlt[cstring] =
+  mkVector[cstring]()
+
+var x = foo()
+var y = bar()
+
+proc init[T; Self: Vector[T]](_: typedesc[Self], n: csize_t): Vector[T]
+  {.importcpp: "std::vector<'*0>(@)", header: "<vector>", constructor, nodecl.}
+proc size[T](x: Vector[T]): csize_t
+  {.importcpp: "#.size()", header: "<vector>", nodecl.}
+
+var z = Vector[int16].init(32)
+assert z.size == 32
diff --git a/tests/cpp/tenum_set.nim b/tests/cpp/tenum_set.nim
new file mode 100644
index 000000000..6afed722f
--- /dev/null
+++ b/tests/cpp/tenum_set.nim
@@ -0,0 +1,9 @@
+discard """
+targets: "cpp"
+output: "{A, B, C}"
+"""
+
+type Enum {.importcpp: "namespaced::Enum", header: "enum.hpp".} = enum A, B, C
+
+var vals = {low(Enum) .. high(Enum)}
+echo vals
diff --git a/tests/cpp/tevalorder.nim b/tests/cpp/tevalorder.nim
new file mode 100644
index 000000000..4764f3aca
--- /dev/null
+++ b/tests/cpp/tevalorder.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''0
+1
+2'''
+targets: "cpp"
+"""
+
+# bug #8202
+var current: int = 0
+
+proc gen(): string = current.inc; $(current - 1)
+
+proc allOut(a, b, c: string) =
+    echo a
+    echo b
+    echo c
+
+allOut(gen(), gen(), gen())
diff --git a/tests/cpp/texportc.nim b/tests/cpp/texportc.nim
new file mode 100644
index 000000000..3a2fa8748
--- /dev/null
+++ b/tests/cpp/texportc.nim
@@ -0,0 +1,22 @@
+discard """
+  targets: "c cpp"
+"""
+
+var fun0 {.importc.}: int
+proc fun1() {.importc.}
+proc fun2() {.importc: "$1".}
+proc fun3() {.importc: "fun3Bis".}
+
+when defined cpp:
+  # proc funx1() {.importcpp.} # this does not work yet
+  proc funx1() {.importc: "_Z5funx1v".}
+
+doAssert fun0 == 10
+fun1()
+fun2()
+fun3()
+
+when defined cpp:
+  funx1()
+
+import ./mexportc
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/cpp/tgen_prototype_for_importc.nim b/tests/cpp/tgen_prototype_for_importc.nim
new file mode 100644
index 000000000..4e5a197a8
--- /dev/null
+++ b/tests/cpp/tgen_prototype_for_importc.nim
@@ -0,0 +1,10 @@
+discard """
+  targets: "cpp"
+  output: '''Hello world'''
+"""
+
+# bug #5136
+
+{.compile: "foo.c".}
+proc myFunc(): cstring {.importc.}
+echo myFunc()
diff --git a/tests/cpp/tget_subsystem.nim b/tests/cpp/tget_subsystem.nim
new file mode 100644
index 000000000..6fb095a3d
--- /dev/null
+++ b/tests/cpp/tget_subsystem.nim
@@ -0,0 +1,39 @@
+discard """
+  targets: "cpp"
+"""
+
+{.emit: """
+
+namespace System {
+  struct Input {};
+}
+
+struct SystemManager {
+  template <class T>
+  static T* getSubsystem() { return new T; }
+};
+
+""".}
+
+type Input {.importcpp: "System::Input".} = object
+proc getSubsystem*[T](): ptr T {.
+  importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
+
+let input: ptr Input = getSubsystem[Input]()
+
+
+# bugs #4910, #6892 
+proc modify(x: var int) = 
+  x = 123
+
+proc foo() =
+  var ts: array[2, int]
+  for t in mitems(ts):
+    discard
+
+  for t in mitems(ts):
+     modify(t)
+
+  for i, t in mpairs(ts):
+    modify(t)
+
diff --git a/tests/cpp/tinitializers.nim b/tests/cpp/tinitializers.nim
new file mode 100644
index 000000000..0199fb96b
--- /dev/null
+++ b/tests/cpp/tinitializers.nim
@@ -0,0 +1,60 @@
+discard """
+  cmd: "nim cpp $file"
+"""
+
+{.emit:"""/*TYPESECTION*/
+struct CppStruct {
+  CppStruct(int x, char* y): x(x), y(y){}
+  void doSomething() {}
+  int x;
+  char* y;
+};
+""".}
+type
+  CppStruct {.importcpp, inheritable.} = object
+  ChildStruct = object of CppStruct
+  HasCppStruct = object
+    cppstruct: CppStruct 
+
+proc constructCppStruct(a:cint = 5, b:cstring = "hello"): CppStruct {.importcpp: "CppStruct(@)", constructor.}
+proc doSomething(this: CppStruct) {.importcpp.}
+proc returnCppStruct(): CppStruct = discard
+proc initChildStruct: ChildStruct = ChildStruct() 
+proc makeChildStruct(): ChildStruct {.constructor:"""ChildStruct(): CppStruct(5, "10")""".} = discard
+proc initHasCppStruct(x: cint): HasCppStruct =
+  HasCppStruct(cppstruct: constructCppStruct(x))
+
+proc main =
+  var hasCppStruct = initHasCppStruct(2) #generates cppstruct = { 10 } inside the struct
+  hasCppStruct.cppstruct.doSomething() 
+  discard returnCppStruct() #generates result = { 10 } 
+  discard initChildStruct() #generates ChildStruct temp ({}) bypassed with makeChildStruct
+  (proc (s:CppStruct) = discard)(CppStruct()) #CppStruct temp ({10})
+main()
+
+
+#Should handle ObjectCalls
+{.emit:"""/*TYPESECTION*/
+struct Foo {
+};
+struct Boo {
+  Boo(int x, char* y, Foo f): x(x), y(y), foo(f){}
+  int x;
+  char* y;
+  Foo foo;
+};
+""".}
+type
+  Foo {.importcpp, inheritable, bycopy.} = object
+  Boo {.importcpp, inheritable.} = object
+    x: int32
+    y: cstring
+    foo: Foo
+
+proc makeBoo(a:cint = 10, b:cstring = "hello", foo: Foo = Foo()): Boo {.importcpp, constructor.}
+
+proc main2() = 
+  let cppStruct = makeBoo()
+  (proc (s:Boo) = discard)(Boo()) 
+
+main2()
\ No newline at end of file
diff --git a/tests/cpp/tmember.nim b/tests/cpp/tmember.nim
new file mode 100644
index 000000000..1a5b6fd97
--- /dev/null
+++ b/tests/cpp/tmember.nim
@@ -0,0 +1,75 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: '''
+2
+false
+hello foo
+hello boo
+hello boo
+FunctorSupport!
+static
+static
+destructing
+destructing
+'''
+"""
+proc print(s: cstring) {.importcpp:"printf(@)", header:"<stdio.h>".}
+
+type
+  Doo  {.exportc.} = object
+    test: int
+
+proc memberProc(f: Doo) {.exportc, member.} = 
+  echo $f.test
+
+proc destructor(f: Doo) {.member: "~'1()", used.} = 
+  print "destructing\n"
+
+proc `==`(self, other: Doo): bool {.member:"operator==('2 const & #2) const -> '0"} = 
+  self.test == other.test
+
+let doo = Doo(test: 2)
+doo.memberProc()
+echo doo == Doo(test: 1)
+
+#virtual
+proc newCpp*[T](): ptr T {.importcpp:"new '*0()".}
+type 
+  Foo {.exportc.} = object of RootObj
+  FooPtr = ptr Foo
+  Boo = object of Foo
+  BooPtr = ptr Boo
+
+proc salute(self: FooPtr) {.member: "virtual $1()".} = 
+  echo "hello foo"
+
+proc salute(self: BooPtr) {.member: "virtual $1()".} =
+  echo "hello boo"
+
+let foo = newCpp[Foo]()
+let boo = newCpp[Boo]()
+let booAsFoo = cast[FooPtr](newCpp[Boo]())  
+
+foo.salute()
+boo.salute()
+booAsFoo.salute()
+
+type
+  NimFunctor = object
+    discard
+proc invoke(f: NimFunctor, n:int) {.member:"operator ()('2 #2)" .} = 
+  echo "FunctorSupport!"
+
+{.experimental: "callOperator".}
+proc `()`(f: NimFunctor, n:int) {.importcpp:"#(@)" .} 
+NimFunctor()(1)
+
+#static
+proc staticProc(self: FooPtr) {.member: "static $1()".} = 
+  echo "static"
+
+proc importedStaticProc() {.importcpp:"Foo::staticProc()".}
+
+foo.staticProc()
+importedStaticProc()
diff --git a/tests/cpp/tmember_forward_declaration.nim b/tests/cpp/tmember_forward_declaration.nim
new file mode 100644
index 000000000..2f4a79daa
--- /dev/null
+++ b/tests/cpp/tmember_forward_declaration.nim
@@ -0,0 +1,27 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: '''
+abc called
+def called
+abc called
+'''
+"""
+
+type Foo = object
+
+proc abc(this: Foo, x: int): void {.member: "$1('2 #2)".}
+proc def(this: Foo, y: int): void {.virtual: "$1('2 #2)".}
+
+proc abc(this: Foo, x: int): void =
+  echo "abc called"
+  if x > 0:
+    this.def(x - 1)
+
+proc def(this: Foo, y: int): void =
+  echo "def called"
+  this.abc(y)
+
+var x = Foo()
+x.abc(1)
+
diff --git a/tests/cpp/tnativesockets.nim b/tests/cpp/tnativesockets.nim
new file mode 100644
index 000000000..1284811b5
--- /dev/null
+++ b/tests/cpp/tnativesockets.nim
@@ -0,0 +1,6 @@
+discard """
+  targets: "cpp"
+outputsub: ""
+"""
+
+import nativesockets
diff --git a/tests/cpp/tnoinitfield.nim b/tests/cpp/tnoinitfield.nim
new file mode 100644
index 000000000..4deffece8
--- /dev/null
+++ b/tests/cpp/tnoinitfield.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: '''
+'''
+"""
+{.emit: """/*TYPESECTION*/
+  struct Foo {
+    Foo(int a){};
+  };
+  struct Boo {
+    Boo(int a){};
+  };
+
+  """.}
+
+type 
+  Foo {.importcpp.} = object
+  Boo {.importcpp, noInit.} = object
+  Test {.exportc.} = object
+    foo {.noInit.}: Foo
+    boo: Boo
+
+proc makeTest(): Test {.constructor: "Test() : foo(10), boo(1)".} = 
+  discard
+
+proc main() = 
+  var t = makeTest()
+
+main()
\ No newline at end of file
diff --git a/tests/cpp/torc.nim b/tests/cpp/torc.nim
new file mode 100644
index 000000000..9f1a41a21
--- /dev/null
+++ b/tests/cpp/torc.nim
@@ -0,0 +1,75 @@
+discard """
+  targets: "cpp"
+  matrix: "--gc:orc"
+"""
+
+import std/options
+
+# bug #18410
+type
+  O = object of RootObj
+   val: pointer
+
+proc p(): Option[O] = none(O)
+
+doAssert $p() == "none(O)"
+
+# bug #17351
+type
+  Foo = object of RootObj
+  Foo2 = object of Foo
+  Bar = object
+    x: Foo2
+
+var b = Bar()
+discard b
+
+# bug #4678
+{.emit: """/*TYPESECTION*/
+enum class SomeEnum {A,B,C};
+""".}
+type
+  EnumVector[T: enum] {.importcpp: "std::vector", header: "vector".} = object
+  SomeEnum {.importcpp, nodecl.} = enum
+    A,B,C
+
+proc asVector*[T](t: T): EnumVector[T] =
+  discard
+# Nim generates this signature here:
+# N_NIMCALL(std::vector<> , asvector_106028_3197418230)(SomeEnum t0)
+
+discard asVector(SomeEnum.A)
+
+
+block: # bug #10219
+  type
+    Vector[T]  {.importcpp: "std::vector", header: "vector".} = object
+
+  proc initVector[T](n: csize_t): Vector[T] 
+      {.importcpp: "std::vector<'*0>(@)", header: "vector".}
+
+  proc unsafeIndex[T](this: var Vector[T], i: csize_t): var T 
+      {.importcpp: "#[#]", header: "vector".}
+
+  proc `[]`[T](this: var Vector[T], i: Natural): var T {.inline, noinit.} =
+    when compileOption("boundChecks"):
+        # this.checkIndex i
+        discard
+    result = this.unsafeIndex(csize_t(i))
+
+  var v1 = initVector[int](10)
+  doAssert v1[0] == 0
+
+block: # bug #12703 bug #19588
+  type
+    cstringConstImpl {.importc:"const char*".} = cstring
+    constChar = distinct cstringConstImpl
+
+  {.emit: """
+  const char* foo() {
+    return "hello";
+  }
+  """.}
+  proc foo(): constChar {.importcpp.} # change to importcpp for C++ backend
+  doAssert $(foo().cstring) == "hello"
+
diff --git a/tests/cpp/tpassbypragmas.nim b/tests/cpp/tpassbypragmas.nim
new file mode 100644
index 000000000..f4301656a
--- /dev/null
+++ b/tests/cpp/tpassbypragmas.nim
@@ -0,0 +1,27 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+"""
+{.emit:"""/*TYPESECTION*/
+
+  template<typename T>
+  struct Box {
+      T first;
+  };
+  struct Foo {
+  void test(void (*func)(Box<Foo>& another)){
+
+    };
+  };
+""".}
+
+type 
+  Foo {.importcpp.} = object
+  Box[T] {.importcpp:"Box<'0>".} = object
+    first: T
+
+proc test(self: Foo, fn: proc(another {.byref.}: Box[Foo]) {.cdecl.}) {.importcpp.}
+
+proc fn(another {.byref.} : Box[Foo]) {.cdecl.} = discard
+
+Foo().test(fn)
\ No newline at end of file
diff --git a/tests/cpp/treturn_array.nim b/tests/cpp/treturn_array.nim
new file mode 100644
index 000000000..432b9ce3b
--- /dev/null
+++ b/tests/cpp/treturn_array.nim
@@ -0,0 +1,13 @@
+discard """
+  targets: "cpp"
+"""
+
+# bug #2259
+type Mat4f* = array[0..15, float]
+
+proc get_rot_mat*(): Mat4f = discard
+var mat: Mat4f = get_rot_mat()
+
+# bug #1389
+proc calcSizes(): array[2, int] = discard
+let sizes: array[2, int] = calcSizes()
diff --git a/tests/cpp/tretvar.nim b/tests/cpp/tretvar.nim
new file mode 100644
index 000000000..0c3765346
--- /dev/null
+++ b/tests/cpp/tretvar.nim
@@ -0,0 +1,39 @@
+discard """
+  targets: "cpp"
+  output: '''test1
+xest1
+'''
+"""
+{.passC: "-std=c++14".}
+
+{.experimental: "dotOperators".}
+
+import macros
+
+type
+  stdString {.importcpp: "std::string", header: "<string>".} = object
+  stdUniquePtr[T] {.importcpp: "std::unique_ptr", header: "<memory>".} = object
+
+proc c_str(a: stdString): cstring {.importcpp: "(char *)(#.c_str())", header: "<string>".}
+
+proc len(a: stdString): csize_t {.importcpp: "(#.length())", header: "<string>".}
+
+proc setChar(a: var stdString, i: csize_t, c: char) {.importcpp: "(#[#] = #)", header: "<string>".}
+
+proc `*`*[T](this: stdUniquePtr[T]): var T {.noSideEffect, importcpp: "(* #)", header: "<memory>".}
+
+proc make_unique_str(a: cstring): stdUniquePtr[stdString] {.importcpp: "std::make_unique<std::string>(#)", header: "<string>".}
+
+macro `.()`*[T](this: stdUniquePtr[T], name: untyped, args: varargs[untyped]): untyped =
+  result = nnkCall.newTree(
+    nnkDotExpr.newTree(
+      newNimNode(nnkPar).add(prefix(this, "*")),
+      name
+    )
+  )
+  copyChildrenTo(args, result)
+
+var val = make_unique_str("test1")
+echo val.c_str()
+val.setChar(0, 'x')
+echo val.c_str()
diff --git a/tests/cpp/tsigbreak.nim b/tests/cpp/tsigbreak.nim
new file mode 100644
index 000000000..14d29adf7
--- /dev/null
+++ b/tests/cpp/tsigbreak.nim
@@ -0,0 +1,29 @@
+discard """
+  targets: "cpp"
+  action: compile
+"""
+
+import tables, lists
+
+type
+  ListTable[K, V] = object
+    table: Table[K, DoublyLinkedNode[V]]
+
+proc initListTable*[K, V](initialSize = 64): ListTable[K, V] =
+  result.table = initTable[K, DoublyLinkedNode[V]]()
+
+proc `[]=`*[K, V](t: var ListTable[K, V], key: K, val: V) =
+  t.table[key].value = val
+
+type
+  SomeObj = object
+  OtherObj = object
+
+proc main() =
+  var someTable = initListTable[int, SomeObj]()
+  var otherTable = initListTable[int, OtherObj]()
+
+  someTable[1] = SomeObj()
+  otherTable[42] = OtherObj()
+
+main()
diff --git a/tests/cpp/tstaticvar_via_typedesc.nim b/tests/cpp/tstaticvar_via_typedesc.nim
new file mode 100644
index 000000000..0d8f424d0
--- /dev/null
+++ b/tests/cpp/tstaticvar_via_typedesc.nim
@@ -0,0 +1,20 @@
+discard """
+  targets: "cpp"
+  output: "42"
+"""
+
+# bug #2324
+
+static: assert defined(cpp), "compile in cpp mode"
+
+{.emit: """
+class Foo {
+public:
+    static int x;
+};
+int Foo::x = 42;
+""".}
+
+type Foo {.importcpp:"Foo".} = object
+proc x* (this: typedesc[Foo]): int {.importcpp:"Foo::x@", nodecl.}
+echo Foo.x
diff --git a/tests/cpp/ttemplatetype.nim b/tests/cpp/ttemplatetype.nim
new file mode 100644
index 000000000..bf243ac43
--- /dev/null
+++ b/tests/cpp/ttemplatetype.nim
@@ -0,0 +1,13 @@
+discard """
+  targets: "cpp"
+"""
+
+type
+  Map[T,U] {.importcpp: "std::map", header: "<map>".} = object
+
+proc cInitMap(T: typedesc, U: typedesc): Map[T,U] {.importcpp: "std::map<'*1,'*2>()", nodecl.}
+
+proc initMap[T, U](): Map[T, U] =
+  result = cInitMap(T, U)
+
+var x: Map[cstring, cint] = initMap[cstring, cint]()
diff --git a/tests/cpp/tterminate_handler.nim b/tests/cpp/tterminate_handler.nim
new file mode 100644
index 000000000..c5ccef53c
--- /dev/null
+++ b/tests/cpp/tterminate_handler.nim
@@ -0,0 +1,10 @@
+discard """
+  targets: "cpp"
+  outputsub: "Error: unhandled unknown cpp exception"
+  exitcode: 1
+  disabled: true
+"""
+type Crap {.importcpp: "int".} = object
+
+var c: Crap
+raise c
diff --git a/tests/cpp/tthread_createthread.nim b/tests/cpp/tthread_createthread.nim
new file mode 100644
index 000000000..b46b876b7
--- /dev/null
+++ b/tests/cpp/tthread_createthread.nim
@@ -0,0 +1,15 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp --hints:on --threads:on $options $file"
+"""
+
+proc threadMain(a: int) {.thread.} =
+    discard
+
+proc main() =
+    var thread: Thread[int]
+
+    thread.createThread(threadMain, 0)
+    thread.joinThreads()
+
+main()
diff --git a/tests/cpp/ttypeinfo1.nim b/tests/cpp/ttypeinfo1.nim
new file mode 100644
index 000000000..97825f452
--- /dev/null
+++ b/tests/cpp/ttypeinfo1.nim
@@ -0,0 +1,22 @@
+discard """
+  targets: "cpp"
+  output: '''100'''
+"""
+
+import typeinfo
+
+#bug #6016
+type
+  Onion {.union.} = object
+    field1: int
+    field2: uint64
+
+  Stroom  = Onion
+
+  PStroom = ptr Stroom
+
+proc pstruct(u: PStroom) =
+  echo u.field2
+
+var x = Onion(field1: 100)
+pstruct(x.addr)
\ No newline at end of file
diff --git a/tests/cpp/ttypeinfo2.nim b/tests/cpp/ttypeinfo2.nim
new file mode 100644
index 000000000..e3661c848
--- /dev/null
+++ b/tests/cpp/ttypeinfo2.nim
@@ -0,0 +1,6 @@
+discard """
+  targets: "cpp"
+"""
+# bug #2841
+import typeinfo
+var tt: Any
diff --git a/tests/cpp/tvector_iterator.nim b/tests/cpp/tvector_iterator.nim
new file mode 100644
index 000000000..c3886c547
--- /dev/null
+++ b/tests/cpp/tvector_iterator.nim
@@ -0,0 +1,19 @@
+discard """
+  targets: "cpp"
+"""
+
+{.emit: """/*TYPESECTION*/
+
+template <class T>
+struct Vector {
+  struct Iterator {};
+};
+
+""".}
+
+type
+  Vector[T] {.importcpp: "Vector".} = object
+  VectorIterator[T] {.importcpp: "Vector<'0>::Iterator".} = object
+
+var x: VectorIterator[void]
+
diff --git a/tests/cpp/tvectorseq.nim b/tests/cpp/tvectorseq.nim
new file mode 100644
index 000000000..4d9ffc3d6
--- /dev/null
+++ b/tests/cpp/tvectorseq.nim
@@ -0,0 +1,38 @@
+discard """
+  targets: "cpp"
+  output: '''(x: 1.0)
+(x: 0.0)'''
+  disabled: "true"
+"""
+
+# This cannot work yet because we omit type information for importcpp'ed types.
+# Fixing this is not hard, but also requires fixing Urhonimo.
+
+# bug #2536
+
+{.emit: """/*TYPESECTION*/
+struct Vector3 {
+public:
+  Vector3(): x(5) {}
+  Vector3(float x_): x(x_) {}
+  float x;
+};
+""".}
+
+type Vector3 {.importcpp: "Vector3", nodecl} = object
+  x: cfloat
+
+proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
+
+# hack around another codegen issue: Generics are attached to where they came
+# from:
+proc `$!`(v:  seq[Vector3]): string = "(x: " & $v[0].x & ")"
+
+proc vec3List*(): seq[Vector3] =
+  let s = @[constructVector3(cfloat(1))]
+  echo($!s)
+  result = s
+  echo($!result)
+
+let f = vec3List()
+#echo($!f)
diff --git a/tests/cpp/tvirtual.nim b/tests/cpp/tvirtual.nim
new file mode 100644
index 000000000..385d052b8
--- /dev/null
+++ b/tests/cpp/tvirtual.nim
@@ -0,0 +1,126 @@
+discard """
+  targets: "cpp"
+  cmd: "nim cpp $file"
+  output: '''
+hello foo
+hello boo
+hello boo
+Const Message: hello world
+NimPrinter: hello world
+NimPrinterConstRef: hello world
+NimPrinterConstRefByRef: hello world
+'''
+"""
+
+{.emit:"""/*TYPESECTION*/
+#include <iostream>
+  class CppPrinter {
+  public:
+    
+    virtual void printConst(char* message) const {
+        std::cout << "Const Message: " << message << std::endl;
+    }
+    virtual void printConstRef(char* message, const int& flag) const {
+        std::cout << "Const Ref Message: " << message << std::endl;
+    }  
+    virtual void printConstRef2(char* message, const int& flag) const {
+        std::cout << "Const Ref2 Message: " << message << std::endl;
+    }  
+    
+};
+""".}
+
+proc newCpp*[T](): ptr T {.importcpp:"new '*0()".}
+type 
+  Foo = object of RootObj
+  FooPtr = ptr Foo
+  Boo = object of Foo
+  BooPtr = ptr Boo
+  CppPrinter {.importcpp, inheritable.} = object
+  NimPrinter {.exportc.} = object of CppPrinter
+
+proc salute(self: FooPtr) {.virtual.} = 
+  echo "hello foo"
+
+proc salute(self: BooPtr) {.virtual.} =
+  echo "hello boo"
+
+let foo = newCpp[Foo]()
+let boo = newCpp[Boo]()
+let booAsFoo = cast[FooPtr](newCpp[Boo]())
+
+#polymorphism works
+foo.salute()
+boo.salute()
+booAsFoo.salute()
+let message = "hello world".cstring
+
+proc printConst(self: CppPrinter, message: cstring) {.importcpp.}
+CppPrinter().printConst(message)
+
+#notice override is optional. 
+#Will make the cpp compiler to fail if not virtual function with the same signature if found in the base type
+proc printConst(self: NimPrinter, message: cstring) {.virtual:"$1('2 #2) const override".} =
+  echo "NimPrinter: " & $message
+
+proc printConstRef(self: NimPrinter, message: cstring, flag: int32) {.virtual:"$1('2 #2, const '3& #3 ) const override".} =
+  echo "NimPrinterConstRef: " & $message
+
+proc printConstRef2(self: NimPrinter, message: cstring, flag {.byref.}: int32) {.virtual:"$1('2 #2, const '3 #3 ) const override".} =
+  echo "NimPrinterConstRefByRef: " & $message
+
+NimPrinter().printConst(message)
+var val : int32 = 10
+NimPrinter().printConstRef(message, val)
+NimPrinter().printConstRef2(message, val)
+
+#bug 22269
+type Doo = object
+proc naiveMember(x: Doo): int {. virtual .} = 2
+discard naiveMember(Doo())
+
+#asmnostackframe works with virtual
+{.emit:"""/*TYPESECTION*/
+  template<typename T>
+  struct Box {
+      T* first;
+     
+      Box(int x){
+        first = new T(x);
+      };
+  };
+  struct Inner {
+    int val;
+    //Coo() = default;
+    Inner(int x){
+      val = x;
+    };
+  };
+  struct Base {
+    virtual Box<Inner> test() = 0;
+  };
+""".}
+
+type 
+  Inner {.importcpp.} = object
+  Base {.importcpp, inheritable.} = object
+  Child  = object of Base
+  Box[T] {.importcpp, inheritable.} = object
+    first: T
+
+proc makeBox[T](x:int32): Box[T] {.importcpp:"Box<'0>(@)", constructor.}
+
+proc test(self: Child): Box[Inner] {.virtual, asmnostackframe.} = 
+  let res {.exportc.} = makeBox[Inner](100)
+  {.emit:"return res;".}
+  
+
+discard Child().test() 
+
+import virtualptr
+
+#We dont want to pull Loo directly by using it as we are testing that the pointer pulls it. 
+proc makeMoo(): Moo {.importcpp:"{ new Loo() }".}
+
+makeMoo().loo.salute()
+
diff --git a/tests/cpp/virtualptr.nim b/tests/cpp/virtualptr.nim
new file mode 100644
index 000000000..f96264081
--- /dev/null
+++ b/tests/cpp/virtualptr.nim
@@ -0,0 +1,9 @@
+type 
+  Loo* {.exportc.} = object
+  LooPtr* = ptr Loo
+  Moo* {.exportc.} = object 
+    loo*: LooPtr
+
+
+proc salute*(foo: LooPtr) {.virtual.} = 
+  discard 
diff --git a/tests/curltest.nim b/tests/curltest.nim
deleted file mode 100755
index 7b040c20a..000000000
--- a/tests/curltest.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-import 
-  libcurl
-
-var hCurl = curl_easy_init()
-if hCurl != nil: 
-  discard curl_easy_setopt(hCurl, CURLOPT_VERBOSE, True)
-  discard curl_easy_setopt(hCurl, CURLOPT_URL, "http://nimrod.ethexor.com")
-  discard curl_easy_perform(hCurl)
-  curl_easy_cleanup(hCurl)
-
diff --git a/tests/defer/t22309.nim b/tests/defer/t22309.nim
new file mode 100644
index 000000000..34ca4843b
--- /dev/null
+++ b/tests/defer/t22309.nim
@@ -0,0 +1,11 @@
+block:
+  defer:
+    let a = 42
+  doAssert not declared(a)
+
+proc lol() =
+  defer:
+    let a = 42
+  doAssert not declared(a)
+
+lol()
diff --git a/tests/destructor/const_smart_ptr.nim b/tests/destructor/const_smart_ptr.nim
new file mode 100644
index 000000000..25dd46500
--- /dev/null
+++ b/tests/destructor/const_smart_ptr.nim
@@ -0,0 +1,75 @@
+type
+  ConstPtr*[T] = object
+    val: ptr T
+
+proc `=destroy`*[T](p: ConstPtr[T]) =
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+
+proc `=copy`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var ConstPtr[T], src: ConstPtr[T]) {.inline.} =
+  if dest.val != nil and dest.val != src.val:
+    `=destroy`(dest)
+  dest.val = src.val
+
+proc newConstPtr*[T](val: sink T): ConstPtr[T] {.inline.} =
+  result.val = cast[type(result.val)](alloc(sizeof(result.val[])))
+  reset(result.val[])
+  result.val[] = val
+
+converter convertConstPtrToObj*[T](p: ConstPtr[T]): lent T =
+  result = p.val[]
+
+
+#-------------------------------------------------------------
+
+type
+  MySeqNonCopyable* = object
+    len: int
+    data: ptr UncheckedArray[float]
+
+proc `=destroy`*(m: MySeqNonCopyable) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+
+proc `=copy`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
+
+proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*(m: MySeqNonCopyable): int {.inline.} = m.len
+
+proc `[]`*(m: MySeqNonCopyable; i: int): float {.inline.} =
+  m.data[i.int]
+
+proc `[]=`*(m: var MySeqNonCopyable; i: int, val: float) {.inline.} =
+  m.data[i.int] = val
+
+proc setTo(s: var MySeqNonCopyable, val: float) =
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeqNonCopyable =
+  result.len = size
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+  result.setTo(initial_value)
+
+#----------------------------------------------------------------------
+
+
+proc test*(x1: int): ConstPtr[MySeqNonCopyable] {.inline.} = # remove inline here to make it work as expected
+  if x1 == 0:
+    let x = newMySeq(1, 0.0)
+    result = newConstPtr(x)
+  else:
+    let y = newMySeq(x1, 0.0)
+    result = newConstPtr(y)
+
+discard test(10)
diff --git a/tests/destructor/helper.nim b/tests/destructor/helper.nim
new file mode 100644
index 000000000..466065747
--- /dev/null
+++ b/tests/destructor/helper.nim
@@ -0,0 +1,3 @@
+type
+  MyTestObject*[T] = object
+    p: ptr T
diff --git a/tests/destructor/nim.cfg b/tests/destructor/nim.cfg
new file mode 100644
index 000000000..7c148b797
--- /dev/null
+++ b/tests/destructor/nim.cfg
@@ -0,0 +1 @@
+--sinkInference:on
diff --git a/tests/destructor/objFile.nim b/tests/destructor/objFile.nim
new file mode 100644
index 000000000..436c090d1
--- /dev/null
+++ b/tests/destructor/objFile.nim
@@ -0,0 +1,8 @@
+type Obj* = object
+  v*: int
+
+proc `=destroy`(this: var Obj) =
+  echo "igotdestroyed"
+  this.v = -1
+
+var test* = Obj(v: 42)
diff --git a/tests/destructor/smart_ptr.nim b/tests/destructor/smart_ptr.nim
new file mode 100644
index 000000000..5079dc9db
--- /dev/null
+++ b/tests/destructor/smart_ptr.nim
@@ -0,0 +1,43 @@
+
+type
+  SharedPtr*[T] = object
+    val: ptr tuple[atomicCounter: int, value: T]
+
+proc `=destroy`*[T](p: var SharedPtr[T]) =
+  mixin `=destroy`
+  if p.val != nil:
+    let c = atomicDec(p.val[].atomicCounter)
+    if c == 0:
+      `=destroy`(p.val.value)
+      freeShared(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) {.inline.} =
+  if dest.val != src.val:
+    if dest.val != nil:
+      `=destroy`(dest)
+    if src.val != nil:
+      discard atomicInc(src.val[].atomicCounter)
+    dest.val = src.val
+
+proc newSharedPtr*[T](val: sink T): SharedPtr[T] =
+  result.val = cast[type(result.val)](allocShared0(sizeof(result.val[])))
+  result.val.atomicCounter = 1
+  result.val.value = val
+
+func get*[T](p: SharedPtr[T]): var T {.inline.} =
+  p.val.value
+
+func isNil*[T](p: SharedPtr[T]): bool {.inline.} =
+  p.val == nil
+
+proc cas*[T](p, old_val: var SharedPtr[T], new_val: SharedPtr[T]): bool {.inline.} =
+  if old_val.val == new_val.val:
+    result = true
+  else:
+    result = cas(p.val.addr, old_val.val, new_val.val)
+    if result:
+      `=destroy`(old_val)
+      if new_val.val != nil:
+        discard atomicInc(new_val.val[].atomicCounter)
+
diff --git a/tests/destructor/t12037.nim b/tests/destructor/t12037.nim
new file mode 100644
index 000000000..30266690f
--- /dev/null
+++ b/tests/destructor/t12037.nim
@@ -0,0 +1,34 @@
+discard """
+  cmd: '''nim c --gc:arc $file'''
+  output: '''
+showing original type, length, and contents seq[int] 1 @[42]
+copy length and contents 1 @[42]
+'''
+"""
+
+proc test() =
+  var sq1 = @[42]
+  echo "showing original type, length, and contents ", sq1.typeof, " ", sq1.len, " ", sq1
+  doAssert cast[int](sq1[0].addr) != 0
+  var sq2 = sq1 # copy of original
+  echo "copy length and contents ", sq2.len, " ", sq2
+  doAssert cast[int](sq2[0].addr) != 0
+  doAssert cast[int](sq1[0].addr) != 0
+
+test()
+
+
+#############################################
+### bug 12820
+import tables
+var t = initTable[string, seq[ptr int]]()
+discard t.hasKeyOrPut("f1", @[])
+
+
+#############################################
+### bug #12989
+proc bug(start: (seq[int], int)) =
+  let (s, i) = start
+
+let input = @[0]
+bug((input, 0))
diff --git a/tests/destructor/t16607.nim b/tests/destructor/t16607.nim
new file mode 100644
index 000000000..f98a6d517
--- /dev/null
+++ b/tests/destructor/t16607.nim
@@ -0,0 +1,23 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+# bug #16607
+
+type
+  O {.requiresInit.} = object
+    initialized: bool
+
+proc `=destroy`(o: var O) =
+  doAssert o.initialized, "O was destroyed before initialization!"
+
+proc initO(): O =
+  O(initialized: true)
+
+proc pair(): tuple[a, b: O] =
+  result = (a: initO(), b: initO())
+
+proc main() =
+  discard pair()
+
+main()
diff --git a/tests/destructor/t17198.nim b/tests/destructor/t17198.nim
new file mode 100644
index 000000000..098db8245
--- /dev/null
+++ b/tests/destructor/t17198.nim
@@ -0,0 +1,32 @@
+discard """
+  cmd: '''nim c --gc:arc $file'''
+  output: '''
+other
+'''
+"""
+
+import std/macros
+
+macro bigCaseStmt(arg: untyped): untyped =
+  result = nnkCaseStmt.newTree(arg)
+
+  # try to change 2000 to a bigger value if it doesn't crash
+  for x in 0 ..< 2000:
+    result.add nnkOfBranch.newTree(newStrLitNode($x), newStrLitNode($x))
+
+  result.add nnkElse.newTree(newStrLitNode("other"))
+
+macro bigIfElseExpr(): untyped =
+  result = nnkIfExpr.newTree()
+
+  for x in 0 ..< 1000:
+    result.add nnkElifExpr.newTree(newLit(false), newStrLitNode($x))
+
+  result.add nnkElseExpr.newTree(newStrLitNode("other"))
+
+proc test(arg: string): string =
+  echo bigIfElseExpr()
+
+  result = bigCaseStmt(arg)
+
+discard test("test")
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/t5342.nim b/tests/destructor/t5342.nim
new file mode 100644
index 000000000..0acd5ef9d
--- /dev/null
+++ b/tests/destructor/t5342.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--mm:refc; --mm:arc"
+  targets: "c js"
+  output: '''
+1
+2
+here
+2
+1
+'''
+"""
+
+
+type
+  A = object
+    id: int
+  B = object
+    a: A
+proc `=destroy`(a: var A) = echo a.id
+var x = A(id: 1)
+var y = B(a: A(id: 2))
+`=destroy`(x)
+`=destroy`(y)
+echo "here"
\ No newline at end of file
diff --git a/tests/destructor/t7346.nim b/tests/destructor/t7346.nim
new file mode 100644
index 000000000..3834d39ff
--- /dev/null
+++ b/tests/destructor/t7346.nim
@@ -0,0 +1,14 @@
+discard """
+joinable: false
+"""
+
+# This bug could only be reproduced with --newruntime
+
+type
+  Obj = object
+    a: int
+
+proc `=`(a: var Obj, b: Obj) = discard
+
+let a: seq[Obj] = @[] # bug #7346
+let b = newSeq[Obj]() # bug #7345
diff --git a/tests/destructor/t9440.nim b/tests/destructor/t9440.nim
new file mode 100644
index 000000000..153bb303d
--- /dev/null
+++ b/tests/destructor/t9440.nim
@@ -0,0 +1,52 @@
+discard """
+  matrix: "--gc:refc; --gc:orc; --gc:arc"
+  output: '''
+()
+Destroyed
+()
+Destroyed
+()
+Destroyed
+end
+-------------------------
+()
+Destroyed
+end
+'''
+
+"""
+
+# bug #9440
+block:
+  type
+    X = object
+
+  proc `=destroy`(x: var X) =
+    echo "Destroyed"
+
+  proc main() =
+    for x in 0 .. 2:
+      var obj = X()
+      echo obj
+    # The destructor call is invoked after "end" is printed
+    echo "end"
+
+  main()
+
+echo "-------------------------"
+
+block:
+  type
+    X = object
+
+  proc `=destroy`(x: var X) =
+    echo "Destroyed"
+
+  proc main() =
+    block:
+      var obj = X()
+      echo obj
+      # The destructor is not called when obj goes out of scope
+    echo "end"
+
+  main()
diff --git a/tests/destructor/tarc.nim b/tests/destructor/tarc.nim
new file mode 100644
index 000000000..54d75a410
--- /dev/null
+++ b/tests/destructor/tarc.nim
@@ -0,0 +1,184 @@
+discard """
+  output: '''
+@[1, 2, 3]
+Success
+@["a", "b", "c"]
+Hello
+1
+2
+0
+List
+@["4", "5", "6", "", "", "a", ""]
+@["", "", "a", ""]
+'''
+  cmd: '''nim c --gc:arc $file'''
+"""
+
+import os
+import math
+import lists
+import strutils
+
+proc mkleak() =
+  # allocate 1 MB via linked lists
+  let numberOfLists = 100
+  for i in countUp(1, numberOfLists):
+    var leakList = initDoublyLinkedList[string]()
+    let numberOfLeaks = 5000
+    for j in countUp(1, numberOfLeaks):
+      leakList.append(newString(200))
+
+proc mkManyLeaks() =
+  for i in 0..0:
+    mkleak()
+  echo "Success"
+
+iterator foobar(c: string): seq[string] {.closure.} =
+  yield @["a", "b", c]
+
+proc tsimpleClosureIterator =
+  var myc = "c"
+  for it in foobar(myc):
+    echo it
+
+type
+  LazyList = ref object
+    c: proc() {.closure.}
+
+proc tlazyList =
+  let dep = @[1, 2, 3]
+  var x = LazyList(c: proc () = echo(dep))
+  x.c()
+
+type
+  Foo = ref object
+
+proc tleakingNewStmt =
+  var x: Foo
+  for i in 0..10:
+    new(x)
+
+iterator infinite(): int {.closure.} =
+  var i = 0
+  while true:
+    yield i
+    inc i
+
+iterator take(it: iterator (): int, numToTake: int): int {.closure.} =
+  var i = 0
+  for x in it():
+    if i >= numToTake:
+      break
+    yield x
+    inc i
+
+proc take3 =
+  for x in infinite.take(3):
+    discard
+
+
+type
+  A = ref object of RootObj
+    x: int
+
+  B = ref object of A
+    more: string
+
+proc inheritanceBug(param: string) =
+  var s: (A, A)
+  s[0] = B(more: "a" & param)
+  s[1] = B(more: "a" & param)
+
+
+type
+  PAsyncHttpServer = ref object
+    value: string
+
+proc serve(server: PAsyncHttpServer) = discard
+
+proc leakObjConstr =
+  serve(PAsyncHttpServer(value: "asdas"))
+
+let startMem = getOccupiedMem()
+take3()
+tlazyList()
+inheritanceBug("whatever")
+mkManyLeaks()
+tsimpleClosureIterator()
+tleakingNewStmt()
+leakObjConstr()
+
+# bug #12964
+
+type
+  Token* = ref object of RootObj
+  Li* = ref object of Token
+
+proc bug12964*() =
+  var token = Li()
+  var tokens = @[Token()]
+  tokens.add token
+
+bug12964()
+
+# bug #13119
+import streams
+
+proc bug13119 =
+  var m = newStringStream("Hello world")
+  let buffer = m.readStr(5)
+  echo buffer
+  m.close
+
+bug13119()
+
+# bug #13105
+
+type
+  Result[T, E] = object
+    a: T
+    b: E
+  D = ref object
+    x: int
+  R = Result[D, int]
+
+proc bug13105 =
+  for n in [R(b: 1), R(b: 2)]:
+    echo n.b
+
+bug13105()
+
+echo getOccupiedMem() - startMem
+
+
+#------------------------------------------------------------------------------
+# issue #14294
+
+import tables
+
+type
+  TagKind = enum
+    List = 0, Compound
+
+  Tag = object
+    case kind: TagKind
+    of List:
+      values: seq[Tag]
+    of Compound:
+      compound: Table[string, Tag]
+
+var a = Tag(kind: List)
+var b = a
+echo a.kind
+var c = a
+
+proc testAdd(i: int; yyy: openArray[string]) =
+  var x: seq[string]
+  x.add [$i, $(i+1), $(i+2)]
+  x.add yyy
+  echo x
+
+var y = newSeq[string](4)
+y[2] = "a"
+testAdd(4, y)
+echo y
diff --git a/tests/destructor/tarc2.nim b/tests/destructor/tarc2.nim
new file mode 100644
index 000000000..a7d7b4945
--- /dev/null
+++ b/tests/destructor/tarc2.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''leak: false'''
+  cmd: '''nim c --gc:orc $file'''
+"""
+
+type
+  T = ref object
+    s: seq[T]
+    data: string
+
+proc create(): T = T(s: @[], data: "abc")
+
+proc addX(x: T; data: string) =
+  x.data = data
+
+{.push sinkInference: off.}
+
+proc addX(x: T; child: T) =
+  x.s.add child
+
+{.pop.}
+
+proc main(rootName: string) =
+  var root = create()
+  root.data = rootName
+  root.addX root
+
+let mem = getOccupiedMem()
+main("yeah")
+GC_fullCollect()
+echo "leak: ", getOccupiedMem() - mem > 0
diff --git a/tests/destructor/tarc3.nim b/tests/destructor/tarc3.nim
new file mode 100644
index 000000000..55d0ea42d
--- /dev/null
+++ b/tests/destructor/tarc3.nim
@@ -0,0 +1,101 @@
+
+discard """
+  cmd: '''nim c --gc:arc $file'''
+"""
+
+when defined(cpp):
+  {.passC: "-std=gnu++2a".}
+
+type
+  TokenKind* = enum
+    tkColon
+    tkComma
+    tkString
+    tkNumber
+    tkInt64
+    tkIdent
+
+  Token* = object
+    case kind*: TokenKind
+    of tkString: strVal*: string
+    of tkNumber: numVal*: float
+    of tkInt64: int64Val*: int64
+    of tkIdent: ident*: string
+    else: discard
+    pos*: Natural
+
+
+  Token2* = object
+    case kind*: TokenKind
+    of tkString: strVal*: string
+    of tkNumber: numVal*: float
+    of tkInt64, tkColon..tkComma:
+      str1*: array[2, string]
+      float: float
+    else: discard
+    pos*: Natural
+
+  Token3* = object
+    case kind*: TokenKind
+    of tkNumber: numVal*: float
+    of tkInt64, tkComma..tkString: ff: seq[float]
+    else: str1*: string
+  
+  Token4* = object
+    case kind*: TokenKind
+    of tkNumber: numVal*: float
+    of tkInt64, tkComma..tkString: ff: seq[float]
+    else: str1*: string
+    case kind2*: TokenKind
+    of tkNumber: 
+      numVal2*: float
+      intSeqVal3*: seq[int]
+    of tkInt64, tkComma..tkString: 
+      case kind3*: TokenKind
+      of tkNumber: numVal3*: float
+      of tkInt64, tkComma..tkString: 
+        ff3: seq[float]
+        ff5: string
+      else: 
+        str3*: string
+        mysrq: seq[int]
+    else: 
+      case kind4*: TokenKind
+      of tkNumber: numVal4*: float
+      of tkInt64, tkComma..tkString: ff4: seq[float]
+      else: str4*: string
+  
+  BaseLexer* = object of RootObj
+    input*: string
+    pos*: Natural
+
+  Json5Lexer* = object of BaseLexer
+
+  JsonLexer* = object of BaseLexer
+    allowComments*: bool
+    allowSpecialFloats*: bool
+
+  Lexer* = Json5Lexer | JsonLexer
+
+  Parser[T: Lexer] = object
+    l: T
+    tok: Token
+    tok2: Token2
+    tok3: Token3
+    tok4: Token4
+    allowTrailingComma: bool
+    allowIdentifierObjectKey: bool
+
+proc initJson5Lexer*(input: string): Json5Lexer =
+  result.input = input
+
+proc parseJson5*(input: string)  =
+  var p = Parser[Json5Lexer](
+    l: initJson5Lexer(input),
+    allowTrailingComma: true,
+    allowIdentifierObjectKey: true
+  )
+
+
+let x = "string"
+parseJson5(x)
\ No newline at end of file
diff --git a/tests/destructor/tarctypesections.nim b/tests/destructor/tarctypesections.nim
new file mode 100644
index 000000000..da81f1884
--- /dev/null
+++ b/tests/destructor/tarctypesections.nim
@@ -0,0 +1,70 @@
+discard """
+  output: "MEM 0"
+  cmd: "nim c --gc:arc $file"
+"""
+
+type
+  RefNode = ref object
+    le, ri: RefNode
+    name: char
+
+proc edge0(a, b: RefNode) =
+  if a.le == nil: a.le = b
+  else: a.ri = b
+
+proc createNode0(name: char): RefNode =
+  new result
+  result.name = name
+
+proc main0 =
+  let r = createNode0('R')
+  let c = createNode0('C')
+  c.edge0 r
+
+
+type
+  NodeDesc = object
+    le, ri: Node
+    name: char
+  Node = ref NodeDesc
+
+proc edge(a, b: Node) =
+  if a.le == nil: a.le = b
+  else: a.ri = b
+
+proc createNode(name: char): Node =
+  new result
+  result.name = name
+
+proc main =
+  let r = createNode('R')
+  let c = createNode('C')
+  c.edge r
+
+
+type
+  NodeB = ref NodeBo
+  NodeBo = object
+    le, ri: NodeB
+    name: char
+
+proc edge(a, b: NodeB) =
+  if a.le == nil: a.le = b
+  else: a.ri = b
+
+proc createNodeB(name: char): NodeB =
+  new result
+  result.name = name
+
+
+proc mainB =
+  let r = createNodeB('R')
+  let c = createNodeB('C')
+  c.edge r
+
+
+let memB = getOccupiedMem()
+main0()
+main()
+mainB()
+echo "MEM ", getOccupiedMem() - memB
diff --git a/tests/destructor/tarray_indexing.nim b/tests/destructor/tarray_indexing.nim
new file mode 100644
index 000000000..a9dfdf4ed
--- /dev/null
+++ b/tests/destructor/tarray_indexing.nim
@@ -0,0 +1,75 @@
+discard """
+  output: '''allocating 1048576 65536
+filling page from 1048576 len 65536'''
+  cmd: '''nim c --gc:arc $file'''
+"""
+
+# bug #12669
+
+type
+    MemState* = enum
+        memPrivate
+
+    MemPermisison* = enum
+        memperm_Read
+
+    MemInfo* = ref object
+        base*, size*: uint32
+        state*: MemState
+        perm*: set[MemPermisison]
+
+    MemBlock = ref object
+        info: MemInfo
+        data: seq[byte]
+
+    UserProcessMemory* = ref object
+        pageAccess: array[0x40000, ptr UncheckedArray[byte]]
+        pages: array[0x40000, MemInfo]
+        blocks: seq[owned MemBlock]
+
+proc allocMemory*(mem: UserProcessMemory, base, size: uint32) =
+    let
+        roundedBase = base and not(0xFFF'u32)
+        roundedSize = (size + 0xFFF) and not(0xFFF'u32)
+
+    echo "allocating ", base, " ", size
+    for i in (roundedBase shr 12)..<((roundedBase + roundedSize) shr 12):
+        #echo "span ", i
+        doAssert mem.pages[i] == nil
+        # TODO: beserer fehler
+
+    let memBlock = MemBlock(
+        info: MemInfo(
+            base: roundedBase,
+            size: roundedSize,
+            state: memPrivate,
+            perm: {memperm_Read}
+        ),
+        data: newSeq[byte](roundedSize))
+    for i in 0..<(roundedSize shr 12):
+        mem.pages[i + (roundedBase shr 12)] = memBlock.info
+        #echo cast[uint64](addr mem.pageAccess[i + (roundedBase shr 12)])
+        mem.pageAccess[i + (roundedBase shr 12)] = cast[ptr UncheckedArray[byte]](addr memBlock.data[i * 0x1000])
+    mem.blocks.add memBlock
+
+    #for i in (roundedBase shr 12)..<((roundedBase + roundedSize) shr 12):
+    #    assert mem.pageAccess[i] != nil
+
+proc fillPages*(mem: UserProcessMemory, start: uint32, data: seq[byte]) =
+    echo "filling page from ", start, " len ", data.len
+    assert (start and not(0xFFF'u32)) == start
+    assert (uint32(data.len) and not(0xFFF'u32)) == uint32(data.len)
+    for i in (start shr 12)..<((start + uint32(data.len)) shr 12):
+        #echo cast[uint64](addr mem.pageAccess[i])
+        let page = mem.pageAccess[i]
+        assert page != nil
+        #copyMem(page, addr data[i * 0x1000 - start], 0x1000)
+
+const base = 0x00100000
+
+proc a(): owned UserProcessMemory =
+    result = UserProcessMemory()
+    result.allocMemory(base, 0x1000 * 16)
+    result.fillPages(base, newSeq[byte](0x1000 * 16))
+
+discard a()
diff --git a/tests/destructor/tasync_prototype.nim b/tests/destructor/tasync_prototype.nim
new file mode 100644
index 000000000..81fd824e9
--- /dev/null
+++ b/tests/destructor/tasync_prototype.nim
@@ -0,0 +1,59 @@
+discard """
+  output: '''asdas
+processClient end
+false
+MEMORY 0
+'''
+  cmd: '''nim c --gc:arc $file'''
+"""
+
+type
+  PAsyncHttpServer = ref object
+    value: string
+  PFutureBase {.acyclic.} = ref object
+    callback: proc () {.closure.}
+    value: string
+    failed: bool
+
+proc accept(server: PAsyncHttpServer): PFutureBase =
+  new(result)
+  result.callback = proc () =
+    discard
+  server.value = "hahaha"
+
+proc processClient(): PFutureBase =
+  new(result)
+
+proc serve(server: PAsyncHttpServer): PFutureBase =
+  iterator serveIter(): PFutureBase {.closure.} =
+    echo server.value
+    while true:
+      var acceptAddrFut = server.accept()
+      yield acceptAddrFut
+      var fut = acceptAddrFut.value
+
+      # with the new scope based destruction, this cannot
+      # possibly work:
+      var f {.cursor.} = processClient()
+      # It also seems to be the wrong way how to avoid the
+      # cycle. The cycle is caused by capturing the 'env'
+      # part from 'env.f'.
+      when true:
+        f.callback =
+          proc () =
+            echo("processClient end")
+            echo(f.failed)
+      yield f
+  var x = serveIter
+  for i in 0 .. 1:
+    result = x()
+    if result.callback != nil:
+      result.callback()
+
+let mem = getOccupiedMem()
+
+proc main =
+  discard serve(PAsyncHttpServer(value: "asdas"))
+
+main()
+echo "MEMORY ", getOccupiedMem() - mem
diff --git a/tests/destructor/tasync_prototype_cyclic.nim b/tests/destructor/tasync_prototype_cyclic.nim
new file mode 100644
index 000000000..8ba73a8fc
--- /dev/null
+++ b/tests/destructor/tasync_prototype_cyclic.nim
@@ -0,0 +1,55 @@
+discard """
+  output: '''asdas
+processClient end
+false
+MEMORY 0
+'''
+  cmd: '''nim c --gc:orc $file'''
+"""
+
+type
+  PAsyncHttpServer = ref object
+    value: string
+  PFutureBase = ref object
+    callback: proc () {.closure.}
+    value: string
+    failed: bool
+
+proc accept(server: PAsyncHttpServer): PFutureBase =
+  new(result)
+  result.callback = proc () =
+    discard
+  server.value = "hahaha"
+
+proc processClient(): PFutureBase =
+  new(result)
+
+proc serve(server: PAsyncHttpServer): PFutureBase =
+  iterator serveIter(): PFutureBase {.closure.} =
+    echo server.value
+    while true:
+      var acceptAddrFut = server.accept()
+      yield acceptAddrFut
+      var fut = acceptAddrFut.value
+
+      var f = processClient()
+      when true:
+        f.callback =
+          proc () =
+            echo("processClient end")
+            echo(f.failed)
+      yield f
+  var x = serveIter
+  for i in 0 .. 1:
+    result = x()
+    if result.callback != nil:
+      result.callback()
+
+let mem = getOccupiedMem()
+
+proc main =
+  discard serve(PAsyncHttpServer(value: "asdas"))
+
+main()
+GC_fullCollect()
+echo "MEMORY ", getOccupiedMem() - mem
diff --git a/tests/destructor/tatomicptrs.nim b/tests/destructor/tatomicptrs.nim
new file mode 100644
index 000000000..82870ac82
--- /dev/null
+++ b/tests/destructor/tatomicptrs.nim
@@ -0,0 +1,176 @@
+discard """
+  output: '''allocating
+allocating
+allocating
+55
+60
+99
+deallocating
+deallocating
+deallocating
+allocating
+deallocating
+'''
+joinable: false
+"""
+
+type
+  SharedPtr*[T] = object
+    x: ptr T
+
+#proc isNil[T](s: SharedPtr[T]): bool {.inline.} = s.x.isNil
+
+template incRef(x) =
+  atomicInc(x.refcount)
+
+template decRef(x): untyped = atomicDec(x.refcount)
+
+proc makeShared*[T](x: sink T): SharedPtr[T] =
+  # XXX could benefit from a macro that generates it.
+  result = cast[SharedPtr[T]](allocShared0(sizeof(x)))
+  result.x[] = x
+  echo "allocating"
+
+proc `=destroy`*[T](dest: var SharedPtr[T]) =
+  var s = dest.x
+  if s != nil and decRef(s) == 0:
+    `=destroy`(s[])
+    deallocShared(s)
+    echo "deallocating"
+    dest.x = nil
+
+proc `=copy`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
+  var s = src.x
+  if s != nil: incRef(s)
+  #atomicSwap(dest, s)
+  # XXX use an atomic store here:
+  swap(dest.x, s)
+  if s != nil and decRef(s) == 0:
+    `=destroy`(s[])
+    deallocShared(s)
+    echo "deallocating"
+
+proc `=dup`*[T](src: SharedPtr[T]): SharedPtr[T] =
+  `=copy`(result, src)
+
+proc `=sink`*[T](dest: var SharedPtr[T]; src: SharedPtr[T]) =
+  ## XXX make this an atomic store:
+  if dest.x != src.x:
+    let s = dest.x
+    if s != nil:
+      `=destroy`(s[])
+      deallocShared(s)
+      echo "deallocating"
+    dest.x = src.x
+
+proc get*[T](s: SharedPtr[T]): lent T =
+  s.x[]
+
+template `.`*[T](s: SharedPtr[T]; field: untyped): untyped =
+  s.x.field
+
+template `.=`*[T](s: SharedPtr[T]; field, value: untyped) =
+  s.x.field = value
+
+from macros import unpackVarargs
+
+template `.()`*[T](s: SharedPtr[T]; field: untyped, args: varargs[untyped]): untyped =
+  # xxx this isn't used, the test should be improved
+  unpackVarargs(s.x.field, args)
+
+
+type
+  Tree = SharedPtr[TreeObj]
+  TreeObj = object
+    refcount: int
+    le, ri: Tree
+    data: int
+
+proc takesTree(a: Tree) =
+  if not a.isNil:
+    takesTree(a.le)
+    echo a.data
+    takesTree(a.ri)
+
+proc createTree(data: int): Tree =
+  result = makeShared(TreeObj(refcount: 1, data: data))
+
+proc createTree(data: int; le, ri: Tree): Tree =
+  result = makeShared(TreeObj(refcount: 1, le: le, ri: ri, data: data))
+
+
+proc main =
+  let le = createTree(55)
+  let ri = createTree(99)
+  let t = createTree(60, le, ri)
+  takesTree(t)
+
+main()
+
+
+
+#-------------------------------------------------------
+#bug #9781
+
+type
+  MySeq* [T] = object
+    refcount: int
+    len: int
+    data: ptr UncheckedArray[T]
+
+proc `=destroy`*[T](m: var MySeq[T]) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=copy`*[T](m: var MySeq[T], m2: MySeq[T]) =
+  if m.data == m2.data: return
+  if m.data != nil:
+    `=destroy`(m)
+
+  m.len = m2.len
+  let bytes = m.len.int * sizeof(float)
+  if bytes > 0:
+    m.data = cast[ptr UncheckedArray[T]](allocShared(bytes))
+    copyMem(m.data, m2.data, bytes)
+
+proc `=dup`*[T](m: MySeq[T]): MySeq[T] =
+  `=copy`[T](result, m)
+
+proc `=sink`*[T](m: var MySeq[T], m2: MySeq[T]) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+    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))
+
+
+let x = makeShared(newMySeq(10, 1.0))
+doAssert: x.get().len == 10
+
+
+
+#-------------------------------------------------------
+#bug #12882
+
+type
+  ValueObject = object
+    v: MySeq[int]
+    name: string
+
+  TopObject = object
+    internal: seq[ValueObject]
+
+var zz = new(TopObject)
+
+
+
diff --git a/tests/destructor/tbintree2.nim b/tests/destructor/tbintree2.nim
new file mode 100644
index 000000000..d56c2850b
--- /dev/null
+++ b/tests/destructor/tbintree2.nim
@@ -0,0 +1,101 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  output: '''0
+(allocCount: 5, deallocCount: 5)'''
+"""
+
+import system / ansi_c
+
+import random
+
+type Node = ref object
+  x, y: int32
+  left, right: owned Node
+
+proc newNode(x: int32): owned Node =
+  result = Node(x: x, y: rand(high int32).int32)
+
+proc merge(lower, greater: owned Node): owned Node =
+  if lower.isNil:
+    result = greater
+  elif greater.isNil:
+    result = lower
+  elif lower.y < greater.y:
+    lower.right = merge(move lower.right, greater)
+    result = lower
+  else:
+    greater.left = merge(lower, move greater.left)
+    result = greater
+
+proc splitBinary(orig: owned Node, value: int32): (owned Node, owned Node) =
+  if orig.isNil:
+    result = (nil, nil)
+  elif orig.x < value:
+    let splitPair = splitBinary(move orig.right, value)
+    orig.right = splitPair[0]
+    result = (orig, splitPair[1])
+  else:
+    let splitPair = splitBinary(move orig.left, value)
+    orig.left = splitPair[1]
+    result = (splitPair[0], orig)
+
+proc merge3(lower, equal, greater: owned Node): owned Node =
+  merge(merge(lower, equal), greater)
+
+proc split(orig: owned Node, value: int32): tuple[lower, equal, greater: owned Node] =
+  let
+    (lower, equalGreater) = splitBinary(orig, value)
+    (equal, greater) = splitBinary(equalGreater, value + 1)
+  result = (lower, equal, greater)
+
+type Tree = object
+  root: owned Node
+
+proc `=destroy`(t: var Tree) {.nodestroy.} =
+  var s: seq[owned Node] = @[t.root]
+  while s.len > 0:
+    let x = s.pop
+    if x.left != nil: s.add(x.left)
+    if x.right != nil: s.add(x.right)
+    `=dispose`(x)
+  `=destroy`(s)
+
+proc hasValue(self: var Tree, x: int32): bool =
+  let splited = split(move self.root, x)
+  result = not splited.equal.isNil
+  self.root = merge3(splited.lower, splited.equal, splited.greater)
+
+proc insert(self: var Tree, x: int32) =
+  var splited = split(move self.root, x)
+  if splited.equal.isNil:
+    splited.equal = newNode(x)
+  self.root = merge3(splited.lower, splited.equal, splited.greater)
+
+proc erase(self: var Tree, x: int32) =
+  let splited = split(move self.root, x)
+  self.root = merge(splited.lower, splited.greater)
+
+proc main() =
+  var
+    tree = Tree()
+    cur = 5'i32
+    res = 0
+
+  for i in 1 ..< 10:
+    let a = i mod 3
+    cur = (cur * 57 + 43) mod 10007
+    case a:
+    of 0:
+      tree.insert(cur)
+    of 1:
+      tree.erase(cur)
+    of 2:
+      if tree.hasValue(cur):
+        res += 1
+    else:
+      discard
+  echo res
+
+dumpAllocStats:
+  main()
+
diff --git a/tests/destructor/tcaseobj_transitions.nim b/tests/destructor/tcaseobj_transitions.nim
new file mode 100644
index 000000000..61464101f
--- /dev/null
+++ b/tests/destructor/tcaseobj_transitions.nim
@@ -0,0 +1,49 @@
+discard """
+  cmd: '''nim c --gc:arc $file'''
+  output: '''no crash'''
+"""
+
+# bug #11205
+
+type
+  MyEnum = enum
+    A, B, C
+  MyCaseObject = object
+    case kind: MyEnum
+    of A: iseq: seq[int]
+    of B: fseq: seq[float]
+    of C: str: string
+
+
+  MyCaseObjectB = object # carefully constructed to use the same enum,
+                         # but a different object type!
+    case kind: MyEnum
+    of A, C: x: int
+    of B: fseq: seq[float]
+
+
+var x = MyCaseObject(kind: A)
+x.iseq.add 1
+#x.kind = B
+#x.fseq.add -3.0
+
+var y = MyCaseObjectB(kind: A)
+y.x = 1
+y.kind = C
+echo "no crash"
+
+
+#################
+## bug #12821
+
+type
+  RefBaseObject* = ref object of RootObj
+    case kind: bool
+      of true: a: int
+      of false: b: float
+
+  MyRefObject = ref object of RefBaseObject
+    x: float
+
+let z = new(MyRefObject)
+z.kind = false
diff --git a/tests/destructor/tcast.nim b/tests/destructor/tcast.nim
new file mode 100644
index 000000000..35a7d874b
--- /dev/null
+++ b/tests/destructor/tcast.nim
@@ -0,0 +1,14 @@
+# Make sure we don't walk cast[T] type section while injecting sinks/destructors
+block:
+  type
+    XY[T] = object
+      discard
+
+  proc `=`[T](x: var XY[T]; v: XY[T]) {.error.}
+  proc `=sink`[T](x: var XY[T]; v: XY[T]) {.error.}
+
+  proc main[T]() =
+    var m = cast[ptr XY[T]](alloc0(sizeof(XY[T])))
+    doAssert(m != nil)
+
+  main[int]()
diff --git a/tests/destructor/tcomplexobjconstr.nim b/tests/destructor/tcomplexobjconstr.nim
new file mode 100644
index 000000000..aea0ad1fe
--- /dev/null
+++ b/tests/destructor/tcomplexobjconstr.nim
@@ -0,0 +1,56 @@
+discard """
+  output: '''true
+OK'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #12826
+
+type
+  MyObject1* = object of RootObj
+    z*: string
+
+  MyObject2* = object of RootObj
+    x*: float
+    name*: string
+    subobj: MyObject1
+    case flag*: bool
+    of false:
+      more: array[3, MyObject1]
+    of true: y*: float
+
+var x = new(MyObject2)
+doAssert x of MyObject2
+doAssert x.subobj of MyObject1
+doAssert x.more[2] of MyObject1
+doAssert x.more[2] of RootObj
+
+var y: MyObject2
+doAssert y of MyObject2
+doAssert y.subobj of MyObject1
+doAssert y.more[2] of MyObject1
+doAssert y.more[2] of RootObj
+
+echo "true"
+
+# bug #12978
+type
+  Vector2* = object of RootObj
+    x*, y*: float
+
+type
+  Vertex* = ref object
+    point*: Vector2
+
+proc newVertex*(p: Vector2): Vertex =
+  return Vertex(point: p)
+
+proc createVertex*(p: Vector2): Vertex =
+  result = newVertex(p)
+
+proc p =
+  var x = Vector2(x: 1, y: 2)
+  let other = createVertex(x)
+  echo "OK"
+
+p()
diff --git a/tests/destructor/tconst_smart_ptr.nim b/tests/destructor/tconst_smart_ptr.nim
new file mode 100644
index 000000000..39fe12612
--- /dev/null
+++ b/tests/destructor/tconst_smart_ptr.nim
@@ -0,0 +1,7 @@
+discard """
+  action: "compile"
+"""
+
+import const_smart_ptr
+
+discard test(0)
diff --git a/tests/destructor/tconsume_twice.nim b/tests/destructor/tconsume_twice.nim
new file mode 100644
index 000000000..b0a039e9b
--- /dev/null
+++ b/tests/destructor/tconsume_twice.nim
@@ -0,0 +1,15 @@
+discard """
+  cmd: "nim c --newruntime $file"
+  errormsg: "'=copy' is not available for type <owned Foo>; requires a copy because it's not the last read of 'a'; another read is done here: tconsume_twice.nim(13, 10); routine: consumeTwice"
+  line: 11
+"""
+type
+  Foo = ref object
+
+proc use(a: owned Foo): bool = discard
+proc consumeTwice(a: owned Foo): owned Foo =
+  if use(a):
+    return
+  return a
+
+assert consumeTwice(Foo()) != nil
diff --git a/tests/destructor/tcustomseqs.nim b/tests/destructor/tcustomseqs.nim
new file mode 100644
index 000000000..17a19f871
--- /dev/null
+++ b/tests/destructor/tcustomseqs.nim
@@ -0,0 +1,144 @@
+discard """
+  output: '''1
+2
+3
+4
+5
+6
+89
+90
+90
+0 0 1
+0 1 2
+0 2 3
+1 0 4
+1 1 5
+1 2 6
+1 3 7
+after 6 6'''
+joinable: false
+"""
+
+import typetraits
+
+type
+  myseq*[T] = object
+    len, cap: int
+    data: ptr UncheckedArray[T]
+
+# XXX make code memory safe for overflows in '*'
+var
+  allocCount, deallocCount: int
+
+proc `=destroy`*[T](x: var myseq[T]) =
+  if x.data != nil:
+    when not supportsCopyMem(T):
+      for i in 0..<x.len: `=destroy`(x[i])
+    dealloc(x.data)
+    inc deallocCount
+    x.data = nil
+    x.len = 0
+    x.cap = 0
+
+proc `=`*[T](a: var myseq[T]; b: myseq[T]) =
+  if a.data == b.data: return
+  if a.data != nil:
+    `=destroy`(a)
+    #dealloc(a.data)
+    #inc deallocCount
+    #a.data = nil
+  a.len = b.len
+  a.cap = b.cap
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(a.cap * sizeof(T)))
+    inc allocCount
+    when supportsCopyMem(T):
+      copyMem(a.data, b.data, a.cap * sizeof(T))
+    else:
+      for i in 0..<a.len:
+        a.data[i] = b.data[i]
+
+proc `=sink`*[T](a: var myseq[T]; b: myseq[T]) =
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    inc deallocCount
+  a.len = b.len
+  a.cap = b.cap
+  a.data = b.data
+
+proc resize[T](s: var myseq[T]) =
+  if s.cap == 0: s.cap = 8
+  else: s.cap = (s.cap * 3) shr 1
+  if s.data == nil: inc allocCount
+  s.data = cast[type(s.data)](realloc(s.data, s.cap * sizeof(T)))
+
+proc reserveSlot[T](x: var myseq[T]): ptr T =
+  if x.len >= x.cap: resize(x)
+  result = addr(x.data[x.len])
+  inc x.len
+
+template add*[T](x: var myseq[T]; y: T) =
+  reserveSlot(x)[] = y
+
+proc shrink*[T](x: var myseq[T]; newLen: int) =
+  assert newLen <= x.len
+  assert newLen >= 0
+  when not supportsCopyMem(T):
+    for i in countdown(x.len - 1, newLen - 1):
+      `=destroy`(x.data[i])
+  x.len = newLen
+
+proc grow*[T](x: var myseq[T]; newLen: int; value: T) =
+  if newLen <= x.len: return
+  assert newLen >= 0
+  if x.cap == 0: x.cap = newLen
+  else: x.cap = max(newLen, (x.cap * 3) shr 1)
+  if x.data == nil: inc allocCount
+  x.data = cast[type(x.data)](realloc(x.data, x.cap * sizeof(T)))
+  for i in x.len..<newLen:
+    x.data[i] = value
+  x.len = newLen
+
+template default[T](t: typedesc[T]): T =
+  var v: T
+  v
+
+proc setLen*[T](x: var myseq[T]; newLen: int) {.deprecated.} =
+  if newlen < x.len: shrink(x, newLen)
+  else: grow(x, newLen, default(T))
+
+template `[]`*[T](x: myseq[T]; i: Natural): T =
+  assert i < x.len
+  x.data[i]
+
+template `[]=`*[T](x: myseq[T]; i: Natural; y: T) =
+  assert i < x.len
+  x.data[i] = y
+
+proc createSeq*[T](elems: varargs[T]): myseq[T] =
+  result.cap = elems.len
+  result.len = elems.len
+  result.data = cast[type(result.data)](alloc(result.cap * sizeof(T)))
+  inc allocCount
+  when supportsCopyMem(T):
+    copyMem(result.data, addr(elems[0]), result.cap * sizeof(T))
+  else:
+    for i in 0..<result.len:
+      result.data[i] = elems[i]
+
+proc len*[T](x: myseq[T]): int {.inline.} = x.len
+
+proc main =
+  var s = createSeq(1, 2, 3, 4, 5, 6)
+  s.add 89
+  s.grow s.len + 2, 90
+  for i in 0 ..< s.len:
+    echo s[i]
+
+  var nested = createSeq(createSeq(1, 2, 3), createSeq(4, 5, 6, 7))
+  for i in 0 ..< nested.len:
+    for j in 0 ..< nested[i].len:
+      echo i, " ", j, " ", nested[i][j]
+
+main()
+echo "after ", allocCount, " ", deallocCount
diff --git a/tests/destructor/tcustomstrings.nim b/tests/destructor/tcustomstrings.nim
new file mode 100644
index 000000000..31891856b
--- /dev/null
+++ b/tests/destructor/tcustomstrings.nim
@@ -0,0 +1,97 @@
+discard """
+  output: '''foo bar to appendmore here
+foo bar to appendmore here
+foo bar to appendmore here
+foo bar to appendmore here
+foo bar to appendmore here
+after 20 20'''
+joinable: false
+"""
+
+type
+  mystring = object
+    len, cap: int
+    data: ptr UncheckedArray[char]
+
+var
+  allocCount, deallocCount: int
+
+proc `=destroy`*(s: var mystring) =
+  if s.data != nil:
+    dealloc(s.data)
+    inc deallocCount
+    s.data = nil
+    s.len = 0
+    s.cap = 0
+
+proc `=sink`*(a: var mystring, b: mystring) =
+  # we hope this is optimized away for not yet alive objects:
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    inc deallocCount
+  a.len = b.len
+  a.cap = b.cap
+  a.data = b.data
+
+proc `=`*(a: var mystring; b: mystring) =
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    inc deallocCount
+    a.data = nil
+  a.len = b.len
+  a.cap = b.cap
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(a.cap + 1))
+    inc allocCount
+    copyMem(a.data, b.data, a.cap+1)
+
+proc resize(self: var mystring) =
+  if self.cap == 0: self.cap = 8
+  else: self.cap = (self.cap * 3) shr 1
+  if self.data == nil: inc allocCount
+  self.data = cast[type(self.data)](realloc(self.data, self.cap + 1))
+
+proc add*(self: var mystring; c: char) =
+  if self.len >= self.cap: resize(self)
+  self.data[self.len] = c
+  self.data[self.len+1] = '\0'
+  inc self.len
+
+proc ensure(self: var mystring; newLen: int) =
+  if newLen >= self.cap:
+    self.cap = max((self.cap * 3) shr 1, newLen)
+    if self.cap > 0:
+      if self.data == nil: inc allocCount
+      self.data = cast[type(self.data)](realloc(self.data, self.cap + 1))
+
+proc add*(self: var mystring; y: mystring) =
+  let newLen = self.len + y.len
+  ensure(self, newLen)
+  copyMem(addr self.data[self.len], y.data, y.data.len + 1)
+  self.len = newLen
+
+proc create*(lit: string): mystring =
+  let newLen = lit.len
+  ensure(result, newLen)
+  copyMem(addr result.data[result.len], addr lit[0], newLen + 1)
+  result.len = newLen
+
+proc `&`*(a, b: mystring): mystring =
+  result = a
+  result.add b
+
+proc main(n: int) =
+  var a: mystring
+  let b = create" to append"
+  for i in 0..<n:
+    if i > 4: break
+    a = create"foo bar"
+    let c = b & create"more here"
+    a.add c
+    echo cstring(a.data)
+
+  var x: array[4, mystring]
+  for i in 0..high(x): x[i] = create"added to array"
+
+main(1000)
+echo "after ", allocCount, " ", deallocCount
diff --git a/tests/destructor/tcycle1.nim b/tests/destructor/tcycle1.nim
new file mode 100644
index 000000000..8dc552294
--- /dev/null
+++ b/tests/destructor/tcycle1.nim
@@ -0,0 +1,54 @@
+discard """
+  output: "MEM 0"
+  cmd: "nim c --gc:orc $file"
+"""
+
+type
+  Node = ref object of RootObj
+    le, ri: Node
+    name: char
+
+proc edge(a, b: Node) =
+  if a.le == nil: a.le = b
+  else: a.ri = b
+
+proc createNode(name: char): Node =
+  new result
+  result.name = name
+
+#[
+
++---------+      +------+
+|         |      |      |
+|  A      +----->+      <------+-------------+
++--+------+      |      |      |             |
+   |             |      |      |     C       |
+   |             |  R   |      |             |
++--v------+      |      |      +-------------+
+|         |      |      |        ^
+|   B     <------+      |        |
+|         |      |      +--------+
++---------+      |      |
+                 +------+
+
+]#
+
+proc main =
+  let a = createNode('A')
+  let b = createNode('B')
+  let r = createNode('R')
+  let c = createNode('C')
+
+  a.edge b
+  a.edge r
+
+  r.edge b
+  r.edge c
+
+  c.edge r
+
+
+let mem = getOccupiedMem()
+main()
+GC_fullCollect()
+echo "MEM ", getOccupiedMem() - mem
diff --git a/tests/destructor/tcycle2.nim b/tests/destructor/tcycle2.nim
new file mode 100644
index 000000000..7b03101fe
--- /dev/null
+++ b/tests/destructor/tcycle2.nim
@@ -0,0 +1,36 @@
+discard """
+  output: "MEM 0"
+  cmd: "nim c --gc:orc $file"
+"""
+
+type
+  Node = ref object
+    kids: seq[Node]
+    data: string
+
+proc main(x: int) =
+  var n = Node(kids: @[], data: "3" & $x)
+  let m = n
+  n.kids.add m
+
+type
+  NodeA = ref object
+    s: char
+    a: array[3, NodeA]
+
+proc m: NodeA =
+  result = NodeA(s: 'a')
+  result.a[0] = result
+  result.a[1] = result
+  result.a[2] = result
+
+proc mainA =
+  for i in 0..10:
+    discard m()
+
+let mem = getOccupiedMem()
+main(90)
+mainA()
+GC_fullCollect()
+
+echo "MEM ", getOccupiedMem() - mem
diff --git a/tests/destructor/tcycle3.nim b/tests/destructor/tcycle3.nim
new file mode 100644
index 000000000..8662136e7
--- /dev/null
+++ b/tests/destructor/tcycle3.nim
@@ -0,0 +1,98 @@
+discard """
+  output: '''BEGIN
+END
+END 2
+cpu.nes false
+cpu step nes is nil? - false
+0'''
+  cmd: '''nim c --gc:orc $file'''
+"""
+
+# extracted from thavlak.nim
+
+type
+  BasicBlock = ref object
+    inEdges: seq[BasicBlock]
+    outEdges: seq[BasicBlock]
+    name: int
+
+proc newBasicBlock(name: int): BasicBlock =
+  result = BasicBlock(
+    inEdges: newSeq[BasicBlock](),
+    outEdges: newSeq[BasicBlock](),
+    name: name
+  )
+
+type
+  Cfg = object
+    basicBlockMap: seq[BasicBlock]
+    startNode: BasicBlock
+
+proc newCfg(): Cfg =
+  result = Cfg(
+    basicBlockMap: newSeq[BasicBlock](),
+    startNode: nil)
+
+proc createNode(cfg: var Cfg, name: int): BasicBlock =
+  if name < cfg.basicBlockMap.len:
+    result = cfg.basicBlockMap[name]
+  else:
+    result = newBasicBlock(name)
+    cfg.basicBlockMap.setLen name+1
+    cfg.basicBlockMap[name] = result
+
+proc newBasicBlockEdge(cfg: var Cfg, fromName, toName: int) =
+  echo "BEGIN"
+  let fr = cfg.createNode(fromName)
+  let to = cfg.createNode(toName)
+
+  fr.outEdges.add(to)
+  to.inEdges.add(fr)
+
+proc run(cfg: var Cfg) =
+  cfg.startNode = cfg.createNode(0) # RC = 2
+  newBasicBlockEdge(cfg, 0, 1) #
+  echo "END"
+
+  discard cfg.createNode(1)
+
+proc main =
+  var c = newCfg()
+  c.run
+  echo "END 2"
+
+# bug #14159
+type
+  NES = ref object
+    cpu: CPU
+    apu: APU
+
+  CPU = ref object
+    nes: NES
+
+  APU = object
+    nes: NES
+    cpu: CPU
+
+proc initAPU(nes: sink NES): APU {.nosinks.} =
+  result.nes = nes
+  result.cpu = nes.cpu
+
+proc step(cpu: CPU): int =
+  echo "cpu.nes ", cpu.isNil
+  echo "cpu step nes is nil? - ", cpu.nes.isNil()
+
+proc newNES(): NES =
+  new result
+  result.cpu = CPU(nes: result)
+  result.apu = initAPU(result)
+
+proc bug14159 =
+  var nesConsole = newNES()
+  discard nesConsole.cpu.step()
+
+let mem = getOccupiedMem()
+main()
+bug14159()
+GC_fullCollect()
+echo getOccupiedMem() - mem
diff --git a/tests/destructor/tdangingref_simple.nim b/tests/destructor/tdangingref_simple.nim
new file mode 100644
index 000000000..279581b0f
--- /dev/null
+++ b/tests/destructor/tdangingref_simple.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''a
+[FATAL] dangling references exist
+'''
+  exitCode: 1
+  cmd: "nim c --newruntime $file"
+"""
+
+# bug #11350
+
+type
+  Node = ref object
+    data: int
+
+proc use(x: Node) = discard
+
+proc main =
+  var x = Node(data: 3) # inferred to be an ``owned ref``
+  var dangling = unown x
+  assert dangling.data == 3
+  #use x
+  #dangling = nil
+  # reassignment causes the memory of what ``x`` points to to be freed:
+  echo "a"
+  x = Node(data: 4)
+  echo "b"
+  # accessing 'dangling' here is invalid as it is nil.
+  # at scope exit the memory of what ``x`` points to is freed
+  if dangling != nil:
+    echo dangling.data
+
+main()
diff --git a/tests/destructor/tdestructor.nim b/tests/destructor/tdestructor.nim
new file mode 100644
index 000000000..e081eb251
--- /dev/null
+++ b/tests/destructor/tdestructor.nim
@@ -0,0 +1,167 @@
+discard """
+  output: '''----1
+myobj constructed
+myobj destroyed
+----2
+mygeneric1 constructed
+mygeneric1 destroyed
+----3
+mygeneric2 constructed
+mygeneric2 destroyed
+myobj destroyed
+----4
+mygeneric3 constructed
+mygeneric1 destroyed
+----5
+mydistinctObj constructed
+myobj destroyed
+mygeneric2 destroyed
+------------------8
+mygeneric1 destroyed
+----6
+myobj destroyed
+----7
+---9
+myobj destroyed
+myobj destroyed
+'''
+"""
+
+type
+  TMyObj = object
+    x, y: int
+    p: pointer
+
+proc `=destroy`(o: var TMyObj) =
+  if o.p != nil:
+    dealloc o.p
+    o.p = nil
+    echo "myobj destroyed"
+
+type
+  TMyGeneric1[T] = object
+    x: T
+
+  TMyGeneric2[A, B] = object
+    x: A
+    y: B
+
+proc `=destroy`(o: var TMyGeneric1[int]) =
+  echo "mygeneric1 destroyed"
+
+proc `=destroy`[A, B](o: var TMyGeneric2[A, B]) =
+  echo "mygeneric2 destroyed"
+
+type
+  TMyGeneric3[A, B, C] = object
+    x: A
+    y: B
+    z: C
+
+  TDistinctObjX = distinct TMyGeneric3[TMyObj, TMyGeneric2[int, int], int]
+  TDistinctObj = TDistinctObjX
+
+  TObjKind = enum Z, A, B, C, D
+
+  TCaseObj = object
+    z: TMyGeneric3[TMyObj, float, int]
+    case kind: TObjKind
+    of Z: discard
+    of A:
+      x: TMyGeneric1[int]
+    of B, C:
+      y: TMyObj
+    else:
+      case innerKind: TObjKind
+      of Z: discard
+      of A, B, C:
+        p: TMyGeneric3[int, float, string]
+      of D:
+        q: TMyGeneric3[TMyObj, int, int]
+      r: string
+
+proc open: TMyObj =
+  # allow for superfluous ()
+  result = (TMyObj(x: 1, y: 2, p: alloc(3)))
+
+proc `$`(x: TMyObj): string = $x.y
+
+proc myobj() =
+  var x = open()
+  echo "myobj constructed"
+
+proc mygeneric1() =
+  var x = TMyGeneric1[int](x: 10)
+  echo "mygeneric1 constructed"
+
+proc mygeneric2[T](val: T) =
+  var a = open()
+
+  var b = TMyGeneric2[int, T](x: 10, y: val)
+  echo "mygeneric2 constructed"
+
+  var c = TMyGeneric3[int, int, string](x: 10, y: 20, z: "test")
+
+proc mygeneric3 =
+  var x = TMyGeneric3[int, string, TMyGeneric1[int]](
+    x: 10, y: "test", z: TMyGeneric1[int](x: 10))
+
+  echo "mygeneric3 constructed"
+
+proc mydistinctObj =
+  var x = TMyGeneric3[TMyObj, TMyGeneric2[int, int], int](
+    x: open(), y: TMyGeneric2[int, int](x: 5, y: 15), z: 20)
+
+  echo "mydistinctObj constructed"
+
+echo "----1"
+myobj()
+
+echo "----2"
+mygeneric1()
+
+echo "----3"
+mygeneric2[int](10)
+
+echo "----4"
+mygeneric3()
+
+echo "----5"
+mydistinctObj()
+
+proc caseobj =
+  block:
+    var o1 = TCaseObj(kind: A, x: TMyGeneric1[int](x: 10))
+
+  block:
+    echo "----6"
+    var o2 = TCaseObj(kind: B, y: open())
+
+  block:
+    echo "----7"
+    var o3 = TCaseObj(kind: D, innerKind: B, r: "test",
+                      p: TMyGeneric3[int, float, string](x: 10, y: 1.0, z: "test"))
+
+
+echo "------------------8"
+caseobj()
+
+proc caseobj_test_sink: TCaseObj =
+  # check that lifted sink can destroy case val correctly
+  result = TCaseObj(kind: D, innerKind: D, r: "test",
+                      q: TMyGeneric3[TMyObj, int, int](x: open(), y: 1, z: 0))
+  result = TCaseObj(kind: B, y: open())
+
+
+echo "---9"
+discard caseobj_test_sink()
+
+# issue #14315
+
+type Vector*[T] = object
+  x1: int
+  # x2: T # uncomment will remove error
+
+# proc `=destroy`*(x: var Vector[int]) = discard # this will remove error
+proc `=destroy`*[T](x: var Vector[T]) = discard
+var a: Vector[int] # Error: unresolved generic parameter
diff --git a/tests/destructor/tdestructor3.nim b/tests/destructor/tdestructor3.nim
new file mode 100644
index 000000000..3f5eb2cc1
--- /dev/null
+++ b/tests/destructor/tdestructor3.nim
@@ -0,0 +1,185 @@
+discard """
+  output: '''
+assign
+destroy
+destroy
+5
+123
+destroy Foo: 123
+destroy Foo: 5
+(x1: (val: ...))
+destroy
+---------------
+app begin
+(val: ...)
+destroy
+app end
+'''
+joinable: false
+"""
+
+# bug #2821
+
+type T = object
+
+proc `=`(lhs: var T, rhs: T) =
+  echo "assign"
+
+proc `=destroy`(v: var T) =
+  echo "destroy"
+
+proc use(x: T) = discard
+
+proc usedToBeBlock =
+  var v1 = T()
+  var v2: T = v1
+  discard addr(v2) # prevent cursorfication
+  use v1
+
+usedToBeBlock()
+
+# bug #1632
+
+type
+  Foo = object of RootObj
+    x: int
+
+proc `=destroy`(a: var Foo) =
+  echo "destroy Foo: " & $a.x
+
+template toFooPtr(a: int{lit}): ptr Foo =
+  var temp = Foo(x:a)
+  temp.addr
+
+proc test(a: ptr Foo) =
+  echo a[].x
+
+proc main =
+  test(toFooPtr(5))
+  test(toFooPtr(123))
+
+main()
+
+# bug #11517
+type
+  UniquePtr*[T] = object
+    val: ptr T
+
+proc `=destroy`*[T](p: var UniquePtr[T]) =
+  mixin `=destroy`
+  echo "destroy"
+  if p.val != nil:
+    `=destroy`(p.val[])
+    dealloc(p.val)
+    p.val = nil
+
+proc `=`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.}
+
+proc `=sink`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.inline.} =
+  if dest.val != src.val:
+    if dest.val != nil:
+      `=destroy`(dest)
+    dest.val = src.val
+
+proc newUniquePtr*[T](val: sink T): UniquePtr[T] =
+  result.val = create(T)
+  result.val[] = val
+
+#-------------------------------------------------------------
+
+type
+  MyObject = object of RootObj
+    x1: UniquePtr[int]
+
+  MyObject2 = object of MyObject
+
+proc newObj2(x:int, y: float): MyObject2 =
+  MyObject2(x1: newUniquePtr(x))
+
+proc test =
+  let obj2 = newObj2(1, 1.0)
+  echo obj2
+
+test()
+
+
+#------------------------------------------------------------
+# Issue #12883
+
+type
+  TopObject = object
+    internal: UniquePtr[int]
+
+proc deleteTop(p: ptr TopObject) =
+  if p != nil:
+    `=destroy`(p[]) # !!! this operation used to leak the integer
+    deallocshared(p)
+
+proc createTop(): ptr TopObject =
+  result = cast[ptr TopObject](allocShared0(sizeof(TopObject)))
+  result.internal = newUniquePtr(1)
+
+proc test2() =
+  let x = createTop()
+  echo $x.internal
+  deleteTop(x)
+
+echo "---------------"
+echo "app begin"
+test2()
+echo "app end"
+
+# bug #14601
+
+when true: # D20200607T202043
+  type Foo2 = object
+    x: int
+    x2: array[10, int]
+
+  type Vec = object
+    vals: seq[Foo2]
+
+  proc `=destroy`*(a: var Foo2) {.inline.} =
+    discard
+
+  proc initFoo2(x: int): Foo2 = Foo2(x: x)
+
+  proc add2(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2`
+    v.vals.add a
+
+  proc add3(v: var Vec, a: Foo2) = # ditto with `a: sink Foo2`
+    v.vals = @[a]
+
+  proc add4(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2`
+    v.vals.add a
+
+  proc add5(v: var Vec, a: sink Foo2) = # ditto with `a: sink Foo2`
+    v.vals = @[a]
+
+  proc main2()=
+    var a: Vec
+    var b = Foo2(x: 10)
+    a.add2 b # ok
+    a.vals.add Foo2(x: 10) # ok
+    a.add2 initFoo2(x = 10) # ok
+    a.add2 Foo2(x: 10) # bug
+    a.add3 initFoo2(x = 10) # ok
+    a.add3 Foo2(x: 10) # bug
+    a.add4 initFoo2(x = 10) # ok
+    a.add4 Foo2(x: 10) # bug
+    a.add5 initFoo2(x = 10) # ok
+    a.add5 Foo2(x: 10) # bug
+  main2()
+
+
+
+#------------------------------------------------------------
+# Issue #15825
+
+type
+  Union = string | int | char
+
+proc run(a: sink Union) =
+  discard
+
+run("123")
diff --git a/tests/destructor/tdestructor_too_late.nim b/tests/destructor/tdestructor_too_late.nim
new file mode 100644
index 000000000..76d1dde84
--- /dev/null
+++ b/tests/destructor/tdestructor_too_late.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "cannot bind another '=destroy' to: Obj; previous declaration was constructed here implicitly: tdestructor_too_late.nim(7, 16)"
+"""
+type Obj* = object
+  v*: int
+
+proc something(this: sink Obj) = 
+  discard
+
+proc `=destroy`(this: var Obj) =
+  echo "igotdestroyed"
+  this.v = -1
+
+var test* = Obj(v: 42)
\ No newline at end of file
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/tdont_return_unowned_from_owned.nim b/tests/destructor/tdont_return_unowned_from_owned.nim
new file mode 100644
index 000000000..ffe87cd76
--- /dev/null
+++ b/tests/destructor/tdont_return_unowned_from_owned.nim
@@ -0,0 +1,56 @@
+discard """
+  cmd: "nim check --newruntime --hints:off $file"
+  nimout: '''
+tdont_return_unowned_from_owned.nim(26, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
+tdont_return_unowned_from_owned.nim(27, 13) Error: assignment produces a dangling ref: the unowned ref lives longer than the owned ref
+tdont_return_unowned_from_owned.nim(31, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(RootRef)' as the return type
+tdont_return_unowned_from_owned.nim(43, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type
+tdont_return_unowned_from_owned.nim(46, 10) Error: cannot return an owned pointer as an unowned pointer; use 'owned(Obj)' as the return type
+tdont_return_unowned_from_owned.nim(49, 6) Error: type mismatch: got <Obj>
+but expected one of:
+proc new[T](a: var ref T; finalizer: proc (x: ref T) {.nimcall.})
+  first type mismatch at position: 2
+  missing parameter: finalizer
+2 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
+
+expression: new(result)
+tdont_return_unowned_from_owned.nim(49, 6) Error: illformed AST: 
+'''
+  errormsg: "illformed AST:"
+"""
+
+
+
+proc testA(result: var (RootRef, RootRef)) =
+  let r: owned RootRef = RootRef()
+  result[0] = r
+  result[1] = RootRef()
+
+proc testB(): RootRef =
+  let r: owned RootRef = RootRef()
+  result = r
+
+
+
+
+
+## line 30
+# bug #11073
+type
+  Obj = ref object
+
+proc newObjA(): Obj =
+  result = new Obj
+
+proc newObjB(): Obj =
+  result = Obj()
+
+proc newObjC(): Obj =
+  new(result) # illFormedAst raises GlobalError,
+              # without pipeline parsing, it needs to placed at the end
+              # in case that it disturbs other errors
+
+let a = newObjA()
+let b = newObjB()
+let c = newObjC()
+
diff --git a/tests/destructor/terror_module.nim b/tests/destructor/terror_module.nim
new file mode 100644
index 000000000..f3d7c9b26
--- /dev/null
+++ b/tests/destructor/terror_module.nim
@@ -0,0 +1,20 @@
+discard """
+joinable: false
+cmd: "nim check $file"
+errormsg: "type bound operation `=deepcopy` can be defined only in the same module with its type (MyTestObject)"
+nimout: '''
+terror_module.nim(14, 1) Error: type bound operation `=destroy` can be defined only in the same module with its type (MyTestObject)
+terror_module.nim(16, 1) Error: type bound operation `=sink` can be defined only in the same module with its type (MyTestObject)
+terror_module.nim(18, 1) Error: type bound operation `=` can be defined only in the same module with its type (MyTestObject)
+terror_module.nim(20, 1) Error: type bound operation `=deepcopy` can be defined only in the same module with its type (MyTestObject)
+'''
+"""
+import helper
+
+proc `=destroy`[T](x: var MyTestObject[T]) = discard
+
+proc `=sink`[T](x: var MyTestObject[T], y:MyTestObject[T]) = discard
+
+proc `=`[T](x: var MyTestObject[T], y: MyTestObject[T]) = discard
+
+proc `=deepcopy`[T](x: ptr MyTestObject[T]): ptr MyTestObject[T] = discard
diff --git a/tests/destructor/texceptions.nim b/tests/destructor/texceptions.nim
new file mode 100644
index 000000000..335ca23be
--- /dev/null
+++ b/tests/destructor/texceptions.nim
@@ -0,0 +1,29 @@
+discard """
+  cmd: '''nim c --gc:arc $file'''
+  output: '''0'''
+"""
+
+proc other =
+  raise newException(ValueError, "stuff happening")
+
+proc indirectViaProcCall =
+  var correct = 0
+  for i in 1 .. 20:
+    try:
+      other()
+    except:
+      let x = getCurrentException()
+      correct += ord(x of ValueError)
+  doAssert correct == 20
+
+proc direct =
+  for i in 1 .. 20:
+    try:
+      raise newException(ValueError, "stuff happening")
+    except ValueError:
+      discard
+
+let mem = getOccupiedMem()
+indirectViaProcCall()
+direct()
+echo getOccupiedMem() - mem
diff --git a/tests/destructor/texplicit_move.nim b/tests/destructor/texplicit_move.nim
new file mode 100644
index 000000000..93795af42
--- /dev/null
+++ b/tests/destructor/texplicit_move.nim
@@ -0,0 +1,30 @@
+
+discard """
+  output: '''3
+0
+0
+10
+destroyed!
+'''
+joinable: false
+"""
+
+type
+  myseq* = object
+    f: int
+
+proc `=destroy`*(x: var myseq) =
+  echo "destroyed!"
+
+var
+  x: myseq
+x.f = 3
+echo move(x.f)
+echo x.f
+
+# bug #9743
+let a = create int
+a[] = 10
+var b = move a[]
+echo a[]
+echo b
diff --git a/tests/destructor/tfinalizer.nim b/tests/destructor/tfinalizer.nim
new file mode 100644
index 000000000..eb2cd09af
--- /dev/null
+++ b/tests/destructor/tfinalizer.nim
@@ -0,0 +1,31 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: '''Foo(field: "Dick Laurent", k: ka, x: 0.0)
+Nobody is dead
+Dick Laurent is dead'''
+"""
+
+type
+  Kind = enum
+    ka, kb
+  Foo = ref object
+    field: string
+    case k: Kind
+    of ka: x: float
+    of kb: discard
+
+#var x = Foo(field: "lovely")
+proc finalizer(x: Foo) =
+  echo x.field, " is dead"
+
+var x: Foo
+new(x, finalizer)
+x.field = "Dick Laurent"
+# reference to a great movie. If you haven't seen it, highly recommended.
+
+echo repr x
+
+# bug #13112: bind the same finalizer multiple times:
+var xx: Foo
+new(xx, finalizer)
+xx.field = "Nobody"
diff --git a/tests/destructor/tgcdestructors.nim b/tests/destructor/tgcdestructors.nim
new file mode 100644
index 000000000..07a3731a0
--- /dev/null
+++ b/tests/destructor/tgcdestructors.nim
@@ -0,0 +1,203 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
+  output: '''hi
+ho
+ha
+@["arg", "asdfklasdfkl", "asdkfj", "dfasj", "klfjl"]
+@[1, 2, 3]
+@["red", "yellow", "orange", "rtrt1", "pink"]
+a: @[4, 2, 3]
+0
+30
+true
+(allocCount: 27, deallocCount: 27)'''
+"""
+
+include system / ansi_c
+
+proc main =
+  var s: seq[string] = @[]
+  for i in 0..<80: s.add "foo"
+
+main()
+
+const
+  test = @["hi", "ho", "ha"]
+
+for t in test:
+  echo t
+
+type
+  InterpolatedKind* = enum
+    ikStr,                   ## ``str`` part of the interpolated string
+    ikDollar,                ## escaped ``$`` part of the interpolated string
+    ikVar,                   ## ``var`` part of the interpolated string
+    ikExpr                   ## ``expr`` part of the interpolated string
+
+iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
+                                                  value: string] =
+  var i = 0
+  var kind: InterpolatedKind
+  while true:
+    var j = i
+    if j < s.len and s[j] == '$':
+      if j+1 < s.len and s[j+1] == '{':
+        inc j, 2
+        var nesting = 0
+        block curlies:
+          while j < s.len:
+            case s[j]
+            of '{': inc nesting
+            of '}':
+              if nesting == 0:
+                inc j
+                break curlies
+              dec nesting
+            else: discard
+            inc j
+          raise newException(ValueError,
+            "Expected closing '}': " & substr(s, i, s.high))
+        inc i, 2 # skip ${
+        kind = ikExpr
+      elif j+1 < s.len and s[j+1] in {'A'..'Z', 'a'..'z', '_'}:
+        inc j, 2
+        while j < s.len and s[j] in {'A'..'Z', 'a'..'z', '0'..'9', '_'}: inc(j)
+        inc i # skip $
+        kind = ikVar
+      elif j+1 < s.len and s[j+1] == '$':
+        inc j, 2
+        inc i # skip $
+        kind = ikDollar
+      else:
+        raise newException(ValueError,
+          "Unable to parse a varible name at " & substr(s, i, s.high))
+    else:
+      while j < s.len and s[j] != '$': inc j
+      kind = ikStr
+    if j > i:
+      # do not copy the trailing } for ikExpr:
+      yield (kind, substr(s, i, j-1-ord(kind == ikExpr)))
+    else:
+      break
+    i = j
+
+proc parseCmdLine(c: string): seq[string] =
+  result = @[]
+  var i = 0
+  var a = ""
+  while true:
+    setLen(a, 0)
+    while i < c.len and c[i] in {' ', '\t', '\l', '\r'}: inc(i)
+    if i >= c.len: break
+    var inQuote = false
+    while i < c.len:
+      case c[i]
+      of '\\':
+        var j = i
+        while j < c.len and c[j] == '\\': inc(j)
+        if j < c.len and c[j] == '"':
+          for k in 1..(j-i) div 2: a.add('\\')
+          if (j-i) mod 2 == 0:
+            i = j
+          else:
+            a.add('"')
+            i = j+1
+        else:
+          a.add(c[i])
+          inc(i)
+      of '"':
+        inc(i)
+        if not inQuote: inQuote = true
+        elif i < c.len and c[i] == '"':
+          a.add(c[i])
+          inc(i)
+        else:
+          inQuote = false
+          break
+      of ' ', '\t':
+        if not inQuote: break
+        a.add(c[i])
+        inc(i)
+      else:
+        a.add(c[i])
+        inc(i)
+    add(result, a)
+
+
+proc other =
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                  (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  var i = 0
+  for s in interpolatedFragments(input):
+    doAssert s == expected[i]
+    inc i
+
+  echo parseCmdLine("arg asdfklasdfkl asdkfj dfasj klfjl")
+
+other()
+
+# bug #11050
+
+type
+  Obj* = object
+    f*: seq[int]
+
+method main(o: Obj) {.base.} =
+  for newb in o.f:
+    discard
+
+# test that o.f was not moved!
+proc testforNoMove =
+  var o = Obj(f: @[1, 2, 3])
+  main(o)
+  echo o.f
+
+testforNoMove()
+
+# bug #11065
+type
+  Warm = seq[string]
+
+proc testWarm =
+  var w: Warm
+  w = @["red", "yellow", "orange"]
+
+  var x = "rt"
+  var y = "rt1"
+  w.add(x & y)
+
+  w.add("pink")
+  echo w
+
+testWarm()
+
+proc mutConstSeq() =
+  # bug #11524
+  var a = @[1,2,3]
+  a[0] = 4
+  echo "a: ", a
+
+mutConstSeq()
+
+proc mainSeqOfCap =
+  # bug #11098
+  var s = newSeqOfCap[int](10)
+  echo s.len
+
+  var s2 = newSeqUninitialized[int](30)
+  echo s2.len
+
+mainSeqOfCap()
+
+# bug #11614
+
+let ga = "foo"
+
+proc takeAinArray =
+  let b = [ga]
+
+takeAinArray()
+echo ga == "foo"
+
+echo getAllocStats()
diff --git a/tests/destructor/tgcleak4.nim b/tests/destructor/tgcleak4.nim
new file mode 100644
index 000000000..4299c8841
--- /dev/null
+++ b/tests/destructor/tgcleak4.nim
@@ -0,0 +1,47 @@
+discard """
+  outputsub: "no leak: "
+  cmd: "nim c --gc:arc $file"
+"""
+# bug #12758
+type
+  TExpr {.inheritable.} = object ## abstract base class for an expression
+  PLiteral = ref TLiteral
+  TLiteral = object of TExpr
+    x: int
+    op1: string
+  TPlusExpr = object of TExpr
+    a, b: ref TExpr
+    op2: string
+
+method eval(e: ref TExpr): int {.base.} =
+  # override this base method
+  quit "to override!"
+
+method eval(e: ref TLiteral): int = return e.x
+
+method eval(e: ref TPlusExpr): int =
+  # watch out: relies on dynamic binding
+  return eval(e.a) + eval(e.b)
+
+proc newLit(x: int): ref TLiteral =
+  new(result)
+  result.x = x
+  result.op1 = $getOccupiedMem()
+
+proc newPlus(a, b: ref TExpr): ref TPlusExpr =
+  new(result)
+  result.a = a
+  result.b = b
+  result.op2 = $getOccupiedMem()
+
+const Limit = when compileOption("gc", "markAndSweep") or compileOption("gc", "boehm"): 5*1024*1024 else: 500_000
+
+for i in 0..100_000:
+  var s: array[0..11, ref TExpr]
+  for j in 0..high(s):
+    s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4))
+    if eval(s[j]) != j+6:
+      quit "error: wrong result"
+  if getOccupiedMem() > Limit: quit("still a leak!")
+
+echo "no leak: ", getOccupiedMem()
diff --git a/tests/destructor/tglobaldestructor.nim b/tests/destructor/tglobaldestructor.nim
new file mode 100644
index 000000000..4d002a092
--- /dev/null
+++ b/tests/destructor/tglobaldestructor.nim
@@ -0,0 +1,9 @@
+discard """
+  cmd: '''nim c --gc:arc $file'''
+  output: '''(v: 42)
+igotdestroyed'''
+"""
+
+import objFile
+
+echo test
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/tgotoexceptions.nim b/tests/destructor/tgotoexceptions.nim
new file mode 100755
index 000000000..f76592270
--- /dev/null
+++ b/tests/destructor/tgotoexceptions.nim
@@ -0,0 +1,117 @@
+discard """
+  output: '''
+msg1
+msg2
+finally2
+finally1
+begin
+one iteration!
+caught!
+except1
+finally1
+caught! 2
+BEFORE
+FINALLY
+BEFORE
+EXCEPT
+FINALLY
+RECOVER
+BEFORE
+EXCEPT: IOError: hi
+FINALLY
+'''
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+"""
+
+#bug 7204
+proc nested_finally =
+  try:
+    raise newException(KeyError, "msg1")
+  except KeyError as ex:
+    echo ex.msg
+    try:
+      raise newException(ValueError, "msg2")
+    except:
+      echo getCurrentExceptionMsg()
+    finally:
+      echo "finally2"
+  finally:
+    echo "finally1"
+
+nested_finally()
+
+proc doraise =
+  raise newException(ValueError, "gah")
+
+proc main =
+  while true:
+    try:
+      echo "begin"
+      doraise()
+    finally:
+      echo "one ", "iteration!"
+
+try:
+  main()
+except:
+  echo "caught!"
+
+when true:
+  proc p =
+    try:
+      raise newException(Exception, "Hello")
+    except:
+      echo "except1"
+      raise
+    finally:
+      echo "finally1"
+
+  try:
+    p()
+  except:
+    echo "caught! 2"
+
+
+proc noException =
+  try:
+    echo "BEFORE"
+
+  except:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: noException()
+except: echo "RECOVER"
+
+proc reraise_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "")
+
+  except IOError:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: reraise_in_except()
+except: echo "RECOVER"
+
+proc return_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "hi")
+
+  except:
+    echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg()
+    return
+
+  finally:
+    echo "FINALLY"
+
+try: return_in_except()
+except: echo "RECOVER"
diff --git a/tests/destructor/tgotoexceptions2.nim b/tests/destructor/tgotoexceptions2.nim
new file mode 100644
index 000000000..057caf7b7
--- /dev/null
+++ b/tests/destructor/tgotoexceptions2.nim
@@ -0,0 +1,104 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+  output: '''
+B1
+B2
+catch
+A1
+1
+B1
+B2
+catch
+A1
+A2
+0
+B1
+B2
+A1
+1
+B1
+B2
+A1
+A2
+3
+A
+B
+C
+'''
+"""
+
+# More thorough test of return-in-finaly
+
+var raiseEx = true
+var returnA = true
+var returnB = false
+
+proc main: int =
+  try: #A
+    try: #B
+      if raiseEx:
+        raise newException(OSError, "")
+      return 3
+    finally: #B
+      echo "B1"
+      if returnB:
+        return 2
+      echo "B2"
+  except OSError: #A
+    echo "catch"
+  finally: #A
+    echo "A1"
+    if returnA:
+      return 1
+    echo "A2"
+
+for x in [true, false]:
+  for y in [true, false]:
+    # echo "raiseEx: " & $x
+    # echo "returnA: " & $y
+    # echo "returnB: " & $z
+    # in the original test returnB was set to true too and
+    # this leads to swallowing the OSError exception. This is
+    # somewhat compatible with Python but it's non-sense, 'finally'
+    # should not be allowed to swallow exceptions. The goto based
+    # implementation does something sane so we don't "correct" its
+    # behavior just to be compatible with v1.
+    raiseEx = x
+    returnA = y
+    echo main()
+
+# Various tests of return nested in double try/except statements
+
+proc test1() =
+
+  defer: echo "A"
+
+  try:
+    raise newException(OSError, "Problem")
+  except OSError:
+    return
+
+test1()
+
+
+proc test2() =
+
+  defer: echo "B"
+
+  try:
+    return
+  except OSError:
+    discard
+
+test2()
+
+proc test3() =
+  try:
+    try:
+      raise newException(OSError, "Problem")
+    except OSError:
+      return
+  finally:
+    echo "C"
+
+test3()
diff --git a/tests/destructor/tgotoexceptions3.nim b/tests/destructor/tgotoexceptions3.nim
new file mode 100644
index 000000000..308d288b2
--- /dev/null
+++ b/tests/destructor/tgotoexceptions3.nim
@@ -0,0 +1,7 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+  outputsub: "Error: unhandled exception: Problem [OSError]"
+  exitcode: "1"
+"""
+
+raise newException(OSError, "Problem")
diff --git a/tests/destructor/tgotoexceptions4.nim b/tests/destructor/tgotoexceptions4.nim
new file mode 100644
index 000000000..b2b481256
--- /dev/null
+++ b/tests/destructor/tgotoexceptions4.nim
@@ -0,0 +1,60 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+  output: '''caught in gun
+caught in fun
+caughtsome msgMyExcept
+in finally
+caught1
+123
+123'''
+"""
+
+when true:
+  # bug #13070
+  type MyExcept = object of CatchableError
+  proc gun() =
+    try:
+      raise newException(MyExcept, "some msg")
+    except Exception as eab:
+      echo "caught in gun"
+      raise eab
+
+  proc fun() =
+    try:
+      gun()
+    except Exception as e:
+      echo "caught in fun"
+      echo("caught", e.msg, e.name)
+    finally:
+      echo "in finally"
+  fun()
+
+when true:
+  # bug #13072
+  type MyExceptB = object of CatchableError
+  proc gunB() =
+    raise newException(MyExceptB, "some msg")
+  proc funB() =
+    try:
+      gunB()
+    except CatchableError:
+      echo "caught1"
+  funB()
+
+# bug #13782
+
+import strutils
+var n = 123
+
+try: n = parseInt("xxx")
+except: discard
+
+echo n
+
+proc sameTestButForLocalVar =
+  var n = 123
+  try: n = parseInt("xxx")
+  except: discard
+  echo n
+
+sameTestButForLocalVar()
diff --git a/tests/destructor/tgotoexceptions5.nim b/tests/destructor/tgotoexceptions5.nim
new file mode 100644
index 000000000..695aab0a4
--- /dev/null
+++ b/tests/destructor/tgotoexceptions5.nim
@@ -0,0 +1,45 @@
+discard """
+  output: '''
+before
+swallowed
+before
+swallowed B
+'''
+  cmd: "nim c --gc:arc --exceptions:goto -d:ssl $file"
+"""
+
+# bug #13599
+proc main() =
+  try:
+    echo "before"
+    raise newException(CatchableError, "foo")
+  except AssertionDefect:
+    echo "caught"
+  echo "after"
+
+try:
+  main()
+except:
+  echo "swallowed"
+
+proc mainB() =
+  try:
+    echo "before"
+    raise newException(CatchableError, "foo")
+  # except CatchableError: # would work
+  except AssertionDefect:
+    echo "caught"
+  except:
+    raise
+  echo "after"
+
+try:
+  mainB()
+except:
+  echo "swallowed B"
+
+# bug #14647
+import httpclient
+
+newAsyncHttpClient().close()
+
diff --git a/tests/destructor/tgotoexceptions6.nim b/tests/destructor/tgotoexceptions6.nim
new file mode 100644
index 000000000..7c01f6a52
--- /dev/null
+++ b/tests/destructor/tgotoexceptions6.nim
@@ -0,0 +1,10 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto $file"
+  outputsub: "Error: unhandled exception: virus detected [ValueError]"
+  exitcode: "1"
+"""
+
+# bug #13436
+proc foo =
+  raise newException(ValueError, "virus detected")
+foo()
diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim
new file mode 100644
index 000000000..c04bd6ba0
--- /dev/null
+++ b/tests/destructor/tgotoexceptions7.nim
@@ -0,0 +1,49 @@
+discard """
+  cmd: "nim c --gc:arc --exceptions:goto --panics:off $file"
+  output: '''prevented!
+caught
+AssertionDefect
+900'''
+"""
+
+type
+  E = enum
+    kindA, kindB
+  Obj = object
+    case kind: E
+    of kindA: s: string
+    of kindB: i: int
+
+  ObjA = ref object of RootObj
+  ObjB = ref object of ObjA
+
+proc takeRange(x: range[0..4]) = discard
+
+proc bplease(x: ObjB) = discard
+
+proc helper = doAssert(false)
+
+proc main(i: int) =
+  var obj = Obj(kind: kindA, s: "abc")
+  {.cast(uncheckedAssign).}:
+    obj.kind = kindB
+  obj.i = 2
+  try:
+    var objA = ObjA()
+    bplease(ObjB(objA))
+  except ObjectConversionDefect:
+    echo "prevented!"
+
+  try:
+    takeRange(i)
+  except RangeDefect:
+    echo "caught"
+
+  try:
+    helper()
+  except AssertionDefect:
+    echo "AssertionDefect"
+
+  echo i * i
+
+main(30)
diff --git a/tests/destructor/tgotoexceptions8.nim b/tests/destructor/tgotoexceptions8.nim
new file mode 100644
index 000000000..8ed2ed0ba
--- /dev/null
+++ b/tests/destructor/tgotoexceptions8.nim
@@ -0,0 +1,76 @@
+discard """
+  output: '''A
+B
+X
+inner finally
+Y
+outer finally
+msg1
+msg2
+finally2
+finally1
+true'''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #13668
+
+proc main =
+  try:
+    try:
+      raise newException(IOError, "IOError")
+
+    except:
+      echo "A"
+      raise newException(CatchableError, "CatchableError")
+
+  except:
+    echo "B"
+    #discard
+
+proc mainB =
+  try:
+    try:
+      raise newException(IOError, "IOError")
+
+    except:
+      echo "X"
+      raise newException(CatchableError, "CatchableError")
+    finally:
+      echo "inner finally"
+
+  except:
+    echo "Y"
+    #discard
+  finally:
+    echo "outer finally"
+
+main()
+mainB()
+
+when true:
+  #bug 7204
+  proc nested_finally =
+    try:
+      raise newException(KeyError, "msg1")
+    except KeyError as ex:
+      echo ex.msg
+      try:
+        # pop exception
+        raise newException(ValueError, "msg2") # push: exception stack (1 entry)
+      except:
+        echo getCurrentExceptionMsg()
+        # pop exception (except)
+      finally:
+        echo "finally2"
+      # pop exception (except KeyError as ex)
+    finally:
+      echo "finally1"
+
+  nested_finally()
+
+# bug #14925
+proc test(b: bool) =
+  echo b
+
+test(try: true except: false)
diff --git a/tests/destructor/tinvalid_rebind.nim b/tests/destructor/tinvalid_rebind.nim
new file mode 100644
index 000000000..0f15c8f9e
--- /dev/null
+++ b/tests/destructor/tinvalid_rebind.nim
@@ -0,0 +1,15 @@
+discard """
+joinable: false
+cmd: "nim check $file"
+errormsg: "cannot bind another '=destroy' to: Foo; previous declaration was constructed here implicitly: tinvalid_rebind.nim(12, 7)"
+line: 14
+"""
+
+type
+  Foo[T] = object
+
+proc main =
+  var f: Foo[int]
+
+proc `=destroy`[T](f: var Foo[T]) =
+  discard
diff --git a/tests/destructor/tmatrix.nim b/tests/destructor/tmatrix.nim
new file mode 100644
index 000000000..2fd5af789
--- /dev/null
+++ b/tests/destructor/tmatrix.nim
@@ -0,0 +1,135 @@
+discard """
+  output: '''after 2 2
+after 2 2
+after 2 2
+after 2 2'''
+"""
+# bug #9263
+type
+  Matrix* = object
+    # Array for internal storage of elements.
+    data: ptr UncheckedArray[float]
+    # Row and column dimensions.
+    m*, n*: int
+
+var
+  allocCount, deallocCount: int
+
+proc `=destroy`*(m: var Matrix) =
+  if m.data != nil:
+    dealloc(m.data)
+    deallocCount.inc
+    m.data = nil
+    m.m = 0
+    m.n = 0
+
+proc `=sink`*(a: var Matrix; b: Matrix) =
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    deallocCount.inc
+  a.data = b.data
+  a.m = b.m
+  a.n = b.n
+
+proc `=copy`*(a: var Matrix; b: Matrix) =
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    deallocCount.inc
+    a.data = nil
+  a.m = b.m
+  a.n = b.n
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(a.m * a.n * sizeof(float)))
+    allocCount.inc
+    copyMem(a.data, b.data, b.m * b.n * sizeof(float))
+
+proc `=dup`*(a: Matrix): Matrix =
+  `=copy`(result, a)
+
+proc matrix*(m, n: int, s: float): Matrix =
+  ## Construct an m-by-n constant matrix.
+  result.m = m
+  result.n = n
+  result.data = cast[type(result.data)](alloc(m * n * sizeof(float)))
+  allocCount.inc
+  for i in 0 ..< m * n:
+    result.data[i] = s
+
+proc len(m: Matrix): int = m.n * m.m
+
+proc `[]`*(m: Matrix, i, j: int): float {.inline.} =
+  ## Get a single element.
+  m.data[i * m.n + j]
+
+proc `[]`*(m: var Matrix, i, j: int): var float {.inline.} =
+  ## Get a single element.
+  m.data[i * m.n + j]
+
+proc `[]=`*(m: var Matrix, i, j: int, s: float) =
+  ## Set a single element.
+  m.data[i * m.n + j] = s
+
+proc `-`*(m: sink Matrix): Matrix =
+  ## Unary minus
+  result = m
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = -result[i, j]
+
+proc `+`*(a: sink Matrix; b: Matrix): Matrix =
+  ## ``C = A + B``
+  doAssert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(a.len == b.len) # non destructive use before sink is ok
+  result = a
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = result[i, j] + b[i, j]
+
+proc `-`*(a: sink Matrix; b: Matrix): Matrix =
+  ## ``C = A - B``
+  assert(b.m == a.m and b.n == a.n, "Matrix dimensions must agree.")
+  doAssert(a.len == b.len) # non destructive use before sink is ok
+  result = a
+  for i in 0 ..< result.m:
+    for j in 0 ..< result.n:
+      result[i, j] = a[i, j] - b[i, j]
+
+proc info =
+  echo "after ", allocCount, " ", deallocCount
+  allocCount = 0
+  deallocCount = 0
+
+proc copy(a: Matrix): Matrix = a
+
+proc test1 =
+  var a = matrix(5, 5, 1.0)
+  var b = copy a
+  var c = a + b
+
+proc test2 =
+  var a = matrix(5, 5, 1.0)
+  var b = copy a
+  var c = -a
+
+proc test3 =
+  var a = matrix(5, 5, 1.0)
+  var b = matrix(5, 5, 2.0)
+  #    a = a - b
+  b = -b + a
+
+proc test4 =
+  # bug #9294
+  var a = matrix(5, 5, 1.0)
+  a = -a + a
+
+test1()
+info()
+
+test2()
+info()
+
+test3()
+info()
+
+test4()
+info()
diff --git a/tests/destructor/tmisc_destructors.nim b/tests/destructor/tmisc_destructors.nim
new file mode 100644
index 000000000..082cb0f78
--- /dev/null
+++ b/tests/destructor/tmisc_destructors.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''@[0]
+@[1]
+@[2]
+@[3]'''
+  joinable: false
+"""
+
+# bug #6434
+
+type
+  Foo* = object
+    boo: int
+
+var sink_counter = 0
+var assign_counter = 0
+
+proc `=sink`(dest: var Foo, src: Foo) =
+  sink_counter.inc
+
+proc `=`(dest: var Foo, src: Foo) =
+  assign_counter.inc
+
+proc createFoo(): Foo = Foo(boo: 0)
+
+proc test(): auto =
+  var a, b = createFoo()
+  return (a, b, Foo(boo: 5))
+
+var (ag, bg, _) = test()
+
+doAssert assign_counter == 0
+doAssert sink_counter == 0
+
+# bug #11510
+proc main =
+  for i in 0 ..< 4:
+    var buffer: seq[int] # = @[] # uncomment to make it work
+    # var buffer: string # also this is broken
+    buffer.add i
+    echo buffer
+
+main()
diff --git a/tests/destructor/tmove.nim b/tests/destructor/tmove.nim
new file mode 100644
index 000000000..2762aff90
--- /dev/null
+++ b/tests/destructor/tmove.nim
@@ -0,0 +1,18 @@
+discard """
+  targets: "c cpp"
+"""
+
+block:
+  var called = 0
+
+  proc bar(a: var int): var int =
+    inc called
+    result = a
+
+  proc foo =
+    var a = 2
+    var s = move bar(a)
+    doAssert called == 1
+    doAssert s == 2
+
+  foo()
diff --git a/tests/destructor/tmove_objconstr.nim b/tests/destructor/tmove_objconstr.nim
new file mode 100644
index 000000000..cdc1eb1c0
--- /dev/null
+++ b/tests/destructor/tmove_objconstr.nim
@@ -0,0 +1,194 @@
+
+discard """
+output:  '''test created
+test destroyed 0
+1
+2
+3
+4
+Pony is dying!'''
+joinable: false
+targets: "c"
+"""
+
+# bug #4214
+type
+  Data = object
+    data: string
+    rc: int
+
+proc `=destroy`(d: var Data) =
+  dec d.rc
+  echo d.data, " destroyed ", d.rc
+
+proc `=`(dst: var Data, src: Data) =
+  echo src.data, " copied"
+  dst.data = src.data & " (copy)"
+  dec dst.rc
+  inc dst.rc
+
+proc initData(s: string): Data =
+  result = Data(data: s, rc: 1)
+  echo s, " created"
+
+proc pointlessWrapper(s: string): Data =
+  result = initData(s)
+
+proc main =
+  var x = pointlessWrapper"test"
+
+when true:
+  main()
+
+# bug #985
+
+type
+  Pony = object
+    name: string
+
+proc `=destroy`(o: var Pony) =
+  echo "Pony is dying!"
+
+proc getPony: Pony =
+  result = Pony(name: "Sparkles")
+
+iterator items(p: Pony): int =
+  for i in 1..4:
+    yield i
+
+for x in getPony():
+  echo x
+
+
+
+
+
+#------------------------------------------------------------
+#-- Move into tuple constructor and move on tuple unpacking
+#------------------------------------------------------------
+
+type
+  MySeqNonCopyable* = object
+    len: int
+    data: ptr UncheckedArray[float]
+
+proc `=destroy`*(m: var MySeqNonCopyable) {.inline.} =
+  if m.data != nil:
+    deallocShared(m.data)
+    m.data = nil
+
+proc `=`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.error.}
+
+proc `=sink`*(m: var MySeqNonCopyable, m2: MySeqNonCopyable) {.inline.} =
+  if m.data != m2.data:
+    if m.data != nil:
+      `=destroy`(m)
+    m.len = m2.len
+    m.data = m2.data
+
+proc len*(m: MySeqNonCopyable): int {.inline.} = m.len
+
+proc `[]`*(m: MySeqNonCopyable; i: int): float {.inline.} =
+  m.data[i.int]
+
+proc `[]=`*(m: var MySeqNonCopyable; i, val: float) {.inline.} =
+  m.data[i.int] = val
+
+proc setTo(s: var MySeqNonCopyable, val: float) =
+  for i in 0..<s.len.int:
+    s.data[i] = val
+
+proc newMySeq*(size: int, initial_value = 0.0): MySeqNonCopyable =#
+  result.len = size
+  if size > 0:
+    result.data = cast[ptr UncheckedArray[float]](createShared(float, size))
+
+  result.setTo(initial_value)
+
+proc myfunc(x, y: int): (MySeqNonCopyable, MySeqNonCopyable) =
+  result = (newMySeq(x, 1.0), newMySeq(y, 5.0))
+
+proc myfunc2(x, y: int): tuple[a: MySeqNonCopyable, b:int, c:MySeqNonCopyable] =
+  var cc = newMySeq(y, 5.0)
+  (a: case x:
+    of 1:
+      let (z1, z2) = myfunc(x, y)
+      z2
+    elif x > 5: raise newException(ValueError, "new error")
+    else: newMySeq(x, 1.0),
+   b: 0,
+   c: block:
+        var tmp = if y > 0: move(cc) else: newMySeq(1, 3.0)
+        tmp[0] = 5
+        tmp
+  )
+
+
+let (seq1, seq2) = myfunc(2, 3)
+doAssert seq1.len == 2
+doAssert seq1[0] == 1.0
+doAssert seq2.len == 3
+doAssert seq2[0] == 5.0
+
+var (seq3, i, _) = myfunc2(2, 3)
+doAssert seq3.len == 2
+doAssert seq3[0] == 1.0
+
+var seq4, seq5: MySeqNonCopyable
+(seq4, i, seq5) = myfunc2(2, 3)
+
+proc foo =
+  seq4 = block:
+    var tmp = newMySeq(4, 1.0)
+    tmp[0] = 3.0
+    tmp
+
+  doAssert seq4[0] == 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
+
+foo()
+
+#------------------------------------------------------------
+#-- Move into array constructor
+#------------------------------------------------------------
+
+var ii = 1
+let arr2 = [newMySeq(2, 5.0), if i > 1: newMySeq(3, 1.0) else: newMySeq(0, 0.0)]
+var seqOfSeq2 = @[newMySeq(2, 5.0), newMySeq(3, 1.0)]
+
+
+## issue #10462
+proc myfuncLoop(x: int): MySeqNonCopyable =
+  for i in 0..<x:
+    var cc = newMySeq(i, 5.0)
+    result = cc
+
+discard myfuncLoop(3)
+
+#------------------------------------------------------------
+# Move into table via openArray
+#------------------------------------------------------------
+
+type
+  TableNonCopyable = object
+    x: seq[(string, MySeqNonCopyable)]
+
+proc toTable(pairs: sink openArray[(string, MySeqNonCopyable)]): TableNonCopyable =
+  discard
+
+
+let mytable = {"a": newMySeq(2, 5.0)}.toTable
+
diff --git a/tests/destructor/tnewruntime_misc.nim b/tests/destructor/tnewruntime_misc.nim
new file mode 100644
index 000000000..21c70557d
--- /dev/null
+++ b/tests/destructor/tnewruntime_misc.nim
@@ -0,0 +1,155 @@
+discard """
+  cmd: '''nim cpp -d:nimAllocStats --newruntime --threads:on $file'''
+  output: '''(field: "value")
+Indeed
+axc
+(v: 10)
+...
+destroying GenericObj[T] GenericObj[system.int]
+test
+(allocCount: 12, deallocCount: 10)
+3'''
+"""
+
+import system / ansi_c
+
+import tables
+
+type
+  Node = ref object
+    field: string
+
+# bug #11807
+import os
+putEnv("HEAPTRASHING", "Indeed")
+
+let s1 = getAllocStats()
+
+
+proc newTableOwned[A, B](initialSize = defaultInitialSize): owned(TableRef[A, B]) =
+  new(result)
+  result[] = initTable[A, B](initialSize)
+
+proc main =
+  var w = newTableOwned[string, owned Node]()
+  w["key"] = Node(field: "value")
+  echo w["key"][]
+  echo getEnv("HEAPTRASHING")
+
+  # bug #11891
+  var x = "abc"
+  x[1] = 'x'
+  echo x
+
+main()
+
+# bug #11745
+
+type
+  Foo = object
+    bar: seq[int]
+
+var x = [Foo()]
+
+# bug #11563
+type
+  MyTypeType = enum
+    Zero, One
+  MyType = object
+    case kind: MyTypeType
+    of Zero:
+      s*: seq[MyType]
+    of One:
+      x*: int
+var t: MyType
+
+# bug #11254
+proc test(p: owned proc()) =
+  let x = (proc())p
+
+test(proc() = discard)
+
+# bug #10689
+
+type
+  O = object
+    v: int
+
+proc `=sink`(d: var O, s: O) =
+  d.v = s.v
+
+proc selfAssign =
+  var o = O(v: 10)
+  o = o
+  echo o
+
+selfAssign()
+
+# bug #11833
+type FooAt = object
+
+proc testWrongAt() =
+  var x = @[@[FooAt()]]
+
+testWrongAt()
+
+#-------------------------------------------------
+type
+  Table[A, B] = object
+    x: seq[(A, B)]
+
+
+proc toTable[A,B](p: sink openArray[(A, B)]): Table[A, B] =
+  for zz in mitems(p):
+    result.x.add move(zz)
+
+
+let table = {"a": new(int)}.toTable()
+
+# bug # #12051
+
+type
+  GenericObj[T] = object
+    val: T
+  Generic[T] = owned ref GenericObj[T]
+
+proc `=destroy`[T](x: var GenericObj[T]) =
+  echo "destroying GenericObj[T] ", x.typeof # to know when its being destroyed
+
+proc main12() =
+  let gnrc = Generic[int](val: 42)
+  echo "..."
+
+main12()
+
+#####################################################################
+## bug #12827
+type
+  MyObject = object
+    x: string
+    y: seq[string]
+    needs_ref: ref int
+
+proc xx(xml: string): MyObject =
+  let stream = xml
+  result.x  = xml
+  defer: echo stream
+
+
+discard xx("test")
+
+# Windows has 1 extra allocation in `getEnv` - there it allocates parameter to
+# `_wgetenv` (WideCString). Therefore subtract by 1 to match other OSes'
+# allocation.
+when defined(windows):
+  import std/importutils
+  privateAccess(AllocStats)
+  echo getAllocStats() - s1 - AllocStats(allocCount: 1, deallocCount: 1)
+else:
+  echo getAllocStats() - s1
+
+# bug #13457
+var s = "abcde"
+s.setLen(3)
+
+echo s.cstring.len
diff --git a/tests/destructor/tnewruntime_strutils.nim b/tests/destructor/tnewruntime_strutils.nim
new file mode 100644
index 000000000..9c8d41973
--- /dev/null
+++ b/tests/destructor/tnewruntime_strutils.nim
@@ -0,0 +1,254 @@
+discard """
+  valgrind: true
+  cmd: '''nim c -d:nimAllocStats --gc:arc -d:useMalloc $file'''
+  output: '''
+@[(input: @["KXSC", "BGMC"]), (input: @["PXFX"]), (input: @["WXRQ", "ZSCZD"])]
+14
+First tasks completed.
+Second tasks completed.
+test1'''
+"""
+
+import strutils, os, std / wordwrap
+
+import system / ansi_c
+
+# bug #11004
+proc retTuple(): (seq[int], int) =
+  return (@[1], 1)
+
+# bug #12899
+
+import sequtils, strmisc
+
+const input = ["KXSC, BGMC => 7 PTHL", "PXFX => LBZJ", "WXRQ, ZSCZD => HLQM"]
+
+type
+  Reaction = object
+    input: seq[string]
+
+proc bug12899 =
+  var reactions: seq[Reaction] = @[]
+  for l in input:
+    let x = l.partition(" => ")
+    reactions.add Reaction(input: @(x[0].split(", ")))
+
+  let x = $reactions
+  echo x
+
+bug12899()
+
+
+proc nonStaticTests =
+  doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
+  doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586
+  doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
+  doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
+  doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
+                                                    ["1,0e-11", "1,0e-011"]
+
+  doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
+  doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
+
+  block: # formatSize tests
+    when not defined(js):
+      doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB"   # <=== bug #8231
+    doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
+    doAssert formatSize(4096) == "4KiB"
+    doAssert formatSize(4096, prefix=bpColloquial, includeSpace=true) == "4 kB"
+    doAssert formatSize(4096, includeSpace=true) == "4 KiB"
+    doAssert formatSize(5_378_934, prefix=bpColloquial, decimalSep=',') == "5,13MB"
+
+  block: # formatEng tests
+    doAssert formatEng(0, 2, trim=false) == "0.00"
+    doAssert formatEng(0, 2) == "0"
+    doAssert formatEng(53, 2, trim=false) == "53.00"
+    doAssert formatEng(0.053, 2, trim=false) == "53.00e-3"
+    doAssert formatEng(0.053, 4, trim=false) == "53.0000e-3"
+    doAssert formatEng(0.053, 4, trim=true) == "53e-3"
+    doAssert formatEng(0.053, 0) == "53e-3"
+    doAssert formatEng(52731234) == "52.731234e6"
+    doAssert formatEng(-52731234) == "-52.731234e6"
+    doAssert formatEng(52731234, 1) == "52.7e6"
+    doAssert formatEng(-52731234, 1) == "-52.7e6"
+    doAssert formatEng(52731234, 1, decimalSep=',') == "52,7e6"
+    doAssert formatEng(-52731234, 1, decimalSep=',') == "-52,7e6"
+
+    doAssert formatEng(4100, siPrefix=true, unit="V") == "4.1 kV"
+    doAssert formatEng(4.1, siPrefix=true, unit="V", useUnitSpace=true) == "4.1 V"
+    doAssert formatEng(4.1, siPrefix=true) == "4.1" # Note lack of space
+    doAssert formatEng(4100, siPrefix=true) == "4.1 k"
+    doAssert formatEng(4.1, siPrefix=true, unit="", useUnitSpace=true) == "4.1 " # Includes space
+    doAssert formatEng(4100, siPrefix=true, unit="") == "4.1 k"
+    doAssert formatEng(4100) == "4.1e3"
+    doAssert formatEng(4100, unit="V", useUnitSpace=true) == "4.1e3 V"
+    doAssert formatEng(4100, unit="", useUnitSpace=true) == "4.1e3 "
+    # Don't use SI prefix as number is too big
+    doAssert formatEng(3.1e22, siPrefix=true, unit="a", useUnitSpace=true) == "31e21 a"
+    # Don't use SI prefix as number is too small
+    doAssert formatEng(3.1e-25, siPrefix=true, unit="A", useUnitSpace=true) == "310e-27 A"
+
+proc staticTests =
+  doAssert align("abc", 4) == " abc"
+  doAssert align("a", 0) == "a"
+  doAssert align("1232", 6) == "  1232"
+  doAssert align("1232", 6, '#') == "##1232"
+
+  doAssert alignLeft("abc", 4) == "abc "
+  doAssert alignLeft("a", 0) == "a"
+  doAssert alignLeft("1232", 6) == "1232  "
+  doAssert alignLeft("1232", 6, '#') == "1232##"
+
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+                it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  doAssert wrapWords(inp, 10, false) == outp
+
+  let
+    longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
+    longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
+  doAssert wrapWords(longInp, 8, true) == longOutp
+
+  doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
+            "The cat eats fish."
+
+  doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
+  doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
+
+  doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
+  doAssert "oo".replace("", "abc") == "oo"
+
+  type MyEnum = enum enA, enB, enC, enuD, enE
+  doAssert parseEnum[MyEnum]("enu_D") == enuD
+
+  doAssert parseEnum("invalid enum value", enC) == enC
+
+  doAssert center("foo", 13) == "     foo     "
+  doAssert center("foo", 0) == "foo"
+  doAssert center("foo", 3, fillChar = 'a') == "foo"
+  doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
+
+  doAssert count("foofoofoo", "foofoo") == 1
+  doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
+  doAssert count("foofoofoo", 'f') == 3
+  doAssert count("foofoofoobar", {'f','b'}) == 4
+
+  doAssert strip("  foofoofoo  ") == "foofoofoo"
+  doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+  doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+  doAssert strip("stripme but don't strip this stripme",
+                  chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
+                  " but don't strip this "
+  doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+  doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
+
+  doAssert "  foo\n  bar".indent(4, "Q") == "QQQQ  foo\nQQQQ  bar"
+
+  doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
+  doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.", "PEOPLE!")) == "HELLO PEOPLE!"
+  doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
+
+  doAssert rsplit("foo bar", seps=Whitespace) == @["foo", "bar"]
+  doAssert rsplit(" foo bar", seps=Whitespace, maxsplit=1) == @[" foo", "bar"]
+  doAssert rsplit(" foo bar ", seps=Whitespace, maxsplit=1) == @[" foo bar", ""]
+  doAssert rsplit(":foo:bar", sep=':') == @["", "foo", "bar"]
+  doAssert rsplit(":foo:bar", sep=':', maxsplit=2) == @["", "foo", "bar"]
+  doAssert rsplit(":foo:bar", sep=':', maxsplit=3) == @["", "foo", "bar"]
+  doAssert rsplit("foothebar", sep="the") == @["foo", "bar"]
+
+  doAssert(unescape(r"\x013", "", "") == "\x013")
+
+  doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
+  doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
+  doAssert join([1, 2, 3]) == "123"
+  doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
+
+  doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
+
+  doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
+  doAssert """~~foo
+~~  bar
+~~  baz""".unindent(4, "~") == "foo\n  bar\n  baz"
+  doAssert """foo
+  bar
+    baz
+  """.unindent(4) == "foo\nbar\nbaz\n"
+  doAssert """foo
+    bar
+    baz
+  """.unindent(2) == "foo\n  bar\n  baz\n"
+  doAssert """foo
+      bar
+      baz
+    """.unindent(100) == "foo\nbar\nbaz\n"
+
+  doAssert """foo
+      foo
+      bar
+    """.unindent() == "foo\nfoo\nbar\n"
+
+  let s = " this is an example  "
+  let s2 = ":this;is;an:example;;"
+
+  doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
+  doAssert s2.split(seps={':', ';'}) == @["", "this", "is", "an", "example", "", ""]
+  doAssert s.split(maxsplit=4) == @["", "this", "is", "an", "example  "]
+  doAssert s.split(' ', maxsplit=1) == @["", "this is an example  "]
+  doAssert s.split(" ", maxsplit=4) == @["", "this", "is", "an", "example  "]
+
+  doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
+  doAssert s.splitWhitespace(maxsplit=1) == @["this", "is an example  "]
+  doAssert s.splitWhitespace(maxsplit=2) == @["this", "is", "an example  "]
+  doAssert s.splitWhitespace(maxsplit=3) == @["this", "is", "an", "example  "]
+  doAssert s.splitWhitespace(maxsplit=4) == @["this", "is", "an", "example"]
+
+  discard retTuple()
+
+nonStaticTests()
+staticTests()
+
+# bug #12965
+let xaa = @[""].join()
+let xbb = @["", ""].join()
+
+# bug #16365
+
+# Task 1:
+when true:
+  # Task 1_a:
+  var test_string_a = "name_something"
+  echo test_string_a.len()
+  let new_len_a = test_string_a.len - "_something".len()
+  test_string_a.setLen new_len_a
+
+  echo "First tasks completed."
+
+# Task 2:
+when true:
+  # Task 2_a
+  var test_string: string
+  let some_string = "something"
+  for i in some_string.items:
+    test_string.add $i
+
+  # Task 2_b
+  var test_string_b = "name_something"
+  let new_len_b = test_string_b.len - "_something".len()
+  test_string_b.setLen new_len_b
+
+  echo "Second tasks completed."
+
+# bug #17450
+proc main =
+  var i = 1
+  echo:
+    block:
+      "test" & $i
+
+main()
+
diff --git a/tests/destructor/tnonvardestructor.nim b/tests/destructor/tnonvardestructor.nim
new file mode 100644
index 000000000..1b4413790
--- /dev/null
+++ b/tests/destructor/tnonvardestructor.nim
@@ -0,0 +1,247 @@
+discard """

+  targets: "c cpp"

+  matrix: "--mm:arc; --mm:orc"

+"""

+

+block:

+  type

+    PublicKey = array[32, uint8]

+    PrivateKey = array[64, uint8]

+

+  proc ed25519_create_keypair(publicKey: ptr PublicKey; privateKey: ptr PrivateKey) =

+    publicKey[][0] = uint8(88)

+

+  type

+    KeyPair = object

+      public: PublicKey

+      private: PrivateKey

+

+  proc initKeyPair(): KeyPair =

+    ed25519_create_keypair(result.public.addr, result.private.addr)

+

+  let keys = initKeyPair()

+  doAssert keys.public[0] == 88

+

+

+template minIndexByIt: untyped =

+  var other = 3

+  other

+

+proc bug20303() =

+  var hlibs = @["hello", "world", "how", "are", "you"]

+  let res = hlibs[minIndexByIt()]

+  doAssert res == "are"

+

+bug20303()

+

+proc main() = # todo bug with templates

+  block: # bug #11267

+    var a: seq[char] = block: @[]

+    doAssert a == @[]

+    # 2

+    proc b: seq[string] =

+      discard

+      @[]

+    doAssert b() == @[]

+static: main()

+main()

+

+

+type Obj = tuple

+  value: int

+  arr: seq[int]

+

+proc bug(): seq[Obj] =

+  result.add (value: 0, arr: @[])

+  result[^1].value = 1

+  result[^1].arr.add 1

+

+# bug #19990

+let s = bug()

+doAssert s[0] == (value: 1, arr: @[1])

+

+block: # bug #21974

+  type Test[T] = ref object

+      values : seq[T]

+      counter: int

+

+  proc newTest[T](): Test[T] =

+      result         = new(Test[T])

+      result.values  = newSeq[T](16)

+      result.counter = 0

+

+  proc push[T](self: Test[T], value: T) =

+      self.counter += 1

+      if self.counter >= self.values.len:

+          self.values.setLen(self.values.len * 2)

+      self.values[self.counter - 1] = value

+

+  proc pop[T](self: Test[T]): T =

+      result         = self.values[0]

+      self.values[0] = self.values[self.counter - 1] # <--- This line

+      self.counter  -= 1

+

+

+  type X = tuple

+      priority: int

+      value   : string

+

+  var a = newTest[X]()

+  a.push((1, "One"))

+  doAssert a.pop.value == "One"

+

+# bug #21987

+

+type

+  EmbeddedImage* = distinct Image

+  Image = object

+    len: int

+

+proc imageCopy*(image: Image): Image {.nodestroy.}

+

+proc `=destroy`*(x: Image) =

+  discard

+

+proc `=sink`*(dest: var Image; source: Image) =

+  `=destroy`(dest)

+  wasMoved(dest)

+

+proc `=dup`*(source: Image): Image {.nodestroy.} =

+  result = imageCopy(source)

+

+proc `=copy`*(dest: var Image; source: Image) =

+  dest = imageCopy(source) # calls =sink implicitly

+

+proc `=destroy`*(x: EmbeddedImage) = discard

+

+proc `=dup`*(source: EmbeddedImage): EmbeddedImage {.nodestroy.} = source

+

+proc `=copy`*(dest: var EmbeddedImage; source: EmbeddedImage) {.nodestroy.} =

+  dest = source

+

+proc imageCopy*(image: Image): Image =

+  result = image

+

+proc main2 =

+  block:

+    var a = Image(len: 2).EmbeddedImage

+    var b = Image(len: 1).EmbeddedImage

+    b = a

+    doAssert Image(a).len == 2

+    doAssert Image(b).len == 2

+

+  block:

+    var a = Image(len: 2)

+    var b = Image(len: 1)

+    b = a

+    doAssert a.len == 2

+    doAssert b.len == 0

+

+main2()

+

+type

+  Edge = object

+    neighbor {.cursor.}: Node

+

+  NodeObj = object

+    neighbors: seq[Edge]

+    label: string

+    visited: bool

+  Node = ref NodeObj

+

+  Graph = object

+    nodes: seq[Node]

+

+proc `=destroy`(x: NodeObj) =

+  `=destroy`(x.neighbors)

+  `=destroy`(x.label)

+

+proc addNode(self: var Graph; label: string): Node =

+  self.nodes.add(Node(label: label))

+  result = self.nodes[^1]

+

+proc addEdge(self: Graph; source, neighbor: Node) =

+  source.neighbors.add(Edge(neighbor: neighbor))

+

+block:

+  proc main =

+    var graph: Graph

+    let nodeA = graph.addNode("a")

+    let nodeB = graph.addNode("b")

+    let nodeC = graph.addNode("c")

+

+    graph.addEdge(nodeA, neighbor = nodeB)

+    graph.addEdge(nodeA, neighbor = nodeC)

+

+  main()

+

+block:

+  type RefObj = ref object

+

+  proc `[]`(val: static[int]) = # works with different name/overload or without static arg

+    discard

+

+  template noRef(T: typedesc): typedesc = # works without template indirection

+    typeof(default(T)[])

+

+  proc `=destroy`(x: noRef(RefObj)) =

+    discard

+

+  proc foo =

+    var x = new RefObj

+    doAssert $(x[]) == "()"

+

+  # bug #11705

+  foo()

+

+block: # bug #22197

+  type

+    H5IdObj = object

+    H5Id = ref H5IdObj

+

+    FileID = distinct H5Id

+

+    H5GroupObj = object

+      file_id: FileID

+    H5Group = ref H5GroupObj

+

+  ## This would make it work!

+  #proc `=destroy`*(x: FileID) = `=destroy`(cast[H5Id](x))

+  ## If this does not exist, it also works!

+  proc newFileID(): FileID = FileID(H5Id())

+

+  proc `=destroy`(grp: H5GroupObj) =

+    ## Closes the group and resets all references to nil.

+    if cast[pointer](grp.fileId) != nil:

+      `=destroy`(grp.file_id)

+

+  var grp = H5Group()

+  reset(grp.file_id)

+  reset(grp)

+

+import std/tables

+

+block: # bug #22286

+  type

+    A = object

+    B = object

+      a: A

+    C = object

+      b: B

+

+  proc `=destroy`(self: A) =

+    echo "destroyed"

+

+  proc `=destroy`(self: C) =

+    `=destroy`(self.b)

+

+  var c = C()

+

+block: # https://forum.nim-lang.org/t/10642

+  type AObj = object

+    name: string

+    tableField: Table[string, string]

+

+  proc `=destroy`(x: AObj) =

+    `=destroy`(x.name)

+    `=destroy`(x.tableField)

diff --git a/tests/destructor/tobjfield_analysis.nim b/tests/destructor/tobjfield_analysis.nim
new file mode 100644
index 000000000..83f394c3b
--- /dev/null
+++ b/tests/destructor/tobjfield_analysis.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''works'''
+"""
+
+#  bug #11095
+
+type
+  MyVal[T] = object
+    f: ptr T
+
+proc `=destroy`[T](x: var MyVal[T]) =
+  if x.f != nil:
+    dealloc(x.f)
+
+proc `=sink`[T](x1: var MyVal[T], x2: MyVal[T]) =
+  if x1.f != x2.f:
+    `=destroy`(x1)
+    x1.f = x2.f
+
+proc `=`[T](x1: var MyVal[T], x2: MyVal[T]) {.error.}
+
+proc newVal[T](x: sink T): MyVal[T] =
+  result.f = create(T)
+  result.f[] = x
+
+proc set[T](x: var MyVal[T], val: T) =
+  x.f[] = val
+
+proc sinkMe[T](x: sink MyVal[T]) =
+  discard
+
+var flag = false
+
+proc main =
+  var y = case flag
+    of true:
+      var x1 = newVal[float](1.0)
+      var x2 = newVal[float](2.0)
+      (newVal(x1), newVal(x2))
+
+    of false:
+      var x1 = newVal[float](1.0)
+      var x2 = newVal[float](2.0)
+      (newVal(x1), newVal(x2))
+
+  sinkMe y[0]
+  sinkMe y[1]
+  echo "works"
+
+main()
+
diff --git a/tests/destructor/topt.nim b/tests/destructor/topt.nim
new file mode 100644
index 000000000..4adda1914
--- /dev/null
+++ b/tests/destructor/topt.nim
@@ -0,0 +1,61 @@
+
+discard """
+  output: '''5
+vseq destroy
+'''
+joinable: false
+"""
+type
+  opt*[T] = object
+    case exists: bool
+      of true: val: T
+      of false: discard
+
+proc some*[T](val: sink T): opt[T] {.inline.} =
+  ## Returns an ``opt`` that has the value.
+  ## nil is considered as none for reference types
+  result = opt[T](exists: true, val: val)
+
+proc none*(T: typedesc): opt[T] {.inline.} =
+  ## Returns an ``opt`` for this type that has no value.
+  # the default is the none type
+  discard
+
+proc none*[T]: opt[T] {.inline.} =
+  ## Alias for ``none(T)``.
+  none(T)
+
+proc unsafeGet*[T](self: opt[T]): lent T {.inline.} =
+  ## Returns the value of a ``some``. Behavior is undefined for ``none``.
+  self.val
+
+type
+  VSeq*[T] = object
+    len: int
+    data: ptr UncheckedArray[T]
+
+proc `=destroy`*[T](m: var VSeq[T]) {.inline.} =
+  if m.data != nil:
+    echo "vseq destroy"
+    dealloc(m.data)
+    m.data = nil
+
+proc `=`*[T](m: var VSeq[T], m2: VSeq[T]) {.error.}
+
+proc `=sink`*[T](m: var VSeq[T], m2: VSeq[T]) {.inline.} =
+  if m.data != m2.data:
+    `=destroy`(m)
+  m.len = m2.len
+  m.data = m2.data
+
+proc newVSeq*[T](len: int): VSeq[T] =
+  ## Only support sequence creation from scalar size because creation from
+  ## vetorized size can't reproduce the original scalar size
+  result.len = len
+  if len > 0:
+    result.data = cast[ptr UncheckedArray[T]](alloc(sizeof(T) * len))
+
+let x = some newVSeq[float](5)
+echo x.unsafeGet.len
+let y = none(VSeq[float])
+
diff --git a/tests/destructor/topttree.nim b/tests/destructor/topttree.nim
new file mode 100644
index 000000000..8cf757e8b
--- /dev/null
+++ b/tests/destructor/topttree.nim
@@ -0,0 +1,109 @@
+discard """
+  disabled: i386
+  output: '''10.0
+60.0
+90.0
+120.0
+10.0
+60.0
+90.0
+120.0
+8 8'''
+joinable: false
+"""
+
+import typetraits
+
+type
+  opt[T] = object
+    data: ptr T
+
+var
+  allocCount, deallocCount: int
+
+proc `=destroy`*[T](x: var opt[T]) =
+  if x.data != nil:
+    mixin `=destroy`
+    when not supportsCopyMem(T):
+      `=destroy`(x.data[])
+    dealloc(x.data)
+    inc deallocCount
+    x.data = nil
+
+proc `=`*[T](a: var opt[T]; b: opt[T]) =
+  if a.data == b.data: return
+  if a.data != nil:
+    dealloc(a.data)
+    inc deallocCount
+    a.data = nil
+  if b.data != nil:
+    a.data = cast[type(a.data)](alloc(sizeof(T)))
+    inc allocCount
+    when supportsCopyMem(T):
+      copyMem(a.data, b.data, sizeof(T))
+    else:
+      a.data[] = b.data[]
+
+proc `=sink`*[T](a: var opt[T]; b: opt[T]) =
+  if a.data != nil and a.data != b.data:
+    dealloc(a.data)
+    inc deallocCount
+  a.data = b.data
+
+proc createOpt*[T](x: T): opt[T] =
+  result.data = cast[type(result.data)](alloc(sizeof(T)))
+  inc allocCount
+  result.data[] = x
+
+template `[]`[T](x: opt[T]): T =
+  assert x.p != nil, "attempt to read from moved/destroyed value"
+  x.p[]
+
+template `?=`[T](it: untyped; x: opt[T]): bool =
+  template it: untyped {.inject.} = x.data[]
+  if x.data != nil:
+    true
+  else:
+    false
+
+type
+  Tree = object
+    data: float
+    le, ri: opt[Tree]
+
+proc createTree(data: float): Tree =
+  result.data = data
+
+proc insert(t: var opt[Tree]; newVal: float) =
+  #if it ?= t:
+  if t.data != nil:
+    if newVal < t.data[].data:
+      insert(t.data[].le, newVal)
+    elif t.data[].data < newVal:
+      insert(t.data[].ri, newVal)
+    else:
+      discard "already in the tree"
+  else:
+    t = createOpt(Tree(data: newVal))
+
+proc write(t: opt[Tree]) =
+  if it ?= t:
+    write(it.le)
+    write stdout, it.data, "\n"
+    write(it.ri)
+
+proc use(t: opt[Tree]) = discard
+
+proc main =
+  var t: opt[Tree]
+  insert t, 60.0
+  insert t, 90.0
+  insert t, 10.0
+  insert t, 120.0
+  write t
+  let copy = t
+  write copy
+  use t
+
+main()
+echo allocCount, " ", deallocCount
diff --git a/tests/destructor/towned_binary_tree.nim b/tests/destructor/towned_binary_tree.nim
new file mode 100644
index 000000000..fb635e7c6
--- /dev/null
+++ b/tests/destructor/towned_binary_tree.nim
@@ -0,0 +1,91 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
+  output: '''31665
+(allocCount: 33334, deallocCount: 33334)'''
+"""
+
+#  bug #11053
+
+import random
+
+type Node = ref object
+  x, y: int32
+  left, right: owned Node
+
+proc newNode(x: int32): owned Node =
+  result = Node(x: x, y: rand(high int32).int32)
+
+proc merge(lower, greater: owned Node): owned Node =
+  if lower.isNil:
+    result = greater
+  elif greater.isNil:
+    result = lower
+  elif lower.y < greater.y:
+    lower.right = merge(lower.right, greater)
+    result = lower
+  else:
+    greater.left = merge(lower, greater.left)
+    result = greater
+
+proc splitBinary(orig: owned Node, value: int32): (owned Node, owned Node) =
+  if orig.isNil:
+    result = (nil, nil)
+  elif orig.x < value:
+    let splitPair = splitBinary(orig.right, value)
+    orig.right = splitPair[0]
+    result = (orig, splitPair[1])
+  else:
+    let splitPair = splitBinary(orig.left, value)
+    orig.left = splitPair[1]
+    result = (splitPair[0], orig)
+
+proc merge3(lower, equal, greater: owned Node): owned Node =
+  merge(merge(lower, equal), greater)
+
+proc split(orig: owned Node, value: int32): tuple[lower, equal, greater: owned Node] =
+  let
+    (lower, equalGreater) = splitBinary(orig, value)
+    (equal, greater) = splitBinary(equalGreater, value + 1)
+  result = (lower, equal, greater)
+
+type Tree = object
+  root: owned Node
+
+proc hasValue(self: var Tree, x: int32): bool =
+  let splited = split(move self.root, x)
+  result = not splited.equal.isNil
+  self.root = merge3(splited.lower, splited.equal, splited.greater)
+
+proc insert(self: var Tree, x: int32) =
+  var splited = split(move self.root, x)
+  if splited.equal.isNil:
+    splited.equal = newNode(x)
+  self.root = merge3(splited.lower, splited.equal, splited.greater)
+
+proc erase(self: var Tree, x: int32) =
+  let splited = split(move self.root, x)
+  self.root = merge(splited.lower, splited.greater)
+
+proc main() =
+  var
+    tree = Tree()
+    cur = 5'i32
+    res = 0
+
+  for i in 1 ..< 100000:
+    let a = i mod 3
+    cur = (cur * 57 + 43) mod 10007
+    case a:
+    of 0:
+      tree.insert(cur)
+    of 1:
+      tree.erase(cur)
+    of 2:
+      if tree.hasValue(cur):
+        res += 1
+    else:
+      discard
+  echo res
+
+dumpAllocStats:
+  main()
diff --git a/tests/destructor/tprevent_assign.nim b/tests/destructor/tprevent_assign.nim
new file mode 100644
index 000000000..4c484ebc1
--- /dev/null
+++ b/tests/destructor/tprevent_assign.nim
@@ -0,0 +1,33 @@
+discard """
+  errormsg: "'=copy' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
+  line: 29
+"""
+
+type
+  Foo = object
+    x: int
+
+proc `=destroy`(f: var Foo) = f.x = 0
+proc `=`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
+
+proc createTree(x: int): Foo =
+  Foo(x: x)
+
+proc take2(a, b: sink Foo) =
+  echo a.x, " ", b.x
+
+proc allowThis() =
+  # all these temporary lets are harmless:
+  let otherTree = createTree(44)
+  let b = otherTree
+  let c = b
+  take2(createTree(34), c)
+
+proc preventThis() =
+  let otherTree = createTree(44)
+  let b = otherTree
+  take2(createTree(34), otherTree)
+
+allowThis()
+preventThis()
diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim
new file mode 100644
index 000000000..eb5588b1a
--- /dev/null
+++ b/tests/destructor/tprevent_assign2.nim
@@ -0,0 +1,56 @@
+discard """
+  errormsg: "'=dup' is not available for type <Foo>, which is inferred from unavailable '=copy'; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(51, 31); routine: preventThis"
+  file: "tprevent_assign2.nim"
+  line: 49
+"""
+
+type
+  Foo = object
+    x: int
+
+proc `=destroy`(f: var Foo) = f.x = 0
+proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+
+proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
+
+proc createTree(x: int): Foo =
+  Foo(x: x)
+
+proc take2(a, b: sink Foo) =
+  echo a.x, " ", b.x
+
+when false:
+  var otherTree: Foo
+  try:
+    for i in 0..3:
+      while true:
+        #if i == 0:
+        otherTree = createTree(44)
+        case i
+        of 0:
+          echo otherTree
+          take2(createTree(34), otherTree)
+        of 1:
+          take2(createTree(34), otherTree)
+        else:
+          discard
+  finally:
+    discard
+
+proc preventThis() =
+  var otherTree: Foo
+  for i in 0..3:
+    while true:
+      if i == 0:
+        otherTree = createTree(44)
+      case i
+      of 0:
+        echo otherTree
+        take2(createTree(34), otherTree)
+      of 1:
+        take2(createTree(34), otherTree)
+      else:
+        discard
+
+#allowThis()
+preventThis()
diff --git a/tests/destructor/tprevent_assign3.nim b/tests/destructor/tprevent_assign3.nim
new file mode 100644
index 000000000..aa834a66c
--- /dev/null
+++ b/tests/destructor/tprevent_assign3.nim
@@ -0,0 +1,54 @@
+discard """
+  errormsg: "'=dup' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
+  file: "tprevent_assign3.nim"
+  line: 47
+"""
+
+type
+  Foo = object
+    x: int
+
+proc `=destroy`(f: var Foo) = f.x = 0
+proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
+proc `=dup`(a: Foo): Foo {.error.}
+proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
+
+proc createTree(x: int): Foo =
+  Foo(x: x)
+
+proc take2(a, b: sink Foo) =
+  echo a.x, " ", b.x
+
+when false:
+  var otherTree: Foo
+  try:
+    for i in 0..3:
+      while true:
+        #if i == 0:
+        otherTree = createTree(44)
+        case i
+        of 0:
+          echo otherTree
+          take2(createTree(34), otherTree)
+        of 1:
+          take2(createTree(34), otherTree)
+        else:
+          discard
+  finally:
+    discard
+
+proc preventThis2() =
+  var otherTree: Foo
+  try:
+    try:
+      otherTree = createTree(44)
+      echo otherTree
+    finally:
+      take2(createTree(34), otherTree)
+  finally:
+    echo otherTree
+
+#allowThis()
+preventThis2()
+
+
diff --git a/tests/destructor/trecursive.nim b/tests/destructor/trecursive.nim
new file mode 100644
index 000000000..e7afa6ba9
--- /dev/null
+++ b/tests/destructor/trecursive.nim
@@ -0,0 +1,60 @@
+
+discard """
+   output: '''
+test1 OK
+'''
+"""
+
+import smart_ptr
+
+type
+  Node[T] = object
+    value: T
+    next: SharedPtr[Node[T]]
+
+  ForwardList[T] = object
+    first: SharedPtr[Node[T]]
+    len: Natural
+
+proc pushFront*[T] (list: var ForwardList[T], val: sink T) =
+  var newNode = newSharedPtr(Node[T](value: val))
+  var result = false
+  while not result:
+    var head = list.first
+    newNode.get.next = head
+    result = list.first.cas(head, newNode)
+  list.len.atomicInc()
+
+proc test1() =
+  var list: ForwardList[int]
+  list.pushFront(1)
+  doAssert list.len == 1
+  echo "test1 OK"
+
+test1()
+
+#------------------------------------------------------------------------------
+# issue #14217
+
+type
+  MyObject = object
+    p: ptr int
+
+proc `=destroy`(x: var MyObject) =
+  if x.p != nil:
+    deallocShared(x.p)
+
+proc `=`(x: var MyObject, y: MyObject) {.error.}
+
+proc newMyObject(i: int): MyObject = 
+  result.p = createShared(int)
+  result.p[] = i
+
+proc test: seq[MyObject] = 
+  for i in 0..3:
+    let x = newMyObject(i)
+    result.add x
+
+var x = test()
+for i in 0..3:
+  doAssert(x[i].p[] == i)
diff --git a/tests/destructor/tselect.nim b/tests/destructor/tselect.nim
new file mode 100644
index 000000000..c22bf7203
--- /dev/null
+++ b/tests/destructor/tselect.nim
@@ -0,0 +1,50 @@
+discard """
+   output: '''abcsuffix
+xyzsuffix
+destroy foo 2
+destroy foo 1
+'''
+  cmd: '''nim c --gc:arc $file'''
+"""
+
+proc select(cond: bool; a, b: sink string): string =
+  if cond:
+    result = a # moves a into result
+  else:
+    result = b # moves b into result
+
+proc test(param: string; cond: bool) =
+  var x = "abc" & param
+  var y = "xyz" & param
+
+  # possible self-assignment:
+  x = select(cond, x, y)
+
+  echo x
+  # 'select' must communicate what parameter has been
+  # consumed. We cannot simply generate:
+  # (select(...); wasMoved(x); wasMoved(y))
+
+test("suffix", true)
+test("suffix", false)
+
+
+
+#--------------------------------------------------------------------
+# issue #13659
+
+type
+  Foo = ref object
+    data: int
+    parent: Foo
+
+proc `=destroy`(self: var type(Foo()[])) =
+  echo "destroy foo ", self.data
+  for i in self.fields: i.reset
+
+proc getParent(self: Foo): Foo = self.parent
+
+var foo1 = Foo(data: 1)
+var foo2 = Foo(data: 2, parent: foo1)
+
+foo2.getParent.data = 1
\ No newline at end of file
diff --git a/tests/destructor/tsetjmp_raise.nim b/tests/destructor/tsetjmp_raise.nim
new file mode 100644
index 000000000..3a9803f39
--- /dev/null
+++ b/tests/destructor/tsetjmp_raise.nim
@@ -0,0 +1,11 @@
+discard """
+  outputsub: "index 2 not in 0 .. 0 [IndexDefect]"
+  exitcode: 1
+  cmd: "nim c --gc:arc --exceptions:setjmp $file"
+"""
+
+# bug #12961
+# --gc:arc --exceptions:setjmp
+let a = @[1]
+echo a[2]
+
diff --git a/tests/destructor/tsimpleclosure.nim b/tests/destructor/tsimpleclosure.nim
new file mode 100644
index 000000000..9626dd6f8
--- /dev/null
+++ b/tests/destructor/tsimpleclosure.nim
@@ -0,0 +1,62 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --gc:arc $file'''
+  output: '''a b
+70
+hello
+hello
+hello
+(allocCount: 3, deallocCount: 3)'''
+"""
+
+import system / ansi_c
+
+proc main(): owned(proc()) =
+  var a = "a"
+  var b = "b"
+  result = proc() =
+    echo a, " ", b
+
+
+proc foo(f: (iterator(): int)) =
+  for i in f(): echo i
+
+proc wrap =
+  let p = main()
+  p()
+
+  let fIt = iterator(): int = yield 70
+  foo fIt
+
+wrap()
+
+# bug #11533
+proc say = echo "hello"
+
+# Error: internal error: genAssignment: tyNil
+var err0: proc() = say
+err0()
+
+var ok0: proc()
+ok0 = say
+ok0()
+
+var ok1 = say
+ok1()
+
+when false:
+  # bug #12443
+  func newStringIterator(s: string): owned(iterator(): char) =
+    result = iterator(): char =
+      var pos = 0
+      while pos < s.len:
+        yield s[pos]
+        inc pos
+
+  proc stringIter() =
+    let si = newStringIterator("foo")
+    for i in si():
+      echo i
+
+  stringIter()
+
+echo getAllocStats()
diff --git a/tests/destructor/tsink.nim b/tests/destructor/tsink.nim
new file mode 100644
index 000000000..e8750ad7c
--- /dev/null
+++ b/tests/destructor/tsink.nim
@@ -0,0 +1,70 @@
+discard """
+  matrix: "--mm:arc"
+"""
+
+type AnObject = object of RootObj
+  value*: int
+
+proc mutate(shit: sink AnObject) =
+  shit.value = 1
+
+proc foo = # bug #23359
+  var bar = AnObject(value: 42)
+  mutate(bar)
+  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/ttuple.nim b/tests/destructor/ttuple.nim
new file mode 100644
index 000000000..d0ea72c60
--- /dev/null
+++ b/tests/destructor/ttuple.nim
@@ -0,0 +1,130 @@
+
+discard """
+   output: '''5.0 10.0
+=destroy
+=destroy
+'''
+"""
+
+type
+  MyOpt[T] = object
+    case has: bool:
+      of true: val: T
+      of false: nil
+
+  MyVal = object
+    f: ptr float
+
+proc `=destroy`(x: var MyVal) =
+  if x.f != nil:
+    dealloc(x.f)
+
+proc `=sink`(x1: var MyVal, x2: Myval) =
+  if x1.f != x2.f:
+    `=destroy`(x1)
+    x1.f = x2.f
+
+proc `=`(x1: var MyVal, x2: Myval) =
+  if x1.f != x2.f:
+    `=destroy`(x1)
+    x1.f = create(float)
+    x1.f[] = x2.f[]
+
+proc newVal(x: float): MyVal =
+  result.f = create(float)
+  result.f[] = x
+
+template getIt[T, R](self: MyOpt[T], body: untyped, default: R): R =
+  if self.has:
+    template it: untyped {.inject.} = self.val
+    body
+  else:
+    default
+
+proc myproc(h: MyOpt[float]) =
+  let (a, b) = h.getIt((newVal(it), newVal(it * 2)), (newVal(1.0), newVal(1.0)))
+  echo a.f[], " ", b.f[]
+
+let h = MyOpt[float](has: true, val: 5.0)
+myproc(h)
+
+
+#-------------------------------------------------------------
+type
+  MyObject* = object
+    len*: int
+    amount: UncheckedArray[float]
+
+  MyObjPtr* = ptr MyObject
+
+  MyObjContainer* {.byref.} = object
+    size1: int
+    size2: int
+    data: ptr UncheckedArray[MyObjPtr]
+
+ 
+proc size1*(m: MyObjContainer): int {.inline.} = m.size1
+proc size2*(m: MyObjContainer): int {.inline.} = m.size2
+
+proc allocateMyObjPtr(size2: int): MyObjPtr =
+  cast[MyObjPtr](allocShared(sizeof(MyObject) + sizeof(float) * size2.int))
+
+proc `=destroy`*(m: var MyObjContainer) {.inline.} =
+  if m.data != nil:
+    for i in 0..<m.size1:
+      if m.data[i] != nil:
+        deallocShared(m.data[i])
+        m.data[i] = nil
+    deallocShared(m.data)
+    echo "=destroy"
+    m.data = nil
+
+proc `=sink`*(m: var MyObjContainer, m2: MyObjContainer) {.inline.} =
+  if m.data != m2.data:
+    `=destroy`(m)
+  m.size1 = m2.size1
+  m.size2 = m2.size2  
+  m.data = m2.data
+
+
+proc `=`*(m: var MyObjContainer, m2: MyObjContainer) {.error.}
+  ## non copyable
+
+func newMyObjContainer*(size2: Natural): MyObjContainer =
+  result.size2 = size2
+
+proc push(m: var MyObjContainer, cf: MyObjPtr) =
+  ## Add MyObjPtr to MyObjContainer, shallow copy
+  m.size1.inc
+  m.data = cast[ptr UncheckedArray[MyObjPtr]](reallocShared(m.data, m.size1 * sizeof(MyObjPtr)))
+  m.data[m.size1 - 1] = cf
+
+ 
+proc add*(m: var MyObjContainer, amount: float) =
+  assert m.size2 > 0, "MyObjContainer is not initialized, use newMyObjContainer() to initialize object before use"
+  let cf = allocateMyObjPtr(m.size2)
+  for i in 0..<m.size2:
+    cf.amount[i.int] = amount
+
+  m.push(cf)
+
+proc add*(dest: var MyObjContainer, src: sink MyObjContainer) =
+  # merge containers
+
+  for i in 0..<src.size1:
+    dest.push src.data[i]
+    src.data[i] = nil
+
+ 
+proc test = 
+  var cf1 = newMyObjContainer(100)
+  cf1.add(1)
+  cf1.add(2)
+
+  var cf3 = newMyObjContainer(100)
+  cf3.add(2)
+  cf3.add(3)
+
+  cf1.add(cf3)
+
+test()
diff --git a/tests/destructor/turn_destroy_into_finalizer.nim b/tests/destructor/turn_destroy_into_finalizer.nim
new file mode 100644
index 000000000..1409c1c57
--- /dev/null
+++ b/tests/destructor/turn_destroy_into_finalizer.nim
@@ -0,0 +1,26 @@
+discard """
+  output: "turn_destroy_into_finalizer works"
+  joinable: false
+"""
+
+type
+  Foo = object
+    id: int
+
+var destroyed: int
+
+proc `=destroy`(x: var Foo) =
+  #echo "finally ", x.id
+  inc destroyed
+
+proc main =
+  var r: ref Foo
+  for i in 1..50_000:
+    new(r)
+    r.id = i
+  if destroyed > 30_000:
+    echo "turn_destroy_into_finalizer works"
+  else:
+    echo "turn_destroy_into_finalizer failed: ", destroyed
+
+main()
diff --git a/tests/destructor/tuse_ownedref_after_move.nim b/tests/destructor/tuse_ownedref_after_move.nim
new file mode 100644
index 000000000..69348d530
--- /dev/null
+++ b/tests/destructor/tuse_ownedref_after_move.nim
@@ -0,0 +1,57 @@
+discard """
+  cmd: '''nim c --newruntime $file'''
+  errormsg: "'=copy' is not available for type <owned Button>; requires a copy because it's not the last read of ':envAlt.b1'; routine: main"
+  line: 48
+"""
+
+import system / ansi_c
+
+type
+  Widget* = ref object of RootObj
+    drawImpl: owned(proc (self: Widget))
+
+  Button* = ref object of Widget
+    caption: string
+    onclick: owned(proc())
+
+  Window* = ref object of Widget
+    elements: seq[owned Widget]
+
+
+proc newButton(caption: string; onclick: owned(proc())): owned Button =
+  proc draw(self: Widget) =
+    let b = Button(self)
+    echo b.caption
+
+  result = Button(drawImpl: draw, caption: caption, onclick: onclick)
+
+proc newWindow(): owned Window =
+  proc draw(self: Widget) =
+    let w = Window(self)
+    for e in w.elements:
+      if not e.drawImpl.isNil: e.drawImpl(e)
+
+  result = Window(drawImpl: draw, elements: @[])
+
+proc draw(w: Widget) =
+  if not w.drawImpl.isNil: w.drawImpl(w)
+
+proc add*(w: Window; elem: owned Widget) =
+  w.elements.add elem
+
+proc main =
+  var w = newWindow()
+
+  var b = newButton("button", nil)
+  b.onclick = proc () =
+    b.caption = "clicked!"
+  w.add b
+
+  w.draw()
+  # simulate button click:
+  b.onclick()
+
+  w.draw()
+
+main()
+
diff --git a/tests/destructor/tuse_result_prevents_sinks.nim b/tests/destructor/tuse_result_prevents_sinks.nim
new file mode 100644
index 000000000..e74c16da3
--- /dev/null
+++ b/tests/destructor/tuse_result_prevents_sinks.nim
@@ -0,0 +1,37 @@
+discard """
+  output: ""
+  targets: "c"
+"""
+
+# bug #9594
+
+type
+  Foo = object
+    i: int
+
+proc `=`(self: var Foo; other: Foo) =
+  self.i = other.i + 1
+
+proc `=sink`(self: var Foo; other: Foo) =
+  self.i = other.i
+
+proc `=destroy`(self: var Foo) = discard
+
+template preventCursorInference(x) =
+  let p = addr(x)
+
+proc test(): Foo =
+  result = Foo()
+  let temp = result
+  preventCursorInference temp
+  doAssert temp.i > 0
+  return result
+
+proc testB(): Foo =
+  result = Foo()
+  let temp = result
+  preventCursorInference temp
+  doAssert temp.i > 0
+
+discard test()
+discard testB()
diff --git a/tests/destructor/tv2_cast.nim b/tests/destructor/tv2_cast.nim
new file mode 100644
index 000000000..48bdf67dd
--- /dev/null
+++ b/tests/destructor/tv2_cast.nim
@@ -0,0 +1,116 @@
+discard """
+  output: '''@[1]
+@[116, 101, 115, 116]
+@[1953719668, 875770417]
+destroying O1'''
+  cmd: '''nim c --mm:arc --expandArc:main --expandArc:main1 --expandArc:main2 --expandArc:main3 --hints:off --assertions:off $file'''
+  nimout: '''
+--expandArc: main
+
+var
+  data
+  :tmpD
+data = cast[string](encode(cast[seq[byte]](
+  :tmpD = newString(100)
+  :tmpD)))
+`=destroy`(:tmpD)
+`=destroy`(data)
+-- end of expandArc ------------------------
+--expandArc: main1
+
+var
+  s
+  data
+s = newString(100)
+data = cast[string](encode(toOpenArrayByte(s, 0, len(s) - 1)))
+`=destroy`(data)
+`=destroy`(s)
+-- end of expandArc ------------------------
+--expandArc: main2
+
+var
+  s
+  data
+s = newSeq(100)
+data = cast[string](encode(s))
+`=destroy`(data)
+`=destroy_1`(s)
+-- end of expandArc ------------------------
+--expandArc: main3
+
+var
+  data
+  :tmpD
+data = cast[string](encode do:
+  :tmpD = newSeq(100)
+  :tmpD)
+`=destroy`(:tmpD)
+`=destroy_1`(data)
+-- end of expandArc ------------------------
+'''
+"""
+
+func encode*(src: openArray[byte]): seq[byte] =
+  result = newSeq[byte](src.len)
+
+template compress*(src: string): string =
+  cast[string](encode(cast[seq[byte]](src)))
+
+proc main =
+  let data = compress(newString(100))
+main()
+
+proc main1 =
+  var
+    s = newString(100)
+  let data = cast[string](encode(s.toOpenArrayByte(0, s.len-1)))
+main1()
+
+proc main2 =
+  var
+    s = newSeq[byte](100)
+  let data = cast[string](encode(s))
+main2()
+
+proc main3 =
+  let data = cast[string](encode(newSeq[byte](100)))
+main3()
+
+# bug #11018
+discard cast[seq[uint8]](@[1])
+discard cast[seq[uint8]]("test")
+echo cast[seq[uint8]](@[1])
+echo cast[seq[uint8]]("test")
+
+discard cast[string](@[116'u8, 101, 115, 116])
+#echo cast[string](@[116'u8, 101, 115, 116, 0])
+var a = cast[seq[uint32]]("test1234")
+a.setLen(2)
+echo a
+
+
+#issue 11204
+var ac {.compileTime.} = @["a", "b"]
+const bc = ac.len
+
+
+type
+  O = object of RootRef
+    i: int
+
+  O1 = object of O
+  O2 = object of O
+
+proc `=destroy`(o: var O) =
+  echo "destroying O"
+
+proc `=destroy`(o: var O1) =
+  echo "destroying O1"
+
+proc `=destroy`(o: var O2) =
+  echo "destroying O2"
+
+proc test =
+  let o3 = cast[ref O2]((ref O1)())
+
+test()
diff --git a/tests/destructor/tv2_raise.nim b/tests/destructor/tv2_raise.nim
new file mode 100644
index 000000000..66b0aec30
--- /dev/null
+++ b/tests/destructor/tv2_raise.nim
@@ -0,0 +1,53 @@
+discard """
+  valgrind: true
+  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  output: '''OK 3
+(allocCount: 7, deallocCount: 4)'''
+"""
+
+import strutils, math
+import system / ansi_c
+
+proc mainA =
+  try:
+    var e: owned(ref ValueError)
+    new(e)
+    e.msg = "message"
+    raise e
+  except Exception as e:
+    raise
+
+
+proc main =
+  raise newException(ValueError, "argh")
+
+var ok = 0
+try:
+  mainA()
+except ValueError:
+  inc ok
+except:
+  discard
+
+try:
+  main()
+except ValueError:
+  inc ok
+except:
+  discard
+
+#  bug #11577
+
+proc newError*: owned(ref Exception) {.noinline.} =
+  new(result)
+
+proc mainC =
+  raise newError()
+
+try:
+  mainC()
+except:
+  inc ok
+
+echo "OK ", ok
+echo getAllocStats()
diff --git a/tests/destructor/twasmoved.nim b/tests/destructor/twasmoved.nim
new file mode 100644
index 000000000..566322702
--- /dev/null
+++ b/tests/destructor/twasmoved.nim
@@ -0,0 +1,14 @@
+type
+  Foo = object
+    id: int
+
+proc `=wasMoved`(x: var Foo) =
+  x.id = -1
+
+proc foo =
+  var s = Foo(id: 999)
+  var m = move s
+  doAssert s.id == -1
+  doAssert m.id == 999
+
+foo()
diff --git a/tests/destructor/twasmoved_error.nim b/tests/destructor/twasmoved_error.nim
new file mode 100644
index 000000000..1cd57e3df
--- /dev/null
+++ b/tests/destructor/twasmoved_error.nim
@@ -0,0 +1,37 @@
+discard """
+  cmd: '''nim c --mm:arc $file'''
+  errormsg: "'=wasMoved' is not available for type <Game>; routine: main"
+"""
+
+# bug #19291
+
+const
+  screenWidth = 800
+  screenHeight = 450
+
+var
+  ready = false
+type
+  Game = object
+
+proc `=destroy`(x: var Game) =
+  assert ready, "Window is already opened"
+  ready = false
+
+proc `=sink`(x: var Game; y: Game) {.error.}
+proc `=copy`(x: var Game; y: Game) {.error.}
+proc `=wasMoved`(x: var Game) {.error.}
+
+proc initGame(width, height: int32, title: string): Game =
+  assert not ready, "Window is already closed"
+  ready = true
+
+proc update(x: Game) = discard
+
+proc main =
+  var g = initGame(screenWidth, screenHeight, "Tetris raylib")
+  g.update()
+  var g2 = g
+  echo "hello"
+
+main()
diff --git a/tests/destructor/twidgets.nim b/tests/destructor/twidgets.nim
new file mode 100644
index 000000000..f13868110
--- /dev/null
+++ b/tests/destructor/twidgets.nim
@@ -0,0 +1,76 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  output: '''button
+clicked!
+(allocCount: 4, deallocCount: 4)'''
+"""
+
+import system / ansi_c
+
+type
+  Widget* = ref object of RootObj
+    drawImpl: owned(proc (self: Widget))
+
+  Button* = ref object of Widget
+    caption: string
+    onclick: owned(proc())
+
+  Window* = ref object of Widget
+    elements: seq[owned Widget]
+
+
+proc newButton(caption: string; onclick: owned(proc())): owned Button =
+  proc draw(self: Widget) =
+    let b = Button(self)
+    echo b.caption
+
+  #result = Button(drawImpl: draw, caption: caption, onclick: onclick)
+  new(result)
+  result.drawImpl = draw
+  result.caption = caption
+  result.onclick = onclick
+
+iterator unitems*[T](a: seq[owned T]): T {.inline.} =
+  ## Iterates over each item of `a`.
+  var i = 0
+  let L = len(a)
+  while i < L:
+    yield a[i]
+    inc(i)
+    assert(len(a) == L, "the length of the seq changed while iterating over it")
+
+proc newWindow(): owned Window =
+  proc windraw(self: Widget) =
+    let w = Window(self)
+    for i in 0..<len(w.elements):
+      let e = Widget(w.elements[i])
+      let d = (proc(self: Widget))e.drawImpl
+      if not d.isNil: d(e)
+
+  result = Window(drawImpl: windraw, elements: @[])
+
+proc draw(w: Widget) =
+  let d = (proc(self: Widget))w.drawImpl
+  if not d.isNil: d(w)
+
+proc add*(w: Window; elem: owned Widget) =
+  w.elements.add elem
+
+proc main =
+  var w = newWindow()
+
+  var b = newButton("button", nil)
+  let u: Button = b
+  b.onclick = proc () =
+    u.caption = "clicked!"
+  w.add b
+
+  w.draw()
+  # simulate button click:
+  u.onclick()
+
+  w.draw()
+
+dumpAllocstats:
+  main()
+
diff --git a/tests/destructor/twidgets_unown.nim b/tests/destructor/twidgets_unown.nim
new file mode 100644
index 000000000..8653d5c28
--- /dev/null
+++ b/tests/destructor/twidgets_unown.nim
@@ -0,0 +1,72 @@
+discard """
+  cmd: '''nim c -d:nimAllocStats --newruntime $file'''
+  output: '''button
+clicked!
+(allocCount: 6, deallocCount: 6)'''
+"""
+
+import system / ansi_c
+
+type
+  Widget* = ref object of RootObj
+    drawImpl: owned(proc (self: Widget))
+
+  Button* = ref object of Widget
+    caption: string
+    onclick: owned(proc())
+
+  Window* = ref object of Widget
+    elements: seq[owned Widget]
+
+
+proc newButton(caption: string; onclick: owned(proc())): owned Button =
+  proc draw(self: Widget) =
+    let b = Button(self)
+    echo b.caption
+
+  #result = Button(drawImpl: draw, caption: caption, onclick: onclick)
+  new(result)
+  result.drawImpl = draw
+  result.caption = caption
+  result.onclick = onclick
+
+proc newWindow(): owned Window =
+  proc windraw(self: Widget) =
+    let w = Window(self)
+    for e in unown(w.elements):
+      let d = unown e.drawImpl
+      if not d.isNil: d(e)
+
+  result = Window(drawImpl: windraw, elements: @[])
+
+proc draw(w: Widget) =
+  let d = unown w.drawImpl
+  if not d.isNil: d(w)
+
+proc add*(w: Window; elem: owned Widget) =
+  w.elements.add elem
+
+proc main =
+  var w = newWindow()
+
+  var b = newButton("button", nil)
+  let u = unown b
+  var clicked = "clicked"
+  b.onclick = proc () =
+    clicked.add "!"
+    u.caption = clicked
+  w.add b
+
+  w.draw()
+  # simulate button click:
+  u.onclick()
+
+  w.draw()
+
+  # bug #11257
+  var a: owned proc()
+  if a != nil:
+    a()
+
+dumpAllocStats:
+  main()
diff --git a/tests/dir with space/more spaces/mspace.nim b/tests/dir with space/more spaces/mspace.nim
new file mode 100644
index 000000000..bc2c90f5e
--- /dev/null
+++ b/tests/dir with space/more spaces/mspace.nim
@@ -0,0 +1 @@
+proc tenTimes*(x: int): int = 10*x
diff --git a/tests/dir with space/tspace.nim b/tests/dir with space/tspace.nim
new file mode 100644
index 000000000..87a52c271
--- /dev/null
+++ b/tests/dir with space/tspace.nim
@@ -0,0 +1,10 @@
+discard """
+output: "Successful"
+"""
+# Test for the compiler to be able to compile a Nim file with spaces in the directory name.
+# Also test if import of a directory with a space works.
+
+import "more spaces" / mspace
+
+assert tenTimes(5) == 50
+echo("Successful")
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
new file mode 100644
index 000000000..84b669ed8
--- /dev/null
+++ b/tests/discard/tdiscardable.nim
@@ -0,0 +1,175 @@
+discard """
+output: '''
+tdiscardable
+1
+1
+something defered
+something defered
+hi
+'''
+"""
+
+echo "tdiscardable"
+
+# Test the discardable pragma
+
+proc p(x, y: int): int {.discardable.} =
+  return x + y
+
+# test that it is inherited from generic procs too:
+proc q[T](x, y: T): T {.discardable.} =
+  return x + y
+
+
+p(8, 2)
+q[float](0.8, 0.2)
+
+# bug #942
+
+template maybeMod(x: SomeInteger, module: Natural): untyped =
+  if module > 0: x mod module
+  else: x
+
+proc foo(b: int):int =
+  var x = 1
+  result = x.maybeMod(b) # Works fine
+
+proc bar(b: int):int =
+  result = 1
+  result = result.maybeMod(b) # Error: value returned by statement has to be discarded
+
+echo foo(0)
+echo bar(0)
+
+# bug #9726
+
+proc foo: (proc: int) =
+  proc bar: int = 1
+  return bar
+
+discard foo()
+
+# bug #10842
+
+proc myDiscardable(): int {.discardable.} =
+  discard
+
+proc main1() =
+  defer:
+    echo "something defered"
+  discard myDiscardable()
+
+proc main2() =
+  defer:
+    echo "something defered"
+  myDiscardable()
+
+main1()
+main2()
+
+block: # bug #13583
+  block:
+    proc hello(): int {.discardable.} = 12
+
+    iterator test(): int {.closure.} =
+      while true:
+        hello()
+
+    let t = test
+
+  block:
+    proc hello(): int {.discardable.} = 12
+
+    iterator test(): int {.closure.} =
+      while true:
+        block:
+          yield 12
+          hello()
+
+    let t = test
+    doAssert t() == 12
+
+  block:
+    proc hello(): int {.discardable.} = 12
+
+    iterator test(): int {.closure.} =
+      while true:
+        yield 12
+        hello()
+
+    let t = test
+    doAssert t() == 12
+
+block:
+  proc bar(): string {.discardable.} =
+    "15"
+
+  proc foo(): int =
+    while true:
+      raise newException(ValueError, "check")
+    12
+
+  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/discard/tillegaldiscard.nim b/tests/discard/tillegaldiscard.nim
new file mode 100644
index 000000000..757f4e727
--- /dev/null
+++ b/tests/discard/tillegaldiscard.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "illegal discard"
+  line: 9
+"""
+
+proc pop[T](arg: T): T =
+  echo arg
+
+discard tillegaldiscard.pop
diff --git a/tests/discard/tillegaldiscardtypes.nim b/tests/discard/tillegaldiscardtypes.nim
new file mode 100644
index 000000000..b7877bcd2
--- /dev/null
+++ b/tests/discard/tillegaldiscardtypes.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim check $file"
+  errormsg: "statement returns no value that can be discarded"
+  nimout: '''
+tillegaldiscardtypes.nim(11, 3) Error: statement returns no value that can be discarded
+tillegaldiscardtypes.nim(12, 3) Error: statement returns no value that can be discarded
+'''
+"""
+
+proc b(v: int) = # bug #21360
+  discard @[]
+  discard []
+
+b(0)
\ No newline at end of file
diff --git a/tests/discard/tneedsdiscard.nim b/tests/discard/tneedsdiscard.nim
new file mode 100644
index 000000000..75cd9d2df
--- /dev/null
+++ b/tests/discard/tneedsdiscard.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: '''expression 'open(f, "arg.txt", fmRead, -1)' is of type 'bool' and has to be used (or discarded); start of expression here: tneedsdiscard.nim(7, 3)'''
+  line: 10
+"""
+
+proc p =
+  var f: File
+  echo "hi"
+
+  open(f, "arg.txt")
+
+p()
diff --git a/tests/discard/tneedsdiscard_in_for.nim b/tests/discard/tneedsdiscard_in_for.nim
new file mode 100644
index 000000000..7685bd577
--- /dev/null
+++ b/tests/discard/tneedsdiscard_in_for.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: '''expression 'premultiply(app.gradient[i])' is of type 'Rgba8' and has to be used (or discarded)'''
+  line: 22
+"""
+
+# bug #9076
+type
+  Rgba8 = object
+
+proc premultiply*(c: var Rgba8): var Rgba8 =
+  return c
+
+type
+  App = ref object
+    gradient: seq[Rgba8]
+
+method onDraw(app: App) {.base.} =
+  var
+    width  = 100'f64
+
+  for i in 0..<width.int:
+    app.gradient[i].premultiply()
diff --git a/tests/discard/tvoidcontext.nim b/tests/discard/tvoidcontext.nim
new file mode 100644
index 000000000..9e2b913ad
--- /dev/null
+++ b/tests/discard/tvoidcontext.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: '''expression '"invalid"' is of type 'string' and has to be used (or discarded)'''
+  line: 12
+"""
+
+proc valid*(): string =
+  let x = 317
+  "valid"
+
+proc invalid*(): string =
+  result = "foo"
+  "invalid"
diff --git a/tests/distinct/t7165.nim b/tests/distinct/t7165.nim
new file mode 100644
index 000000000..b16c29c0e
--- /dev/null
+++ b/tests/distinct/t7165.nim
@@ -0,0 +1,15 @@
+
+type
+  Table[K, V] = object
+    key: K
+    val: V
+
+  MyTable = distinct Table[string, int]
+  MyTableRef = ref MyTable
+
+proc newTable[K, V](): ref Table[K, V] = discard
+
+proc newMyTable: MyTableRef =
+  MyTableRef(newTable[string, int]()) # <--- error here
+
+discard newMyTable()
diff --git a/tests/distinct/tborrow.nim b/tests/distinct/tborrow.nim
new file mode 100644
index 000000000..e34248de5
--- /dev/null
+++ b/tests/distinct/tborrow.nim
@@ -0,0 +1,132 @@
+discard """
+  output: '''4887 true
+0.5'''
+"""
+
+# test the new borrow feature that works with generics:
+
+proc `++`*[T: int | float](a, b: T): T =
+  result = a + b
+
+type
+  DI = distinct int
+  DF = distinct float
+  DS = distinct string
+
+proc `++`(x, y: DI): DI {.borrow.}
+proc `++`(x, y: DF): DF {.borrow.}
+
+proc `$`(x: DI): string {.borrow.}
+proc `$`(x: DF): string {.borrow.}
+
+echo  4544.DI ++ 343.DI, " ", (4.5.DF ++ 0.5.DF).float == 5.0
+
+# issue #14440
+
+type Radians = distinct float64
+
+func `-=`(a: var Radians, b: Radians) {.borrow.}
+
+var a = Radians(1.5)
+let b = Radians(1.0)
+
+a -= b
+
+echo a.float64
+
+block: #14449
+  type 
+    Foo[T] = object
+      foo: T
+
+    Bar[T] {.borrow:`.`.} = distinct Foo[T]
+    SomeThing {.borrow:`.`.} = distinct Foo[float]
+    OtherThing {.borrow:`.`.} = distinct SomeThing
+
+  var
+    a: Bar[int]
+    b: SomeThing
+    c: OtherThing
+  a.foo = 300
+  b.foo = 400
+  c.foo = 42
+  assert a.foo == 300
+  assert b.foo == 400d
+  assert c.foo == 42d
+
+block: # Borrow from muliple aliasses #16666
+  type
+    AImpl = object
+      i: int
+    
+    A = AImpl
+  
+    B {.borrow: `.`.} = distinct A
+    C = B
+    D {.borrow: `.`.} = distinct C
+    E {.borrow: `.`.} = distinct D
+  
+  let
+    b = default(B)
+    d = default(D)
+    e = default(E)
+  
+  assert b.i == 0
+  assert d.i == 0
+  assert e.i == 0
+
+block: # Borrow from generic alias
+  type
+    AImpl[T] = object
+      i: T
+    B[T] = AImpl[T]
+    C {.borrow: `.`.} = distinct B[int]
+    D = B[float]
+    E {.borrow: `.`.} = distinct D
+
+  let
+    c = default(C)
+    e = default(E)
+  assert c.i == int(0)
+  assert e.i == 0d
+
+block: # issue #22069
+  type
+    Vehicle[C: static[int]] = object
+      color: array[C, int]
+    Car[C: static[int]] {.borrow: `.`.} = distinct Vehicle[C]
+    MuscleCar = Car[128]
+  var x: MuscleCar
+  doAssert x.color is array[128, int]
+
+block: # issue #22646
+  type
+    Vec[N : static[int], T: SomeNumber] = object
+      arr: array[N, T]
+    Vec3[T: SomeNumber] = Vec[3, T]
+
+  proc `[]=`[N,T](v: var Vec[N,T]; ix:int; c:T): void {.inline.} = v.arr[ix] = c
+  proc `[]`[N,T](v: Vec[N,T]; ix: int): T {.inline.} = v.arr[ix]
+
+  proc dot[N,T](u,v: Vec[N,T]): T {. inline .} = discard
+  proc length[N,T](v: Vec[N,T]): T = discard
+  proc cross[T](v1,v2:Vec[3,T]): Vec[3,T] = discard
+  proc normalizeWorks[T](v: Vec[3,T]): Vec[3,T] = discard ## <- Explicit size makes it work!
+  proc foo[N,T](u, v: Vec[N,T]): Vec[N,T] = discard ## <- broken
+  proc normalize[N,T](v: Vec[N,T]): Vec[N,T] = discard ## <- broken
+
+  type Color = distinct Vec3[float]
+
+  template borrowOps(typ: typedesc): untyped =
+    proc `[]=`(v: var typ; ix: int; c: float): void {.borrow.}
+    proc `[]`(v: typ; ix: int): float {.borrow.}
+    proc dot(v, u: typ): float {.borrow.}
+    proc cross(v, u: typ): typ {.borrow.}
+    proc length(v: typ): float {.borrow.}
+    proc normalizeWorks(v: typ): typ {.borrow.} ## Up to here everything works
+    proc foo(u, v: typ): typ {.borrow.} ## Broken
+    proc normalize(v: typ): typ {.borrow.} ## Broken
+  borrowOps(Color)
+  var x: Vec[3, float]
+  let y = Color(x)
+  doAssert Vec3[float](y) == x
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/distinct/tdistinct.nim b/tests/distinct/tdistinct.nim
new file mode 100644
index 000000000..b6ba7aa99
--- /dev/null
+++ b/tests/distinct/tdistinct.nim
@@ -0,0 +1,227 @@
+discard """
+  targets: "c js"
+  output: '''
+tdistinct
+25
+false
+false
+false
+false
+Foo
+foo
+'''
+"""
+
+echo "tdistinct"
+
+block tborrowdot:
+  type
+    Foo = object
+      a, b: int
+      s: string
+
+    Bar {.borrow: `.`.} = distinct Foo
+
+  var bb: ref Bar
+  new bb
+  bb.a = 90
+  bb.s = "abc"
+
+block tcurrncy:
+  template Additive(typ: untyped) =
+    proc `+`(x, y: typ): typ {.borrow.}
+    proc `-`(x, y: typ): typ {.borrow.}
+
+    # unary operators:
+    proc `+`(x: typ): typ {.borrow.}
+    proc `-`(x: typ): typ {.borrow.}
+
+  template Multiplicative(typ, base: untyped) =
+    proc `*`(x: typ, y: base): typ {.borrow.}
+    proc `*`(x: base, y: typ): typ {.borrow.}
+    proc `div`(x: typ, y: base): typ {.borrow.}
+    proc `mod`(x: typ, y: base): typ {.borrow.}
+
+  template Comparable(typ: untyped) =
+    proc `<`(x, y: typ): bool {.borrow.}
+    proc `<=`(x, y: typ): bool {.borrow.}
+    proc `==`(x, y: typ): bool {.borrow.}
+
+  template DefineCurrency(typ, base: untyped) =
+    type
+      typ = distinct base
+    Additive(typ)
+    Multiplicative(typ, base)
+    Comparable(typ)
+
+    proc `$`(t: typ): string {.borrow.}
+
+  DefineCurrency(TDollar, int)
+  DefineCurrency(TEuro, int)
+  echo($( 12.TDollar + 13.TDollar )) #OUT 25
+
+block tconsts:
+  # bug #2641
+
+  type MyChar = distinct char
+  const c:MyChar = MyChar('a')
+
+  type MyBool = distinct bool
+  const b:MyBool = MyBool(true)
+
+  type MyBoolSet = distinct set[bool]
+  const bs:MyBoolSet = MyBoolSet({true})
+
+  type MyCharSet= distinct set[char]
+  const cs:MyCharSet = MyCharSet({'a'})
+
+  type MyBoolSeq = distinct seq[bool]
+  const bseq:MyBoolSeq = MyBoolSeq(@[true, false])
+
+  type MyBoolArr = distinct array[3, bool]
+  const barr:MyBoolArr = MyBoolArr([true, false, true])
+
+# bug #2760
+
+type
+  DistTup = distinct tuple
+    foo, bar: string
+
+const d: DistTup = DistTup((
+  foo:"FOO", bar:"BAR"
+))
+
+
+# bug #7167
+
+type Id = distinct range[0..3]
+
+proc `<=`(a, b: Id): bool {.borrow.}
+
+var xs: array[Id, bool]
+
+for x in xs: echo x # type mismatch: got (T) but expected 'bool'
+
+# bug #11715
+
+type FooD = distinct int
+proc `<=`(a, b: FooD): bool {.borrow.}
+
+for f in [FooD(0): "Foo"]: echo f
+
+block tRequiresInit:
+  template accept(x) =
+    static: doAssert compiles(x)
+
+  template reject(x) =
+    static: doAssert not compiles(x)
+
+  type
+    Foo = object
+      x: string
+
+    DistinctFoo {.requiresInit, borrow: `.`.} = distinct Foo
+    DistinctString {.requiresInit.} = distinct string
+
+  reject:
+    var foo: DistinctFoo
+    foo.x = "test"
+    doAssert foo.x == "test"
+
+  accept:
+    let foo = DistinctFoo(Foo(x: "test"))
+    doAssert foo.x == "test"
+
+  reject:
+    var s: DistinctString
+    s = "test"
+    doAssert string(s) == "test"
+
+  accept:
+    let s = DistinctString("test")
+    doAssert string(s) == "test"
+
+block: #17322
+  type
+    A[T] = distinct string
+
+  proc foo(a: var A) =
+    a.string.add "foo"
+
+  type
+    B = distinct A[int]
+
+  var b: B
+  foo(A[int](b))
+  echo A[int](b).string
+  b.string.add "bar"
+  assert b.string == "foobar"
+
+type Foo = distinct string
+
+proc main() = # proc instead of template because of MCS/UFCS.
+  # xxx put everything here to test under RT + VM
+  block: # bug #12282
+    block:
+      proc test() =
+        var s: Foo
+        s.string.add('c')
+        doAssert s.string == "c" # was failing
+      test()
+
+    block:
+      proc add(a: var Foo, b: char) {.borrow.}
+      proc test() =
+        var s: Foo
+        s.add('c')
+        doAssert s.string == "c" # was ok
+      test()
+
+    block:
+      proc add(a: var Foo, b: char) {.borrow.}
+      proc test() =
+        var s: string
+        s.Foo.add('c')
+        doAssert s.string == "c" # was failing
+      test()
+    block: #18061
+      type
+        A = distinct (0..100)
+        B = A(0) .. A(10)
+      proc test(b: B) = discard
+      let
+        a = A(10)
+        b = B(a)
+      test(b)
+
+      proc test(a: A) = discard
+      discard cast[B](A(1))
+      var c: B
+
+
+  block: # bug #9423
+    block:
+      type Foo = seq[int]
+      type Foo2 = distinct Foo
+      template fn() =
+        var a = Foo2(@[1])
+        a.Foo.add 2
+        doAssert a.Foo == @[1, 2]
+      fn()
+
+    block:
+      type Stack[T] = distinct seq[T]
+      proc newStack[T](): Stack[T] =
+        Stack[T](newSeq[T]())
+      proc push[T](stack: var Stack[T], elem: T) =
+        seq[T](stack).add(elem)
+      proc len[T](stack: Stack[T]): int =
+        seq[T](stack).len
+      proc fn() = 
+        var stack = newStack[int]()
+        stack.push(5)
+        doAssert stack.len == 1
+      fn()
+
+static: main()
+main()
diff --git a/tests/distinct/tdistinct_issues.nim b/tests/distinct/tdistinct_issues.nim
new file mode 100644
index 000000000..747cf0b8d
--- /dev/null
+++ b/tests/distinct/tdistinct_issues.nim
@@ -0,0 +1,81 @@
+discard """
+  output: '''
+A
+A
+25.0
+210.0
+apr
+'''
+"""
+
+
+block t4435:
+  type
+    A[T] = distinct T
+    B[T] = distinct T
+
+  proc foo[T](x:A[T]) = echo "A"
+  proc foo[T](x:B[T]) = echo "B"
+  proc bar(x:A) = echo "A"
+  proc bar(x:B) = echo "B"
+
+  var
+    a:A[int]
+
+  foo(a) # fine
+  bar(a) # testdistinct.nim(14, 4) Error: ambiguous call; both testdistinct.bar(x: A) and testdistinct.bar(x: B) match for: (A[system.int])
+
+
+
+block t7010:
+  type MyInt = distinct int
+
+  proc `+`(x: MyInt, y: MyInt): MyInt {.borrow.}
+  proc `+=`(x: var MyInt, y: MyInt) {.borrow.}
+  proc `=`(x: var MyInt, y: MyInt) {.borrow.}
+
+  var next: MyInt
+
+  proc getNext() : MyInt =
+      result = next
+      next += 1.MyInt
+      next = next + 1.MyInt
+
+
+
+block t9079:
+  type
+    Dollars = distinct float
+
+  proc `$`(d: Dollars): string {.borrow.}
+  proc `*`(a, b: Dollars): Dollars {.borrow.}
+  proc `+`(a, b: Dollars): Dollars {.borrow.}
+
+  var a = Dollars(20)
+  a = Dollars(25.0)
+  echo a
+  a = 10.Dollars * (20.Dollars + 1.Dollars)
+  echo a
+
+
+
+block t9322:
+  type Fix = distinct string
+  proc `$`(f: Fix): string {.borrow.}
+  proc mystr(s: string) =
+    echo s
+  mystr($Fix("apr"))
+
+
+block: # bug #13517
+  type MyUint64 = distinct uint64
+
+  proc `==`(a: MyUint64, b: uint64): bool = uint64(a) == b
+
+  block:
+    doAssert MyUint64.high is MyUint64
+    doAssert MyUint64.high == 18446744073709551615'u64
+
+  static:
+    doAssert MyUint64.high is MyUint64
+    doAssert MyUint64.high == 18446744073709551615'u64
diff --git a/tests/distinct/tinvalidborrow.nim b/tests/distinct/tinvalidborrow.nim
new file mode 100644
index 000000000..d4b19fa8d
--- /dev/null
+++ b/tests/distinct/tinvalidborrow.nim
@@ -0,0 +1,42 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  action: "reject"
+  nimout:'''
+tinvalidborrow.nim(25, 3) Error: only a 'distinct' type can borrow `.`
+tinvalidborrow.nim(26, 3) Error: only a 'distinct' type can borrow `.`
+tinvalidborrow.nim(27, 1) Error: borrow proc without distinct type parameter is meaningless
+tinvalidborrow.nim(36, 1) Error: borrow with generic parameter is not supported
+tinvalidborrow.nim(41, 1) Error: borrow from proc return type mismatch: 'T'
+tinvalidborrow.nim(42, 1) Error: borrow from '[]=' is not supported
+'''
+"""
+
+
+
+
+
+# bug #516
+
+type
+  TAtom = culong
+  Test {.borrow:`.`.} = distinct int
+  Foo[T] = object
+    a: int
+  Bar[T] {.borrow:`.`.} = Foo[T]
+  OtherFoo {.borrow:`.`.} = Foo[int]
+proc `==`*(a, b: TAtom): bool {.borrow.}
+
+var
+  d, e: TAtom
+
+discard( $(d == e) )
+
+# issue #4121
+type HeapQueue[T] = distinct seq[T]
+proc len*[T](h: HeapQueue[T]): int {.borrow.}
+
+# issue #3564
+type vec4[T] = distinct array[4, float32]
+
+proc `[]`(v: vec4, i: int): float32 {.borrow.}
+proc `[]=`(v: vec4, i: int, va: float32) {.borrow.}
diff --git a/tests/distinct/tnil.nim b/tests/distinct/tnil.nim
new file mode 100644
index 000000000..b54c07432
--- /dev/null
+++ b/tests/distinct/tnil.nim
@@ -0,0 +1,22 @@
+{.experimental: "notnil".}
+type
+  MyPointer = distinct pointer
+  MyString = distinct string
+  MyInt = distinct int
+
+proc foo(a: MyPointer): int =
+  # workaround a Windows 'repr' difference:
+  cast[int](a)
+
+doAssert foo(cast[MyPointer](1)) == 1
+doAssert foo(cast[MyPointer](nil)) == 0
+doAssert foo(MyPointer(nil)) == 0
+
+var p: MyPointer
+p = cast[MyPointer](1)
+p = cast[MyPointer](nil)
+p = nil.MyPointer
+
+var i: MyInt
+i = 1.MyInt
+doAssert(compiles(i = nil) == false)
diff --git a/tests/distinct/typeclassborrow.nim b/tests/distinct/typeclassborrow.nim
new file mode 100644
index 000000000..5e0c63953
--- /dev/null
+++ b/tests/distinct/typeclassborrow.nim
@@ -0,0 +1,56 @@
+import std/tables
+
+type
+  Foo = distinct seq[int]
+  Bar[N: static[int]] = distinct seq[int]
+  Baz = distinct Bar[10]
+
+proc newSeq(s: var Foo, n: Natural) {.borrow.}
+proc newSeq(s: var Bar, n: Natural) {.borrow.}
+proc newSeq(s: var Baz, n: Natural) {.borrow.}
+
+
+proc `$`(s: Foo): string {.borrow.}
+proc `$`(s: Bar): string {.borrow.}
+proc `$`(s: Baz): string {.borrow.}
+
+proc doThing(b: Bar) = discard
+proc doThing(b: Baz) {.borrow.}
+
+var
+  foo: Foo
+  bar: Bar[10]
+  baz: Baz
+
+newSeq(foo, 100)
+newSeq(bar, bar.N)
+newSeq(baz, 10)
+
+bar.doThing()
+baz.doThing()
+
+assert $seq[int](foo) == $foo
+assert $seq[int](bar) == $bar
+assert $seq[int](baz) == $baz
+
+type
+  Fine* = distinct string
+
+proc `==`*(x, y: Fine): bool {.borrow.} =
+  ## Here is the documentation
+  runnableExamples:
+    var x = Fine("1234")
+    var y = Fine("1234")
+    doAssert x == y
+  doAssert false
+
+
+var x = Fine("1234")
+var y = Fine("1234")
+doAssert x == y
+
+block: # bug #22902
+  type
+    DistinctTable = distinct Table[int, int]
+
+  proc `[]`(t: DistinctTable; key: int): lent int {.borrow.}
diff --git a/tests/dll/client.nim b/tests/dll/client.nim
new file mode 100644
index 000000000..62697569f
--- /dev/null
+++ b/tests/dll/client.nim
@@ -0,0 +1,43 @@
+discard """
+  cmd: "nim $target --debuginfo --hints:on --define:useNimRtl $options $file"
+"""
+
+type
+  TNodeKind = enum nkLit, nkSub, nkAdd, nkDiv, nkMul
+  TNode = object
+    case k: TNodeKind
+    of nkLit: x: int
+    else: a, b: ref TNode
+
+  PNode = ref TNode
+
+
+when defined(windows):
+  const dllname = "server.dll"
+elif defined(macosx):
+  const dllname = "libserver.dylib"
+else:
+  const dllname = "libserver.so"
+
+proc newLit(x: int): PNode {.importc: "newLit", dynlib: dllname.}
+proc newOp(k: TNodeKind, a, b: PNode): PNode {.
+  importc: "newOp", dynlib: dllname.}
+proc buildTree(x: int): PNode {.importc: "buildTree", dynlib: dllname.}
+
+proc eval(n: PNode): int =
+  case n.k
+  of nkLit: result = n.x
+  of nkSub: result = eval(n.a) - eval(n.b)
+  of nkAdd: result = eval(n.a) + eval(n.b)
+  of nkDiv: result = eval(n.a) div eval(n.b)
+  of nkMul: result = eval(n.a) * eval(n.b)
+
+# Test the GC:
+for i in 0..100_000:
+  discard eval(buildTree(2))
+
+# bug https://forum.nim-lang.org/t/8176; Error: ambiguous identifier: 'nimrtl'
+import std/strutils
+doAssert join(@[1, 2]) == "12"
+doAssert join(@[1.5, 2.5]) == "1.52.5"
+doAssert join(@["a", "bc"]) == "abc"
diff --git a/tests/dll/client.nim.cfg b/tests/dll/client.nim.cfg
new file mode 100644
index 000000000..0e044a829
--- /dev/null
+++ b/tests/dll/client.nim.cfg
@@ -0,0 +1 @@
+--define:useNimRtl
diff --git a/tests/dll/nimhcr_0.nim b/tests/dll/nimhcr_0.nim
new file mode 100644
index 000000000..fe0b29a36
--- /dev/null
+++ b/tests/dll/nimhcr_0.nim
@@ -0,0 +1,4 @@
+
+let g_0 = 1000 # new value! but also a "new" global :)
+
+proc getInt*(): int = return g_0
diff --git a/tests/dll/nimhcr_0_1.nim b/tests/dll/nimhcr_0_1.nim
new file mode 100644
index 000000000..620050be3
--- /dev/null
+++ b/tests/dll/nimhcr_0_1.nim
@@ -0,0 +1,14 @@
+
+import hotcodereloading
+
+let g_0 = 42 # lets start with the ultimate answer
+
+proc getInt*(): int = return g_0
+
+programResult = 0 # should be accessible
+
+beforeCodeReload:
+  echo "   0: before"
+afterCodeReload:
+  echo "   0: after"
+  
\ No newline at end of file
diff --git a/tests/dll/nimhcr_0_2.nim b/tests/dll/nimhcr_0_2.nim
new file mode 100644
index 000000000..9ce228dc1
--- /dev/null
+++ b/tests/dll/nimhcr_0_2.nim
@@ -0,0 +1,18 @@
+
+import hotcodereloading
+
+import nimhcr_1 # new import!
+
+# global scope for this module was executed when loading the program
+# with a previous version which didn't contain this print statement
+echo "   0: I SHOULDN'T BE PRINTED!"
+
+var g_0 = 0 # changed value but won't take effect
+
+proc getInt*(): int = return g_0 + g_1 + f_1()
+
+beforeCodeReload:
+  echo "   0: before - improved!" # changed handlers!
+afterCodeReload:
+  echo "   0: after - improved!"
+  g_0 = 100 # we cannot change it in its initialization but we can in the 'after' handler!
diff --git a/tests/dll/nimhcr_0_3.nim b/tests/dll/nimhcr_0_3.nim
new file mode 100644
index 000000000..183424e11
--- /dev/null
+++ b/tests/dll/nimhcr_0_3.nim
@@ -0,0 +1,19 @@
+
+import hotcodereloading
+
+import nimhcr_1
+import nimhcr_2 # a new and different import!
+
+proc makeCounter*(): auto =
+  return iterator: int {.closure.} =
+    for i in countup(0, 10, 1):
+      yield i
+
+let c = makeCounter()
+
+afterCodeReload:
+  echo "   0: after - closure iterator: ", c()
+  echo "   0: after - closure iterator: ", c()
+  echo "   0: after - c_2 = ", c_2
+
+proc getInt*(): int = return g_1 + g_2.len
diff --git a/tests/dll/nimhcr_0_4.nim b/tests/dll/nimhcr_0_4.nim
new file mode 100644
index 000000000..4471782a7
--- /dev/null
+++ b/tests/dll/nimhcr_0_4.nim
@@ -0,0 +1,19 @@
+
+import hotcodereloading
+
+import nimhcr_1 # only importing 1
+
+let g_0 = 1000 # new value! but also a "new" global :)
+
+proc getInt*(): int = return g_0
+
+proc makeCounter*(): auto =
+  return iterator: int {.closure.} =
+    for i in countup(0, 10, 1):
+      yield i
+
+let c = makeCounter()
+
+afterCodeReload:
+  echo "   0: after - closure iterator! after reload! does it remember? :", c()
+  echo "   0: after - closure iterator! after reload! does it remember? :", c()
diff --git a/tests/dll/nimhcr_0_5.nim b/tests/dll/nimhcr_0_5.nim
new file mode 100644
index 000000000..aff4014ca
--- /dev/null
+++ b/tests/dll/nimhcr_0_5.nim
@@ -0,0 +1,2 @@
+
+proc getInt*(): int = return 42 # back to the answer...
diff --git a/tests/dll/nimhcr_0_6.nim b/tests/dll/nimhcr_0_6.nim
new file mode 100644
index 000000000..fe0b29a36
--- /dev/null
+++ b/tests/dll/nimhcr_0_6.nim
@@ -0,0 +1,4 @@
+
+let g_0 = 1000 # new value! but also a "new" global :)
+
+proc getInt*(): int = return g_0
diff --git a/tests/dll/nimhcr_1.nim b/tests/dll/nimhcr_1.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/dll/nimhcr_1.nim
diff --git a/tests/dll/nimhcr_1_1.nim b/tests/dll/nimhcr_1_1.nim
new file mode 100644
index 000000000..299c52baa
--- /dev/null
+++ b/tests/dll/nimhcr_1_1.nim
@@ -0,0 +1,51 @@
+
+echo "   1: print me once!"
+
+import hotcodereloading
+
+let g_1* = 8 # devilish!
+
+proc f_1*(): int =
+  var a {.global.} = 1
+  a.inc
+  return a
+
+
+# all these constructs should compile
+let some_glob_1 = 1
+echo "   1: ", some_glob_1
+if true:
+  let some_glob_2 = 2
+  echo "   1: ", some_glob_2
+  if true:
+    let some_glob_3 = 3
+    echo "   1: ", some_glob_3
+block:
+  let some_glob_4 = 4
+  proc inBlock(num: int) =
+    echo "   1: ", num
+  inBlock(some_glob_4)
+var counter = 3
+while counter > 0:
+  let some_glob_5 = 5
+  echo "   1: ", some_glob_5
+  counter.dec
+
+type
+  Type1 = object
+    a: int
+    b: int
+var t = Type1(a: 42, b: 11)
+echo "   1: Type1.a:", t.a
+
+type
+  obj = ref object
+    dat: int
+    str: string
+
+proc foo(): (int, obj) = (1, obj(dat: 3, str: "bar"))
+
+let (aa, bb) = foo()
+afterCodeReload:
+  echo aa
+  echo bb.str
diff --git a/tests/dll/nimhcr_1_2.nim b/tests/dll/nimhcr_1_2.nim
new file mode 100644
index 000000000..caf772450
--- /dev/null
+++ b/tests/dll/nimhcr_1_2.nim
@@ -0,0 +1,4 @@
+
+import nimhcr_2
+
+proc f_1*(): int = return f_2()
diff --git a/tests/dll/nimhcr_1_3.nim b/tests/dll/nimhcr_1_3.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/dll/nimhcr_1_3.nim
diff --git a/tests/dll/nimhcr_2.nim b/tests/dll/nimhcr_2.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/dll/nimhcr_2.nim
diff --git a/tests/dll/nimhcr_2_1.nim b/tests/dll/nimhcr_2_1.nim
new file mode 100644
index 000000000..705ed6d5a
--- /dev/null
+++ b/tests/dll/nimhcr_2_1.nim
@@ -0,0 +1,32 @@
+
+import hotcodereloading
+
+type
+  Type2 = ref object of RootObj
+    data*: int
+
+let g_2* = @[Type2(data: 2), Type2(data: 3)][1..^1] # should have a length of 1
+
+const c_2* = [1, 2, 3] # testing that a complext const object is properly exported
+
+var a: tuple[str: string, i: int]
+a.str = "   2: random string"
+echo a.str
+
+beforeCodeReload:
+  echo "   2: before!"
+
+# testing a construct of 2 functions in the same module which reference each other
+# https://github.com/nim-lang/Nim/issues/11608
+proc rec_1(depth: int)
+proc rec_2(depth: int) =
+  rec_1(depth + 1)
+proc rec_1(depth: int) =
+  if depth < 3:
+    rec_2(depth)
+  else:
+    echo("max mutual recursion reached!")
+
+# https://github.com/nim-lang/Nim/issues/11996
+let rec_2_func_ref = rec_2
+rec_2_func_ref(0)
diff --git a/tests/dll/nimhcr_2_2.nim b/tests/dll/nimhcr_2_2.nim
new file mode 100644
index 000000000..04ab2d3bb
--- /dev/null
+++ b/tests/dll/nimhcr_2_2.nim
@@ -0,0 +1,7 @@
+
+import hotcodereloading
+
+proc f_2*(): int = return 1
+
+afterCodeReload:
+  echo "   2: after!"
diff --git a/tests/dll/nimhcr_2_3.nim b/tests/dll/nimhcr_2_3.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/dll/nimhcr_2_3.nim
diff --git a/tests/dll/nimhcr_basic.nim b/tests/dll/nimhcr_basic.nim
new file mode 100644
index 000000000..2e1f39ae0
--- /dev/null
+++ b/tests/dll/nimhcr_basic.nim
@@ -0,0 +1,8 @@
+discard """
+  output: '''
+Hello world
+'''
+"""
+# for now orc only tests successful compilation
+
+echo "Hello world"
diff --git a/tests/dll/nimhcr_integration.nim b/tests/dll/nimhcr_integration.nim
new file mode 100644
index 000000000..ac34f1f85
--- /dev/null
+++ b/tests/dll/nimhcr_integration.nim
@@ -0,0 +1,170 @@
+discard """
+  disabled: "true"
+  output: '''
+main: HELLO!
+main: hasAnyModuleChanged? true
+main: before
+   0: after
+main: after
+              The answer is: 1000
+main: hasAnyModuleChanged? false
+              The answer is: 1000
+main: hasAnyModuleChanged? true
+   0: before
+main: before
+   1: print me once!
+   1: 1
+   1: 2
+   1: 3
+   1: 4
+   1: 5
+   1: 5
+   1: 5
+   1: Type1.a:42
+1
+bar
+   0: after - improved!
+main: after
+              The answer is: 110
+main: hasAnyModuleChanged? true
+   0: before - improved!
+main: before
+   2: random string
+max mutual recursion reached!
+1
+bar
+   0: after - closure iterator: 0
+   0: after - closure iterator: 1
+   0: after - c_2 = [1, 2, 3]
+main: after
+              The answer is: 9
+main: hasAnyModuleChanged? true
+   2: before!
+main: before
+   2: after!
+   0: after - closure iterator! after reload! does it remember? :2
+   0: after - closure iterator! after reload! does it remember? :3
+main: after
+              The answer is: 1000
+main: hasAnyModuleChanged? true
+main: before
+main: after
+              The answer is: 42
+done
+'''
+"""
+
+#[
+xxx disabled: "openbsd" because it would otherwise give:
+/home/build/Nim/lib/nimhcr.nim(532) hcrInit
+/home/build/Nim/lib/nimhcr.nim(503) initModules
+/home/build/Nim/lib/nimhcr.nim(463) initPointerData
+/home/build/Nim/lib/nimhcr.nim(346) hcrRegisterProc
+/home/build/Nim/lib/pure/reservedmem.nim(223) setLen
+/home/build/Nim/lib/pure/reservedmem.nim(97) setLen
+/home/build/Nim/lib/pure/includes/oserr.nim(94) raiseOSError
+Error: unhandled exception: Not supported [OSError]
+
+After instrumenting code, the stacktrace actually points to the call to `check mprotect`
+]#
+
+## This is perhaps the most complex test in the nim test suite - calling the
+## compiler on the file itself with the same set or arguments and reloading
+## parts of the program at runtime! In the same folder there are a few modules
+## with names such as `nimhcr_<number>.nim`. Each of them has a few versions which
+## are in the format of `nimhcr_<number>_<version>.nim`. The below code uses the
+## `update` proc to say which of the modules should bump its version (and that
+## is done by copying `nimhcr_<number>_<version>.nim` onto `nimhcr_<number>.nim`).
+## The files should refer to each other (when importing) without the versions.
+## A few files can be updated by calling `update` for each of their indexes
+## and after that with a single call to `compileReloadExecute` the new version
+## of the program will be compiled, reloaded, and the only thing the main module
+## calls from `nimhcr_0.nim` (the procedure `getInt` proc) is called for a result.
+##
+## This test is expected to be executed with arguments - the full nim compiler
+## command used for building it - so it can rebuild iself the same way - example:
+##
+## compiling:
+##                   nim c --hotCodeReloading:on --nimCache:<folder> <this_file>.nim
+## executing:
+##   <this_file>.exe nim c --hotCodeReloading:on --nimCache:<folder> <this_file>.nim
+
+import os, osproc, strutils, hotcodereloading
+
+import nimhcr_0 # getInt() - the only thing we continually call from the main module
+
+proc compileReloadExecute() =
+  # Remove the `--forceBuild` option - is there in the first place because:
+  # - when `koch test` is ran for the first time the nimcache is empty
+  # - when each of the variants are built (debug, release after that, different GCs)
+  #   the main executable that gets built into the appropriate nimcache folder
+  #   gets copied to the originally intended destination and is executed
+  #   (this behaviour is only when the --hotCodeReloading option is used).
+  # - when `koch test` is ran again and the nimcache is full the executable files
+  #   in the nimcache folder aren't relinked and therefore aren't copied to the
+  #   originally intended destination - so when the binary at the intended
+  #   destination is executed - it is actually a remnant from a previous execution.
+  #   That is a problem because it points to shared objects to load from its own
+  #   nimcache folder - the one used for building it - a previous run! And when
+  #   this test changes other modules it references but the main module (this file)
+  #   remains intact - the binary isn't replaced. `--forceBuild` fixes this but has
+  #   to be applied only for the main build - the one done from koch, but when this
+  #   binary triggers rebuilding itself here it shouldn't rebuild the main module -
+  #   that would lead to replacing the main binary executable which is running!
+  let cmd = commandLineParams()[0..^1].join(" ").replace(" --forceBuild")
+  doAssert cmd.len > 0
+  let (stdout, exitcode) = execCmdEx(cmd)
+  if exitcode != 0:
+    echo "COMPILATION ERROR!"
+    echo "COMMAND: ", cmd
+    echo "STDOUT: ", stdout
+    quit 1
+  echo "main: hasAnyModuleChanged? ", hasAnyModuleChanged()
+  performCodeReload()
+  echo "              The answer is: ", getInt()
+
+# there are 3 files and all of them start from their 1st version
+var vers = [1, 1, 1]
+proc update(file: int) =
+  proc getfile(mid: string): string =
+    let (path, _, _) = splitFile(currentSourcePath())
+    return path & "/nimhcr_" & mid & ".nim"
+  copyFile(getfile($file & "_" & $vers[file]), getfile($file))
+  inc vers[file]
+
+beforeCodeReload:
+  echo "main: before"
+
+afterCodeReload:
+  echo "main: after"
+
+echo "main: HELLO!"
+
+update 0
+compileReloadExecute() # versions are: 1 - -
+
+compileReloadExecute() # no change
+
+update 0
+update 1
+compileReloadExecute() # versions are: 2 1 -
+
+update 0
+update 2
+compileReloadExecute() # versions are: 3 1 1
+
+update 0
+update 1
+update 2
+compileReloadExecute() # versions are: 4 2 2
+
+update 0
+compileReloadExecute() # versions are: 5 2 2
+
+# final update so there are no git modifications left after everything
+# (the last versions are like the first files without a version suffix)
+update 0
+update 1
+update 2
+
+echo "done"
\ No newline at end of file
diff --git a/tests/dll/nimhcr_unit.nim b/tests/dll/nimhcr_unit.nim
new file mode 100644
index 000000000..249f3f9f1
--- /dev/null
+++ b/tests/dll/nimhcr_unit.nim
@@ -0,0 +1,149 @@
+discard """
+disabled: "openbsd"
+disabled: "netbsd"
+output: '''
+fastcall_proc implementation #1 10
+11
+fastcall_proc implementation #2 20
+22
+fastcall_proc implementation #2 20
+22
+fastcall_proc implementation #3 30
+33
+fastcall_proc implementation #3 30
+33
+fastcall_proc implementation #3 30
+33
+fastcall_proc implementation #3 40
+43
+cdecl_proc implementation #1 10
+11
+cdecl_proc implementation #2 20
+22
+cdecl_proc implementation #2 20
+22
+cdecl_proc implementation #3 30
+33
+cdecl_proc implementation #3 30
+33
+cdecl_proc implementation #3 30
+33
+cdecl_proc implementation #3 40
+43
+stdcall_proc implementation #1 10
+11
+stdcall_proc implementation #2 20
+22
+stdcall_proc implementation #2 20
+22
+stdcall_proc implementation #3 30
+33
+stdcall_proc implementation #3 30
+33
+stdcall_proc implementation #3 30
+33
+stdcall_proc implementation #3 40
+43
+noconv_proc implementation #1 10
+11
+noconv_proc implementation #2 20
+22
+noconv_proc implementation #2 20
+22
+noconv_proc implementation #3 30
+33
+noconv_proc implementation #3 30
+33
+noconv_proc implementation #3 30
+33
+noconv_proc implementation #3 40
+43
+inline_proc implementation #1 10
+11
+inline_proc implementation #2 20
+22
+inline_proc implementation #2 20
+22
+inline_proc implementation #3 30
+33
+inline_proc implementation #3 30
+33
+inline_proc implementation #3 30
+33
+inline_proc implementation #3 40
+43
+'''
+"""
+
+import macros
+
+macro carryOutTests(callingConv: untyped): untyped =
+  let
+    procName = $callingConv & "_proc"
+    globalName = $callingConv & "_global"
+    callingConv = callingConv
+    p1 = ident(procName & "1")
+    p2 = ident(procName & "2")
+    p3 = ident(procName & "3")
+    g1 = ident(globalName & "1")
+    g2 = ident(globalName & "2")
+
+  result = quote do:
+    var `g1`: pointer = nil
+    if hcrRegisterGlobal("dummy_module", `globalName`, sizeof(int), nil, addr `g1`):
+      cast[ptr int](`g1`)[] = 10
+
+    var `g2`: pointer = nil
+    if hcrRegisterGlobal("dummy_module", `globalName`, sizeof(int), nil, addr `g2`):
+      cast[ptr int](`g2`)[] = 20
+
+    doAssert `g1` == `g2` and cast[ptr int](`g1`)[] == 10
+
+    type
+      F = proc (x: int): int {.placeholder.}
+
+    proc `p1`(x: int): int {.placeholder.}=
+      echo `procName`, " implementation #1 ", x
+      return x + 1
+
+    let fp1 = cast[F](hcrRegisterProc("dummy_module", `procName`, cast[pointer](`p1`)))
+    echo fp1(10)
+
+    proc `p2`(x: int): int {.placeholder.} =
+      echo `procName`, " implementation #2 ", x
+      return x + 2
+
+    let fp2 = cast[F](hcrRegisterProc("dummy_module", `procName`, cast[pointer](`p2`)))
+    echo fp1(20)
+    echo fp2(20)
+
+    proc `p3`(x: int): int {.placeholder.} =
+      echo `procName`, " implementation #3 ", x
+      return x + 3
+
+    let fp3 = cast[F](hcrRegisterProc("dummy_module", `procName`, cast[pointer](`p3`)))
+    echo fp1(30)
+    echo fp2(30)
+    echo fp3(30)
+
+    let fp4 = cast[F](hcrGetProc("dummy_module", `procName`))
+    echo fp4(40)
+
+  proc replacePlaceholderPragmas(n: NimNode) =
+    if n.kind == nnkPragma:
+      n[0] = callingConv
+    else:
+      for i in 0 ..< n.len:
+        replacePlaceholderPragmas n[i]
+
+  replacePlaceholderPragmas result
+  # echo result.treeRepr
+
+hcrAddModule("dummy_module")
+
+carryOutTests fastcall
+carryOutTests cdecl
+carryOutTests stdcall
+carryOutTests noconv
+carryOutTests inline
+
diff --git a/tests/dll/nimhcr_unit.nim.cfg b/tests/dll/nimhcr_unit.nim.cfg
new file mode 100644
index 000000000..b13c310d9
--- /dev/null
+++ b/tests/dll/nimhcr_unit.nim.cfg
@@ -0,0 +1,2 @@
+-d:useNimRtl
+-d:testNimHcr
diff --git a/tests/dll/server.nim b/tests/dll/server.nim
new file mode 100644
index 000000000..dd4606298
--- /dev/null
+++ b/tests/dll/server.nim
@@ -0,0 +1,27 @@
+discard """
+action: compile
+  cmd: "nim $target --debuginfo --hints:on --define:useNimRtl --app:lib $options $file"
+batchable: false
+"""
+
+type
+  TNodeKind = enum nkLit, nkSub, nkAdd, nkDiv, nkMul
+  TNode = object
+    case k: TNodeKind
+    of nkLit: x: int
+    else: a, b: ref TNode
+
+  PNode = ref TNode
+
+proc newLit(x: int): PNode {.exportc: "newLit", dynlib.} =
+  result = PNode(k: nkLit, x: x)
+
+proc newOp(k: TNodeKind, a, b: PNode): PNode {.exportc: "newOp", dynlib.} =
+  assert a != nil
+  assert b != nil
+  result = PNode(k: nkSub, a: a, b: b)
+  # now overwrite with the real value:
+  result.k = k
+
+proc buildTree(x: int): PNode {.exportc: "buildTree", dynlib.} =
+  result = newOp(nkMul, newOp(nkAdd, newLit(x), newLit(x)), newLit(x))
diff --git a/tests/dll/server.nim.cfg b/tests/dll/server.nim.cfg
new file mode 100644
index 000000000..02393ba8b
--- /dev/null
+++ b/tests/dll/server.nim.cfg
@@ -0,0 +1,2 @@
+--define:useNimRtl
+--app:lib
diff --git a/tests/dll/test_nimhcr_integration.bat b/tests/dll/test_nimhcr_integration.bat
new file mode 100644
index 000000000..66e6beac4
--- /dev/null
+++ b/tests/dll/test_nimhcr_integration.bat
@@ -0,0 +1,10 @@
+set NIM=nim
+set NIM_FLAGS=-d:debug
+
+%NIM% c --outdir:"." %NIM_FLAGS% ../../lib/nimrtl.nim
+%NIM% c --outdir:"." %NIM_FLAGS% ../../lib/nimhcr.nim
+
+set HCR_FLAGS=--forceBuild --hotCodeReloading:on --nimcache:nimcache %NIM_FLAGS%
+
+%NIM% %HCR_FLAGS% c nimhcr_integration.nim
+nimhcr_integration %NIM% %HCR_FLAGS% c nimhcr_integration.nim
diff --git a/tests/dll/test_nimhcr_integration.sh b/tests/dll/test_nimhcr_integration.sh
new file mode 100755
index 000000000..a2e2d0483
--- /dev/null
+++ b/tests/dll/test_nimhcr_integration.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+rm -rf nimcache
+
+NIM_FLAGS=${*:- -d:debug}
+NIM=nim
+
+$NIM c --outdir:"." $NIM_FLAGS ../../lib/nimrtl.nim
+$NIM c --outdir:"." $NIM_FLAGS ../../lib/nimhcr.nim
+
+echo ===== Compiling HCR Integration Test =====
+HCR_FLAGS="--forceBuild --hotCodeReloading:on --nimcache:nimcache $NIM_FLAGS"
+$NIM $HCR_FLAGS c nimhcr_integration.nim
+export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH
+./nimhcr_integration $NIM $HCR_FLAGS c nimhcr_integration.nim
diff --git a/tests/dll/visibility.nim b/tests/dll/visibility.nim
new file mode 100644
index 000000000..ec15dad29
--- /dev/null
+++ b/tests/dll/visibility.nim
@@ -0,0 +1,43 @@
+discard """
+  output: ""
+"""
+
+const LibName {.used.} =
+  when defined(windows):
+    "visibility.dll"
+  elif defined(macosx):
+    "libvisibility.dylib"
+  else:
+    "libvisibility.so"
+
+when compileOption("app", "lib"):
+  var
+    bar {.exportc.}: int
+    thr {.exportc, threadvar.}: int
+  proc foo() {.exportc.} = discard
+
+  var
+    exported {.exportc, dynlib.}: int
+    exported_thr {.exportc, threadvar, dynlib.}: int
+  proc exported_func() {.exportc, dynlib.} = discard
+elif isMainModule:
+  import dynlib
+
+  let handle = loadLib(LibName)
+
+  template check(sym: untyped) =
+    const s = astToStr(sym)
+    if handle.symAddr(s) != nil:
+      echo s, " is exported"
+  template checkE(sym: untyped) =
+    const s = astToStr(sym)
+    if handle.symAddr(s) == nil:
+      echo s, " is not exported"
+
+  check foo
+  check bar
+  check thr
+
+  checkE exported
+  checkE exported_thr
+  checkE exported_func
diff --git a/tests/dummy.txt b/tests/dummy.txt
new file mode 100644
index 000000000..64cd361f9
--- /dev/null
+++ b/tests/dummy.txt
@@ -0,0 +1 @@
+Just a simple text for test
\ No newline at end of file
diff --git a/tests/ecmas.nim b/tests/ecmas.nim
deleted file mode 100755
index 59e7ae1e8..000000000
--- a/tests/ecmas.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-# This file tests the ECMAScript generator
-
-import
-  dom, strutils
-
-# We need to declare the used elements here. This is annoying but
-# prevents any kind of typo:
-var
-  inputElement {.importc: "document.form1.input", nodecl.}: ref TElement
-
-proc OnButtonClick() {.exportc.} =
-  var x: int = parseInt($inputElement.value)
-  echo($(x * x))
-
-proc OnLoad() {.exportc.} = 
-  echo("Welcome! Please take your time to fill in this formular!")
diff --git a/tests/effects/tcast_as_pragma.nim b/tests/effects/tcast_as_pragma.nim
new file mode 100644
index 000000000..1de61333e
--- /dev/null
+++ b/tests/effects/tcast_as_pragma.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim c $file"
+  action: "compile"
+"""
+
+proc taggy() {.tags: RootEffect.} = discard
+
+proc m {.raises: [], tags: [].} =
+  {.cast(noSideEffect).}:
+    echo "hi"
+
+  {.cast(raises: []).}:
+    raise newException(ValueError, "bah")
+
+  {.cast(tags: []).}:
+    taggy()
+
+m()
diff --git a/tests/effects/tdiagnostic_messages.nim b/tests/effects/tdiagnostic_messages.nim
new file mode 100644
index 000000000..b1acf8c5c
--- /dev/null
+++ b/tests/effects/tdiagnostic_messages.nim
@@ -0,0 +1,37 @@
+discard """
+  nimoutFull: true
+  action: "reject"
+  cmd: "nim r --hint:Conf:off $file"
+  nimout: '''
+tdiagnostic_messages.nim(36, 6) Error: 'a' can have side effects
+> tdiagnostic_messages.nim(37, 30) Hint: 'a' calls `.sideEffect` 'callWithSideEffects'
+>> tdiagnostic_messages.nim(29, 6) Hint: 'callWithSideEffects' called by 'a'
+>>> tdiagnostic_messages.nim(31, 34) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaVarParam'
+>>>> tdiagnostic_messages.nim(25, 6) Hint: 'indirectCallViaVarParam' called by 'callWithSideEffects'
+>>>>> tdiagnostic_messages.nim(26, 7) Hint: 'indirectCallViaVarParam' calls routine via hidden pointer indirection
+>>> tdiagnostic_messages.nim(32, 33) Hint: 'callWithSideEffects' calls `.sideEffect` 'indirectCallViaPointer'
+>>>> tdiagnostic_messages.nim(27, 6) Hint: 'indirectCallViaPointer' called by 'callWithSideEffects'
+>>>>> tdiagnostic_messages.nim(28, 32) Hint: 'indirectCallViaPointer' calls routine via pointer indirection
+>>> tdiagnostic_messages.nim(33, 3) Hint: 'callWithSideEffects' calls `.sideEffect` 'myEcho'
+>>>> tdiagnostic_messages.nim(24, 6) Hint: 'myEcho' called by 'callWithSideEffects'
+>>> tdiagnostic_messages.nim(34, 3) Hint: 'callWithSideEffects' accesses global state 'globalVar'
+>>>> tdiagnostic_messages.nim(23, 5) Hint: 'globalVar' accessed by 'callWithSideEffects'
+
+'''
+"""
+
+var globalVar = 0
+proc myEcho(a: string) {.sideEffect.} = discard
+proc indirectCallViaVarParam(call: var proc(): int {.nimcall.}): int =
+  call()
+proc indirectCallViaPointer(call: pointer): int =
+  cast[ptr proc(): int](call)[]()
+proc callWithSideEffects(): int =
+  var p = proc (): int {.nimcall.} = 0
+  discard indirectCallViaVarParam(p)
+  discard indirectCallViaPointer(addr p)
+  myEcho ""
+  globalVar
+
+func a: int =
+  discard callWithSideEffects()
diff --git a/tests/effects/teffects1.nim b/tests/effects/teffects1.nim
new file mode 100644
index 000000000..1d267b5fa
--- /dev/null
+++ b/tests/effects/teffects1.nim
@@ -0,0 +1,47 @@
+discard """
+  cmd: "nim check --hint:Conf:off --hint:XDeclaredButNotUsed:off $file"
+  nimout: '''
+teffects1.nim(17, 28) template/generic instantiation from here
+'''
+"""
+{.push warningAsError[Effect]: on.}
+type
+  TObj {.pure, inheritable.} = object
+  TObjB = object of TObj
+    a, b, c: string
+
+  IO2Error = ref object of IOError
+
+proc forw: int {. .}
+
+proc lier(): int {.raises: [IO2Error].} = #[tt.Hint
+                            ^ 'lier' cannot raise 'IO2Error' [XCannotRaiseY] ]#
+  writeLine stdout, "arg" #[tt.Error
+  ^ writeLine stdout, ["arg"] can raise an unlisted exception: ref IOError ]#
+
+proc forw: int =
+  raise newException(IOError, "arg")
+
+block:
+  proc someProc(t: string) {.raises: [Defect].} =
+    discard
+  let vh: proc(topic: string) {.raises: [].} = someProc
+
+{.push raises: [Defect].}
+
+type
+  MyProcType* = proc(x: int): string #{.raises: [ValueError, Defect].}
+
+proc foo(x: int): string {.nimcall, raises: [ValueError].} =
+  if x > 9:
+    raise newException(ValueError, "Use single digit")
+  $x
+
+var p: MyProcType = foo #[tt.Error
+                    ^
+type mismatch: got <proc (x: int): string{.nimcall, raises: [ValueError], noSideEffect, gcsafe.}> but expected 'MyProcType = proc (x: int): string{.closure.}'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+.raise effects differ
+]#
+{.pop.}
+{.pop.}
diff --git a/tests/effects/teffects10.nim b/tests/effects/teffects10.nim
new file mode 100644
index 000000000..8193b394a
--- /dev/null
+++ b/tests/effects/teffects10.nim
@@ -0,0 +1,12 @@
+discard """
+action: compile
+"""
+
+# https://github.com/nim-lang/Nim/issues/15495
+
+proc f() {.raises: [].} =
+  var a: proc ()
+  var b: proc ()
+  swap(a, b)
+
+f()
diff --git a/tests/effects/teffects11.nim b/tests/effects/teffects11.nim
new file mode 100644
index 000000000..20b7026ab
--- /dev/null
+++ b/tests/effects/teffects11.nim
@@ -0,0 +1,21 @@
+discard """
+action: compile
+errormsg: "type mismatch: got <proc (x: int){.gcsafe.}>"
+line: 21
+"""
+
+type
+  Effect1 = object
+  Effect2 = object
+  Effect3 = object
+
+proc test(fnc: proc(x: int): void {.forbids: [Effect2].}) {.tags: [Effect1, Effect3, RootEffect].} =
+  fnc(1)
+
+proc t1(x: int): void = echo $x
+proc t2(x: int): void {.tags: [Effect2].} = echo $x
+proc t3(x: int): void {.tags: [Effect3].} = echo $x
+
+test(t1)
+test(t3)
+test(t2)
diff --git a/tests/effects/teffects12.nim b/tests/effects/teffects12.nim
new file mode 100644
index 000000000..5f5499c38
--- /dev/null
+++ b/tests/effects/teffects12.nim
@@ -0,0 +1,52 @@
+discard """
+action: compile
+"""
+
+import std/locks
+
+type
+  Test2Effect* = object
+  Test2* = object
+    value2*: int
+  Test1Effect* = object
+  Test1* = object
+    value1*: int
+  Main* = object
+    test1Lock: Lock
+    test1: Test1
+    test2Lock: Lock
+    test2: Test2
+
+proc `=copy`(obj1: var Test2, obj2: Test2) {.error.}
+proc `=copy`(obj1: var Test1, obj2: Test1) {.error.}
+proc `=copy`(obj1: var Main, obj2: Main) {.error.}
+
+proc withTest1(main: var Main,
+               fn: proc(test1: var Test1) {.gcsafe, forbids: [Test1Effect].}) {.gcsafe, tags: [Test1Effect, RootEffect].} =
+  withLock(main.test1Lock):
+    fn(main.test1)
+
+proc withTest2(main: var Main,
+               fn: proc(test1: var Test2) {.gcsafe, forbids: [Test2Effect].}) {.gcsafe, tags: [Test2Effect, RootEffect].} =
+  withLock(main.test2Lock):
+    fn(main.test2)
+
+proc newMain(): Main =
+  var test1lock: Lock
+  initLock(test1Lock)
+  var test2lock: Lock
+  initLock(test2Lock)
+  var main = Main(test1Lock: move(test1Lock), test1: Test1(value1: 1),
+                  test2Lock: move(test2Lock), test2: Test2(value2: 2))
+  main.withTest1(proc(test1: var Test1) = test1.value1 += 1)
+  main.withTest2(proc(test2: var Test2) = test2.value2 += 1)
+  move main
+
+var main = newMain()
+main.withTest1(proc(test1: var Test1) =
+  test1.value1 += 1
+  main.withTest2(proc(test2: var Test2) = test2.value2 += 1)
+)
+
+main.withTest1(proc(test1: var Test1) {.tags: [].} = echo $test1.value1)
+main.withTest2(proc(test2: var Test2) {.tags: [].} = echo $test2.value2)
diff --git a/tests/effects/teffects13.nim b/tests/effects/teffects13.nim
new file mode 100644
index 000000000..73082f997
--- /dev/null
+++ b/tests/effects/teffects13.nim
@@ -0,0 +1,19 @@
+discard """
+action: compile
+errormsg: "writeSomething() has an illegal effect: WriteIO"
+line: 19
+"""
+
+type
+  IO = object of RootEffect ## input/output effect
+  ReadIO = object of IO     ## input effect
+  WriteIO = object of IO    ## output effect
+
+proc readSomething(): string {.tags: [ReadIO].} = ""
+proc writeSomething(): void {.tags: [WriteIO].} = echo "..."
+
+proc noWritesPlease() {.forbids: [WriteIO].} =
+  # this is OK:
+  echo readSomething()
+  # the compiler prevents this:
+  writeSomething()
diff --git a/tests/effects/teffects14.nim b/tests/effects/teffects14.nim
new file mode 100644
index 000000000..6291d9569
--- /dev/null
+++ b/tests/effects/teffects14.nim
@@ -0,0 +1,15 @@
+discard """
+action: compile
+errormsg: "func1() has an illegal effect: IO"
+line: 15
+"""
+
+type IO = object ## input/output effect
+proc func1(): string {.tags: [IO].} = discard
+proc func2(): string = discard
+
+proc no_IO_please() {.forbids: [IO].} =
+  # this is OK because it didn't define any tag:
+  discard func2()
+  # the compiler prevents this:
+  let y = func1()
diff --git a/tests/effects/teffects15.nim b/tests/effects/teffects15.nim
new file mode 100644
index 000000000..c3079cdbc
--- /dev/null
+++ b/tests/effects/teffects15.nim
@@ -0,0 +1,18 @@
+discard """
+action: compile
+errormsg: "method1(c) has an illegal effect: IO"
+line: 18
+"""
+
+type
+  IO = object ## input/output effect
+  CustomObject* = object of RootObj
+    text: string
+
+method method1(obj: var CustomObject): string {.tags: [IO].} = obj.text & "."
+method method2(obj: var CustomObject): string = obj.text & ":"
+
+proc noIO() {.forbids: [IO].} =
+  var c = CustomObject(text: "a")
+  echo c.method2()
+  echo c.method1()
diff --git a/tests/effects/teffects16.nim b/tests/effects/teffects16.nim
new file mode 100644
index 000000000..ee8f782a3
--- /dev/null
+++ b/tests/effects/teffects16.nim
@@ -0,0 +1,20 @@
+discard """
+action: compile
+errormsg: "writeSomething(\"a\") can have an unlisted effect: WriteIO"
+line: 20
+"""
+
+type
+  IO = object of RootEffect ## input/output effect
+  ReadIO = object of IO     ## input effect
+  WriteIO = object of IO    ## output effect
+  LogIO = object of IO      ## another output effect
+
+proc readSomething(): string {.tags: [ReadIO].} = ""
+proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg
+proc logSomething(msg: string): void {.tags: [LogIo].} = echo msg
+
+proc noWritesPlease() {.forbids: [WriteIO], tags: [LogIO, ReadIO].} =
+  echo readSomething()
+  logSomething("a")
+  writeSomething("a")
diff --git a/tests/effects/teffects17.nim b/tests/effects/teffects17.nim
new file mode 100644
index 000000000..5e6b83896
--- /dev/null
+++ b/tests/effects/teffects17.nim
@@ -0,0 +1,17 @@
+discard """
+action: compile
+errormsg: "writeSomething(\"a\") has an illegal effect: WriteIO"
+line: 17
+"""
+
+type
+  IO = object of RootEffect ## input/output effect
+  ReadIO = object of IO     ## input effect
+  WriteIO = object of IO    ## output effect
+
+proc readSomething(): string {.tags: [ReadIO].} = ""
+proc writeSomething(msg: string): void {.tags: [WriteIO].} = echo msg
+
+proc illegalEffectNegation() {.forbids: [WriteIO], tags: [ReadIO, WriteIO].} =
+  echo readSomething()
+  writeSomething("a")
diff --git a/tests/effects/teffects18.nim b/tests/effects/teffects18.nim
new file mode 100644
index 000000000..576e76635
--- /dev/null
+++ b/tests/effects/teffects18.nim
@@ -0,0 +1,19 @@
+discard """
+action: compile
+errormsg: "type mismatch: got <ProcType2>"
+line: 19
+"""
+
+type MyEffect = object
+type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
+type ProcType2 = proc (i: int): void
+
+proc testFunc(p: ProcType1): void = p(1)
+
+proc toBeCalled(i: int): void {.tags: [MyEffect].} = echo $i
+
+let emptyTags = proc(i: int): void {.tags: [].} = echo $i
+let noTags: ProcType2 = proc(i: int): void = toBeCalled(i)
+
+testFunc(emptyTags)
+testFunc(noTags)
diff --git a/tests/effects/teffects19.nim b/tests/effects/teffects19.nim
new file mode 100644
index 000000000..6b4ab0819
--- /dev/null
+++ b/tests/effects/teffects19.nim
@@ -0,0 +1,23 @@
+discard """
+action: compile
+errormsg: "type mismatch: got <proc (i: int){.gcsafe.}>"
+line: 23
+"""
+
+type MyEffect = object
+type ProcType1 = proc (i: int): void {.forbids: [MyEffect].}
+type ProcType2 = proc (i: int): void
+
+proc caller1(p: ProcType1): void = p(1)
+proc caller2(p: ProcType2): void = p(1)
+
+proc effectful(i: int): void {.tags: [MyEffect].} = echo $i
+proc effectless(i: int): void {.forbids: [MyEffect].} = echo $i
+
+proc toBeCalled1(i: int): void = effectful(i)
+proc toBeCalled2(i: int): void = effectless(i)
+
+caller1(toBeCalled2)
+caller2(toBeCalled1)
+caller2(toBeCalled2)
+caller1(toBeCalled1)
diff --git a/tests/effects/teffects2.nim b/tests/effects/teffects2.nim
new file mode 100644
index 000000000..777a4cebc
--- /dev/null
+++ b/tests/effects/teffects2.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "can raise an unlisted exception: ref IOError"
+  line: 19
+"""
+{.push warningAsError[Effect]: on.}
+type
+  TObj {.pure, inheritable.} = object
+  TObjB = object of TObj
+    a, b, c: string
+
+  EIO2 = ref object of IOError
+
+proc forw: int {.raises: [].}
+
+proc lier(): int {.raises: [IOError].} =
+  writeLine stdout, "arg"
+
+proc forw: int =
+  raise newException(IOError, "arg")
+{.pop.}
diff --git a/tests/effects/teffects3.nim b/tests/effects/teffects3.nim
new file mode 100644
index 000000000..4c050510a
--- /dev/null
+++ b/tests/effects/teffects3.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "type mismatch"
+  line: 18
+"""
+
+type
+  TObj {.pure, inheritable.} = object
+  TObjB = object of TObj
+    a, b, c: string
+    fn: proc (): int {.tags: [].}
+
+
+
+proc raiser(): int {.tags: [TObj, WriteIoEffect].} =
+  writeLine stdout, "arg"
+
+var o: TObjB
+o.fn = raiser
diff --git a/tests/effects/teffects4.nim b/tests/effects/teffects4.nim
new file mode 100644
index 000000000..b875754b6
--- /dev/null
+++ b/tests/effects/teffects4.nim
@@ -0,0 +1,23 @@
+discard """
+  errormsg: "type mismatch"
+  line: 23
+"""
+
+type
+  TObj {.pure, inheritable.} = object
+  TObjB = object of TObj
+    a, b, c: string
+    fn: proc (): int {.tags: [ReadIOEffect].}
+
+
+
+proc q() {.tags: [IoEffect].} =
+  discard
+
+proc raiser(): int =
+  writeLine stdout, "arg"
+  if true:
+    q()
+
+var o: TObjB
+o.fn = raiser
diff --git a/tests/effects/teffects5.nim b/tests/effects/teffects5.nim
new file mode 100644
index 000000000..779b4662c
--- /dev/null
+++ b/tests/effects/teffects5.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "type mismatch"
+  line: 7
+"""
+
+proc p(q: proc() ): proc() {.tags: [], raises: [], closure.} =
+  return proc () =
+    q()
+
+let yay = p(proc () = raise newException(EIO, "IO"))
+
+proc main() {.raises: [], tags: [].} = yay()
+
+main()
diff --git a/tests/effects/teffects6.nim b/tests/effects/teffects6.nim
new file mode 100644
index 000000000..d3af22434
--- /dev/null
+++ b/tests/effects/teffects6.nim
@@ -0,0 +1,56 @@
+discard """
+action: compile
+"""
+
+# XXX: it is not actually tested if the effects are inferred
+
+type
+  PMenu = ref object
+  PMenuItem = ref object
+
+proc createMenuItem*(menu: PMenu, label: string,
+                    action: proc (i: PMenuItem, p: pointer) {.cdecl.}) = discard
+
+var s: PMenu
+createMenuItem(s, "Go to definition...",
+      proc (i: PMenuItem, p: pointer) {.cdecl.} =
+        try:
+          echo(i.repr)
+        except ValueError:
+          echo("blah")
+)
+
+
+proc noRaise(x: proc()) {.raises: [], effectsOf: x.} =
+  # unknown call that might raise anything, but valid:
+  x()
+
+proc doRaise() {.raises: [IoError].} =
+  raise newException(IoError, "IO")
+
+proc use*() =
+  noRaise(doRaise)
+  # Here the compiler inferes that EIO can be raised.
+
+
+use()
+
+# bug #12642
+import os
+
+proc raises() {.raises: Exception.} = discard
+proc harmless() {.raises: [].} = discard
+
+let x = if paramStr(1) == "true": harmless else: raises
+
+let
+  choice = 0
+
+proc withoutSideEffects(): int = 0
+proc withSideEffects(): int = echo "foo" # the echo causes the side effect
+
+let procPtr = case choice
+              of 0: withoutSideEffects
+              else: withSideEffects
+
+echo procPtr.repr
diff --git a/tests/effects/teffects7.nim b/tests/effects/teffects7.nim
new file mode 100644
index 000000000..9b7fbf5f0
--- /dev/null
+++ b/tests/effects/teffects7.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "can raise an unlisted exception: ref ValueError"
+  line: 10
+"""
+{.push warningAsError[Effect]: on.}
+proc foo() {.raises: [].} =
+  try:
+    discard
+  except KeyError:
+    raise newException(ValueError, "foo")
+  except Exception:
+    discard
+
+foo()
+
+{.pop.}
diff --git a/tests/effects/teffects8.nim b/tests/effects/teffects8.nim
new file mode 100644
index 000000000..359b3a1df
--- /dev/null
+++ b/tests/effects/teffects8.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "can raise an unlisted exception: Exception"
+  line: 10
+"""
+{.push warningAsError[Effect]: on.}
+proc foo() {.raises: [].} =
+  try:
+    discard
+  except ValueError:
+    raise
+
+foo()
+{.pop.}
diff --git a/tests/effects/teffects9.nim b/tests/effects/teffects9.nim
new file mode 100644
index 000000000..d92668fe9
--- /dev/null
+++ b/tests/effects/teffects9.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "can raise an unlisted exception: ref Exception"
+  line: 16
+"""
+
+# bug #8481
+
+type
+  ParentObj = ref object of RootObj
+  DerivedObj = ref object of ParentObj
+
+method doSome(o: ParentObj) {.base, raises: [].} =
+  discard
+
+method doSome(o: DerivedObj) =
+  raise newException(Exception, "oops, this raised")
+
+proc thisRaises() {.raises: [].} =
+  let o = new(DerivedObj)
+  o.doSome()
+
+thisRaises()
diff --git a/tests/effects/teffectsmisc.nim b/tests/effects/teffectsmisc.nim
new file mode 100644
index 000000000..8fb95b275
--- /dev/null
+++ b/tests/effects/teffectsmisc.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+printing from adder
+'''
+"""
+
+import std/sugar
+
+block:
+  proc makeAdder(a: int): (int) -> void =
+    proc discard_adder(x: int) {.closure.} =
+      discard a + x
+
+    proc echo_adder(x: int) {.closure.} =
+      echo("printing from adder")
+
+    if a > 0:
+      discard_adder
+    else:
+      echo_adder
+
+  let newAdder = makeAdder(0)
+  newAdder(5)
+
+block:
+  proc makeAdder(a: int): (int) -> void =
+    proc discard_adder(x: int) {.closure.} =
+      discard a + x
+
+    proc echo_adder(x: int) {.closure.} =
+      echo("printing from adder")
+
+    if a > 0:
+      echo_adder
+    else:
+      discard_adder
+
+  let newAdder = makeAdder(0)
+  newAdder(5)
diff --git a/tests/effects/tfuncs_cannot_mutate.nim b/tests/effects/tfuncs_cannot_mutate.nim
new file mode 100644
index 000000000..9934d27a7
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate.nim
@@ -0,0 +1,35 @@
+discard """
+  errormsg: "cannot mutate location select(x, z).data within a strict func"
+  line: 35
+"""
+
+{.experimental: "strictFuncs".}
+
+type
+  Node = ref object
+    le, ri: Node
+    data: string
+
+func insert(x: var seq[Node]; yyy: Node) =
+  let L = x.len
+  x.setLen L + 1
+  x[L] = yyy
+
+func len(n: Node): int =
+  var it = n
+  while it != nil:
+    inc result
+    it = it.ri
+
+func doNotDistract(n: Node) =
+  var m = Node(data: "abc")
+
+func select(a, b: Node): Node = b
+
+func mutate(n: Node) =
+  var it = n
+  let x = it
+  let y = x
+  let z = y
+
+  select(x, z).data = "tricky"
diff --git a/tests/effects/tfuncs_cannot_mutate2.nim b/tests/effects/tfuncs_cannot_mutate2.nim
new file mode 100644
index 000000000..86f811017
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate2.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "cannot mutate location x[0].a within a strict func"
+  line: 12
+"""
+
+{.experimental: "strictFuncs".}
+
+func copy[T](x: var openArray[T]; y: openArray[T]) =
+  for i in 0..high(x):
+    x[i] = y[i]
+
+  x[0].a = nil
+
+type
+  R = ref object
+    a, b: R
+    data: string
+
+proc main =
+  var a, b: array[3, R]
+  b = [R(data: "a"), R(data: "b"), R(data: "c")]
+  copy a, b
+
+main()
diff --git a/tests/effects/tfuncs_cannot_mutate3.nim b/tests/effects/tfuncs_cannot_mutate3.nim
new file mode 100644
index 000000000..029152029
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate3.nim
@@ -0,0 +1,35 @@
+discard """
+  errormsg: "cannot mutate location kid.parent within a strict func"
+  line: 16
+"""
+
+{.experimental: "strictFuncs".}
+
+type
+  Node = ref object
+    name: string
+    kids: seq[Node]
+    parent: Node
+
+func initParents(tree: Node) =
+  for kid in tree.kids:
+    kid.parent = tree
+    initParents(kid)
+
+proc process(intro: Node): Node =
+  var tree = Node(name: "root", kids: @[
+    intro,
+    Node(name: "one", kids: @[
+      Node(name: "two"),
+      Node(name: "three"),
+    ]),
+    Node(name: "four"),
+  ])
+  initParents(tree)
+
+proc main() =
+  var intro = Node(name: "intro")
+  var tree = process(intro)
+  echo intro.parent.name
+
+main()
diff --git a/tests/effects/tfuncs_cannot_mutate_simple.nim b/tests/effects/tfuncs_cannot_mutate_simple.nim
new file mode 100644
index 000000000..0ae4a0db9
--- /dev/null
+++ b/tests/effects/tfuncs_cannot_mutate_simple.nim
@@ -0,0 +1,19 @@
+discard """
+  errormsg: '''cannot mutate location x.data within a strict func'''
+  line: 15
+"""
+
+{.experimental: "strictFuncs".}
+
+# bug #15508
+
+type
+  MyType = ref object
+    data: string
+
+func edit(x: MyType) =
+  x.data = "hello"
+
+let x = MyType()
+x.edit()
+echo x.data
diff --git a/tests/effects/tgcsafe.nim b/tests/effects/tgcsafe.nim
new file mode 100644
index 000000000..cfac3ddd8
--- /dev/null
+++ b/tests/effects/tgcsafe.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "'mainUnsafe' is not GC-safe as it performs an indirect call here"
+  line: 26
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+# bug #6955
+var global_proc: proc(a: string): int {.nimcall.} = nil
+
+proc myproc(i: int) {.gcsafe.} =
+  if global_proc != nil:
+    echo "a"
+  if isNil(global_proc):
+    return
+
+proc mymap(x: proc ()) {.effectsOf: x.} =
+  x()
+
+var
+  myglob: string
+
+proc mainSafe() {.gcsafe.} =
+  mymap(proc () = echo "foo")
+
+proc mainUnsafe() {.gcsafe.} =
+  mymap(proc () = myglob = "bar"; echo "foo", myglob)
diff --git a/tests/effects/tgcsafe2.nim b/tests/effects/tgcsafe2.nim
new file mode 100644
index 000000000..6268592a9
--- /dev/null
+++ b/tests/effects/tgcsafe2.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: '''type mismatch: got <proc (s: string)>'''
+  line: 11
+"""
+#5620
+var res = ""
+
+proc takeCallback(foo: (proc(s: string) {.gcsafe.})) =
+  foo "string"
+
+takeCallback(proc (s: string) =
+  res &= s & "abc")
diff --git a/tests/effects/tgcsafe3.nim b/tests/effects/tgcsafe3.nim
new file mode 100644
index 000000000..36ea5112c
--- /dev/null
+++ b/tests/effects/tgcsafe3.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "'myproc' is not GC-safe as it calls 'global_proc'"
+  line: 12
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+var useGcMem = "string here"
+
+var global_proc: proc(a: string) {.nimcall.} = proc (a: string) =
+  echo useGcMem
+
+proc myproc(i: int) {.gcsafe.} =
+  when false:
+    if global_proc != nil:
+      echo "a"
+    if isNil(global_proc):
+      return
+
+  global_proc("ho")
+
+myproc(0)
diff --git a/tests/effects/thooks.nim b/tests/effects/thooks.nim
new file mode 100644
index 000000000..23cc005cd
--- /dev/null
+++ b/tests/effects/thooks.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "--warningAsError:Effect"
+"""
+
+import std/isolation
+
+# bug #23129
+type
+  Thing = object
+    x: string
+
+proc send(x: string) =
+  let wrapper = Thing(x: x)
+  discard isolate(wrapper)
+
+send("la")
\ No newline at end of file
diff --git a/tests/effects/tlaxeffects.nim b/tests/effects/tlaxeffects.nim
new file mode 100644
index 000000000..7eedc372a
--- /dev/null
+++ b/tests/effects/tlaxeffects.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim $target $options --legacy:laxEffects $file"
+"""
+
+
+type
+  Foo = object
+    bar: seq[Foo]
+
+proc `==`(a, b: Foo): bool =
+  a.bar == b.bar
diff --git a/tests/effects/tnestedprocs.nim b/tests/effects/tnestedprocs.nim
new file mode 100644
index 000000000..125896d44
--- /dev/null
+++ b/tests/effects/tnestedprocs.nim
@@ -0,0 +1,63 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects
+> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2'
+>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner'
+
+tnestedprocs.nim(45, 8) Error: 'inner' can have side effects
+> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6'
+>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner'
+
+tnestedprocs.nim(58, 41) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
+  Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
+'''
+  errormsg: "type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'"
+"""
+{.experimental: "strictEffects".}
+proc outer {.noSideEffect.} =
+  proc inner(p: int) =
+    if p == 0:
+      outer()
+
+  inner(4)
+
+outer()
+
+proc outer2 =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      outer2()
+
+  inner(4)
+
+outer2()
+
+proc outer3(p: int) {.noSideEffect.} =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      p.outer3()
+
+  inner(4)
+
+outer3(5)
+
+proc outer6 =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      outer6()
+
+  inner(4)
+  echo "bad"
+
+outer6()
+
+
+proc outer4 =
+  proc inner(p: int) {.noSideEffect.} =
+    if p == 0:
+      let x: proc () {.noSideEffect.} = outer4
+      x()
+
+  inner(4)
+
+outer4()
diff --git a/tests/effects/tnosideeffect.nim b/tests/effects/tnosideeffect.nim
new file mode 100644
index 000000000..9fc2f74d4
--- /dev/null
+++ b/tests/effects/tnosideeffect.nim
@@ -0,0 +1,24 @@
+block: # `.noSideEffect`
+  func foo(bar: proc(): int): int {.effectsOf: bar.} = bar()
+  var count = 0
+  proc fn1(): int = 1
+  proc fn2(): int = (count.inc; count)
+
+  template accept(body) =
+    doAssert compiles(block:
+      body)
+
+  template reject(body) =
+    doAssert not compiles(block:
+      body)
+
+  accept:
+    func fun1() = discard foo(fn1)
+  reject:
+    func fun1() = discard foo(fn2)
+
+  var foo2: type(foo) = foo
+  accept:
+    func main() = discard foo(fn1)
+  reject:
+    func main() = discard foo2(fn1)
diff --git a/tests/effects/tsidee1.nim b/tests/effects/tsidee1.nim
new file mode 100644
index 000000000..ca6816561
--- /dev/null
+++ b/tests/effects/tsidee1.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "\'SideEffectLyer\' can have side effects"
+  file: "tsidee1.nim"
+  line: 12
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int = return x + global
+
+proc SideEffectLyer(x, y: int): int {.noSideEffect.} = #ERROR_MSG 'SideEffectLyer' can have side effects
+  return x + y + dontcare(x)
+
+echo SideEffectLyer(1, 3)
diff --git a/tests/effects/tsidee2.nim b/tests/effects/tsidee2.nim
new file mode 100644
index 000000000..b2e5f3379
--- /dev/null
+++ b/tests/effects/tsidee2.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "5"
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int = return x
+
+proc SideEffectLyer(x, y: int): int {.noSideEffect.} =
+  return x + y + dontcare(x)
+
+echo SideEffectLyer(1, 3) #OUT 5
diff --git a/tests/effects/tsidee3.nim b/tests/effects/tsidee3.nim
new file mode 100644
index 000000000..c3801ba28
--- /dev/null
+++ b/tests/effects/tsidee3.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "5"
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int {.noSideEffect.} = return x
+
+proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} =
+  return x + y + dontcare(x)
+
+echo noSideEffect(1, 3, dontcare) #OUT 5
diff --git a/tests/effects/tsidee4.nim b/tests/effects/tsidee4.nim
new file mode 100644
index 000000000..d6c192cbf
--- /dev/null
+++ b/tests/effects/tsidee4.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "'noSideEffect' can have side effects"
+  file: "tsidee4.nim"
+  line: 12
+"""
+
+var
+  global: int
+
+proc dontcare(x: int): int = return global
+
+proc noSideEffect(x, y: int, p: proc (a: int): int {.noSideEffect.}): int {.noSideEffect.} =
+  return x + y + dontcare(x)
+
+echo noSideEffect(1, 3, dontcare) #ERROR_MSG type mismatch
diff --git a/tests/effects/tstrict_caseobjects.nim b/tests/effects/tstrict_caseobjects.nim
new file mode 100644
index 000000000..20bc810e0
--- /dev/null
+++ b/tests/effects/tstrict_caseobjects.nim
@@ -0,0 +1,47 @@
+discard """
+  errormsg: "field access outside of valid case branch: x.x"
+  line: 45
+"""
+
+{.experimental: "strictCaseObjects".}
+
+type
+  NodeKind = enum
+    nkParent,
+    nkChild
+  
+  Node {.acyclic.} = ref object
+    case kind: NodeKind
+    of nkParent:
+      children: seq[Node]
+    of nkChild:
+      name: string
+
+let list = @[Node(kind: nkParent, children: @[]), Node(kind: nkChild, name: "hello")]
+for node in list:
+  case node.kind
+  of nkChild: 
+    echo $node.name # here this time there is a warning
+  else: discard
+
+
+type
+  Foo = object
+    case b: bool
+    of false:
+      s: string
+    of true:
+      x: int
+
+var x = Foo(b: true, x: 4)
+case x.b
+of true:
+  echo x.x
+of false:
+  echo "no"
+
+case x.b
+of false:
+  echo x.x
+of true:
+  echo "no"
diff --git a/tests/effects/tstrict_effects.nim b/tests/effects/tstrict_effects.nim
new file mode 100644
index 000000000..eee8fb71a
--- /dev/null
+++ b/tests/effects/tstrict_effects.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "s1 can raise an unlisted exception: CatchableError"
+  line: 27
+"""
+
+{.push warningAsError[Effect]: on.}
+{.experimental: "strictEffects".}
+
+# bug #18376
+
+{.push raises: [Defect].}
+type Call = proc (x: int): int {.gcsafe, raises: [Defect, CatchableError].}
+
+type Bar* = object
+  foo*: Call
+
+proc passOn*(x: Call) = discard
+
+proc barCal(b: var Bar, s: string, s1: Call) =
+  #compiler complains that his line can throw CatchableError
+  passOn s1
+
+
+proc passOnB*(x: Call) {.effectsOf: x.} = discard
+
+proc barCal2(b: var Bar, s: string, s1: Call) =
+  passOnB s1
diff --git a/tests/effects/tstrict_effects2.nim b/tests/effects/tstrict_effects2.nim
new file mode 100644
index 000000000..acc0a0540
--- /dev/null
+++ b/tests/effects/tstrict_effects2.nim
@@ -0,0 +1,28 @@
+discard """
+  errormsg: "can raise an unlisted exception: Exception"
+  line: 23
+"""
+
+{.push warningAsError[Effect]: on.}
+{.experimental: "strictEffects".}
+
+# bug #13905
+
+proc atoi(v: cstring): cint {.importc: "atoi", cdecl, raises: [].}
+
+type Conv = proc(v: cstring): cint {.cdecl, raises: [].}
+
+var x: Conv = atoi
+
+# bug #17475
+
+type
+  Callback = proc()
+
+proc f(callback: Callback) {.raises: [].} =
+  callback()
+
+proc main =
+  f(proc () = raise newException(IOError, "IO"))
+
+main()
diff --git a/tests/effects/tstrict_effects3.nim b/tests/effects/tstrict_effects3.nim
new file mode 100644
index 000000000..0d98a0343
--- /dev/null
+++ b/tests/effects/tstrict_effects3.nim
@@ -0,0 +1,57 @@
+discard """
+  action: compile
+"""
+
+{.push warningAsError[Effect]: on.}
+
+{.experimental: "strictEffects".}
+
+proc fn(a: int, p1, p2: proc()) {.effectsOf: p1.} =
+  if a == 7:
+    p1()
+  if a<0:
+    raise newException(ValueError, $a)
+
+proc main() {.raises: [ValueError].} =
+  fn(1, proc()=discard, proc() = raise newException(IOError, "foo"))
+main()
+
+# bug #19159
+
+import macros
+
+func mkEnter() =
+  template helper =
+    discard
+  when defined pass:
+    helper()
+  else:
+    let ast = getAst(helper())
+
+
+# bug #6559
+type
+  SafeFn = proc (): void {. raises: [] }
+
+proc ok() {. raises: [] .} = discard
+proc fail() {. raises: [] .}
+
+let f1 : SafeFn = ok
+let f2 : SafeFn = fail
+
+
+proc fail() = discard
+f1()
+f2()
+
+import std/json
+
+# bug #22254
+proc senri(a, b: seq[JsonNode]) {.raises: [].} = discard a == b
+
+# bug #22253
+proc serika() {.raises: [].} = discard default(JsonNode) == nil
+
+senri(@[newJBool(true)], @[newJBool(false)])
+serika()
+
diff --git a/tests/effects/tstrict_effects_sort.nim b/tests/effects/tstrict_effects_sort.nim
new file mode 100644
index 000000000..8928ed0d3
--- /dev/null
+++ b/tests/effects/tstrict_effects_sort.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "cmpE can raise an unlisted exception: Exception"
+  line: 27
+"""
+
+{.push warningAsError[Effect]: on.}
+
+{.experimental: "strictEffects".}
+
+import algorithm
+
+type
+  MyInt = distinct int
+
+var toSort = @[MyInt 1, MyInt 2, MyInt 3]
+
+proc cmpN(a, b: MyInt): int =
+  cmp(a.int, b.int)
+
+proc harmless {.raises: [].} =
+  toSort.sort cmpN
+
+proc cmpE(a, b: MyInt): int {.raises: [Exception].} =
+  cmp(a.int, b.int)
+
+proc harmfull {.raises: [].} =
+  toSort.sort cmpE
diff --git a/tests/effects/tstrict_funcs.nim b/tests/effects/tstrict_funcs.nim
new file mode 100644
index 000000000..9d20f5d7e
--- /dev/null
+++ b/tests/effects/tstrict_funcs.nim
@@ -0,0 +1,46 @@
+discard """
+  cmd: "nim c --experimental:strictFuncs --experimental:views $file"
+"""
+
+import tables, streams, parsecsv
+
+type
+  Contig2Reads = TableRef[string, seq[string]]
+
+proc get_Contig2Reads(sin: Stream, fn: string, contig2len: TableRef[string, int]): Contig2Reads =
+  result = newTable[string, seq[string]]()
+  var parser: CsvParser
+  open(parser, sin, filename = fn, separator = ' ', skipInitialSpace = true)
+  while readRow(parser, 2):
+    if contig2len.haskey(parser.row[1]):
+      mgetOrPut(result, parser.row[1], @[]).add(parser.row[0])
+
+
+
+block:
+  # issue #15756
+  func `&&&`[T](x: var seq[T], y: sink T): seq[T] =
+    newSeq(result, x.len + 1)
+    for i in 0..x.len-1:
+      result[i] = move(x[i])
+    result[x.len] = move(y)
+
+  var x = @[0, 1]
+  let z = x &&& 2
+
+
+func copy[T](x: var openArray[T]; y: openArray[T]) =
+  for i in 0..high(x):
+    x[i] = y[i]
+
+type
+  R = ref object
+    a, b: R
+    data: string
+
+proc main =
+  var a, b: array[3, R]
+  b = [R(data: "a"), R(data: "b"), R(data: "c")]
+  copy a, b
+
+main()
diff --git a/tests/effects/tstrict_funcs_imports.nim b/tests/effects/tstrict_funcs_imports.nim
new file mode 100644
index 000000000..bf68b61b2
--- /dev/null
+++ b/tests/effects/tstrict_funcs_imports.nim
@@ -0,0 +1,176 @@
+discard """
+  cmd: "nim $target $options --hints:on --experimental:strictFuncs --experimental:views --threads:on -d:ssl -d:nimCoroutines $file"
+  targets: "c"
+"""
+{.warning[UnusedImport]: off.}
+
+when defined(linux):
+  import linenoise
+
+when defined(nimPreviewSlimSystem):
+  import std/[
+    assertions,
+    formatfloat,
+    objectdollar,
+    syncio,
+    widestrs,
+  ]
+
+import
+  algorithm,
+  asyncdispatch,
+  asyncfile,
+  asyncfutures,
+  asynchttpserver,
+  asyncmacro,
+  asyncnet,
+  asyncstreams,
+  atomics,
+  base64,
+  bitops,
+  browsers,
+  cgi,
+  chains,
+  colors,
+  complex,
+  cookies,
+  coro,
+  cpuinfo,
+  cpuload,
+  critbits,
+  cstrutils,
+  deques,
+  distros,
+  dynlib,
+  encodings,
+  endians,
+  epoll,
+  fenv,
+  hashes,
+  heapqueue,
+  hotcodereloading,
+  htmlgen,
+  htmlparser,
+  httpclient,
+  httpcore,
+  inotify,
+  intsets,
+  json,
+  kqueue,
+  lenientops,
+  lexbase,
+  lists,
+  locks,
+  logging,
+  macrocache,
+  macros,
+  marshal,
+  math,
+  memfiles,
+  mersenne,
+  mimetypes,
+  nativesockets,
+  net,
+  nimhcr,
+  # nimprof,
+  nre,
+  oids,
+  options,
+  os,
+  osproc,
+  parsecfg,
+  parsecsv,
+  parsejson,
+  parseopt,
+  parsesql,
+  parseutils,
+  parsexml,
+  pathnorm,
+  pegs,
+  posix_utils,
+  prelude,
+  random,
+  rationals,
+  rdstdin,
+  re,
+  registry,
+  reservedmem,
+  rlocks,
+  ropes,
+  rtarrays,
+  selectors,
+  sequtils,
+  sets,
+  sharedlist,
+  sharedtables,
+  ssl_certs,
+  ssl_config,
+  stats,
+  streams,
+  streamwrapper,
+  strformat,
+  strmisc,
+  strscans,
+  strtabs,
+  strutils,
+  sugar,
+  tables,
+  terminal,
+  threadpool,
+  times,
+  typeinfo,
+  typetraits,
+  unicode,
+  unidecode,
+  unittest,
+  uri,
+  volatile,
+  winlean,
+  xmlparser,
+  xmltree
+
+import experimental/[
+  diff,
+]
+
+import packages/docutils/[
+  highlite,
+  rst,
+  rstast,
+  rstgen,
+]
+
+import std/[
+  compilesettings,
+  decls,
+  editdistance,
+  effecttraits,
+  enumerate,
+  enumutils,
+  exitprocs,
+  isolation,
+  jsonutils,
+  logic,
+  monotimes,
+  packedsets,
+  setutils,
+  socketstreams,
+  stackframes,
+  sums,
+  time_t,
+  varints,
+  with,
+  wordwrap,
+  wrapnils,
+]
+
+import std/private/[
+  asciitables,
+  decode_helpers,
+  gitutils,
+  globs,
+  miscdollars,
+  since,
+  strimpl,
+  underscored_calls,
+]
diff --git a/tests/effects/tstrict_funcs_imports_js.nim b/tests/effects/tstrict_funcs_imports_js.nim
new file mode 100644
index 000000000..667887ff0
--- /dev/null
+++ b/tests/effects/tstrict_funcs_imports_js.nim
@@ -0,0 +1,20 @@
+discard """
+  cmd: "nim $target $options --hints:on --experimental:strictFuncs --experimental:views $file"
+  targets: "js"
+"""
+{.warning[UnusedImport]: off.}
+
+import
+  asyncjs,
+  dom,
+  jsconsole,
+  jsffi,
+  jsre
+
+import std/[
+  jsbigints,
+]
+
+import std/private/[
+  jsutils,
+]
diff --git a/tests/effects/tstrictfuncs_misc.nim b/tests/effects/tstrictfuncs_misc.nim
new file mode 100644
index 000000000..8c573bb3a
--- /dev/null
+++ b/tests/effects/tstrictfuncs_misc.nim
@@ -0,0 +1,65 @@
+discard """
+  action: compile
+"""
+
+{.experimental: "strictFuncs".}
+
+func sortedFake1[T](a: openArray[T]): seq[T] =
+  for i in 0 .. a.high: result.add a[i]
+func sortedFake2[T](a: openArray[T]): seq[T] =
+  result = newSeq[T](a.len)
+  for i in 0 .. a.high: result[i] = a[i]
+type Foo1 = object
+type Foo2 = ref object
+block:
+  let a1 = sortedFake1([Foo1()]) # ok
+  let a2 = sortedFake1([Foo2()]) # ok
+block:
+  let a1 = sortedFake2([Foo1()]) # ok
+  let a2 = sortedFake2([Foo2()]) # error: Error: 'sortedFake2' can have side effects
+
+
+import std/sequtils
+type Foob = ref object
+  x: int
+let a1 = zip(@[1,2], @[1,2]) # ok
+let a2 = zip(@[Foob(x: 1)], @[Foob(x: 2)]) # error in 1.6.0 RC2, but not 1.4.x
+
+
+# bug #20863
+type
+  Fooc = ref object
+
+func twice(foo: Fooc) =
+  var a = newSeq[Fooc](2)
+  a[0] = foo # No error.
+  a[1] = foo # Error: 'twice' can have side effects.
+
+let foo = Fooc()
+twice(foo)
+
+# bug #17387
+import json
+
+func parseColumn(columnNode: JsonNode) =
+  let columnName = columnNode["name"].str
+
+parseColumn(%*{"a": "b"})
+
+type
+  MyTable = object
+    data: seq[int]
+
+  JsonNode3 = ref object
+    fields: MyTable
+
+proc `[]`(t: MyTable, key: string): int =
+  result = t.data[0]
+
+proc `[]`(x: JsonNode3, key: string): int =
+  result = x.fields[key]
+
+func parseColumn(columnNode: JsonNode3) =
+  var columnName = columnNode["test"]
+
+parseColumn(JsonNode3())
diff --git a/tests/enum/m16462_1.nim b/tests/enum/m16462_1.nim
new file mode 100644
index 000000000..631c63256
--- /dev/null
+++ b/tests/enum/m16462_1.nim
@@ -0,0 +1,3 @@
+type
+  Scancode* {.pure.} = enum
+    SCANCODE_LEFT = 80
\ No newline at end of file
diff --git a/tests/enum/m16462_2.nim b/tests/enum/m16462_2.nim
new file mode 100644
index 000000000..631c63256
--- /dev/null
+++ b/tests/enum/m16462_2.nim
@@ -0,0 +1,3 @@
+type
+  Scancode* {.pure.} = enum
+    SCANCODE_LEFT = 80
\ No newline at end of file
diff --git a/tests/enum/mcrossmodule.nim b/tests/enum/mcrossmodule.nim
new file mode 100644
index 000000000..e534a202c
--- /dev/null
+++ b/tests/enum/mcrossmodule.nim
@@ -0,0 +1,6 @@
+
+type
+  OtherEnum* = enum
+    Success, Failed, More
+
+proc some*(x: OtherEnum): bool = x == Success
diff --git a/tests/enum/t16462.nim b/tests/enum/t16462.nim
new file mode 100644
index 000000000..9f38286bb
--- /dev/null
+++ b/tests/enum/t16462.nim
@@ -0,0 +1,5 @@
+import m16462_1 except Scancode
+import m16462_2
+
+# bug #16462
+let a = SCANCODE_LEFT
\ No newline at end of file
diff --git a/tests/enum/t21863.nim b/tests/enum/t21863.nim
new file mode 100644
index 000000000..d0d8b1fcd
--- /dev/null
+++ b/tests/enum/t21863.nim
@@ -0,0 +1,28 @@
+discard """
+cmd: "nim check --hints:off $file"
+action: reject
+nimout: '''
+t21863.nim(28, 16) Error: undeclared field: 'A' 
+  found 'A' [enumField declared in t21863.nim(24, 18)]
+  found 'A' [enumField declared in t21863.nim(25, 18)]
+t21863.nim(28, 16) Error: undeclared field: '.'
+t21863.nim(28, 16) Error: undeclared field: '.'
+t21863.nim(28, 16) Error: expression '' has no type (or is ambiguous)
+'''
+"""
+
+
+
+
+
+
+
+
+
+block:
+  type
+    EnumA = enum A, B
+    EnumB = enum A
+    EnumC = enum C
+
+  discard EnumC.A
diff --git a/tests/enum/tambiguousoverloads.nim b/tests/enum/tambiguousoverloads.nim
new file mode 100644
index 000000000..12c78c848
--- /dev/null
+++ b/tests/enum/tambiguousoverloads.nim
@@ -0,0 +1,26 @@
+discard """
+cmd: "nim check --hints:off $file"
+"""
+
+block: # bug #21887
+  type
+    EnumA = enum A = 300, B
+    EnumB = enum A = 10
+    EnumC = enum C
+
+  doAssert typeof(EnumC(A)) is EnumC #[tt.Error
+                        ^ ambiguous identifier: 'A' -- use one of the following:
+  EnumA.A: EnumA
+  EnumB.A: EnumB]#
+
+block: # issue #22598
+  type
+    A = enum
+      red
+    B = enum
+      red
+
+  let a = red #[tt.Error
+          ^ ambiguous identifier: 'red' -- use one of the following:
+  A.red: A
+  B.red: B]#
diff --git a/tests/enum/tcrossmodule.nim b/tests/enum/tcrossmodule.nim
new file mode 100644
index 000000000..c21072198
--- /dev/null
+++ b/tests/enum/tcrossmodule.nim
@@ -0,0 +1,15 @@
+import mcrossmodule
+
+type
+  MyEnum = enum
+    Success
+
+template t =
+  doAssert some(Success)
+
+t()
+
+block: # legacy support for behavior before overloadableEnums
+  # warning: ambiguous enum field 'Success' assumed to be of type MyEnum
+  let x = {Success}
+  doAssert x is set[MyEnum]
diff --git a/tests/enum/tenum.nim b/tests/enum/tenum.nim
new file mode 100644
index 000000000..a03019c5d
--- /dev/null
+++ b/tests/enum/tenum.nim
@@ -0,0 +1,267 @@
+discard """
+  output: '''
+B
+B
+ABCDC
+foo
+first0second32third64
+my value A1my value Bconc2valueCabc4abc
+my value A0my value Bconc1valueCabc3abc
+'''
+"""
+
+
+import macros
+
+block tenum1:
+  type E = enum a, b, c, x, y, z
+  var en: E
+  en = a
+
+  # Bug #4066
+  macro genEnum(): untyped = newNimNode(nnkEnumTy).add(newEmptyNode(), newIdentNode("geItem1"))
+  type GeneratedEnum = genEnum()
+  doAssert(type(geItem1) is GeneratedEnum)
+
+
+
+block tenum2:
+  type
+    TEnumHole = enum
+      eA = 0,
+      eB = 4,
+      eC = 5
+
+  var
+    e: TEnumHole = eB
+
+  case e
+  of eA: echo "A"
+  of eB: echo "B"
+  of eC: echo "C"
+
+
+
+block tenum3:
+  type
+    TEnumHole {.size: sizeof(int).} = enum
+      eA = 0,
+      eB = 4,
+      eC = 5
+
+  var
+    e: TEnumHole = eB
+
+  case e
+  of eA: echo "A"
+  of eB: echo "B"
+  of eC: echo "C"
+
+
+
+block tbasic:
+  type
+    MyEnum = enum
+      A,B,C,D
+  # trick the optimizer with an seq:
+  var x = @[A,B,C,D]
+  echo x[0],x[1],x[2],x[3],MyEnum(2)
+
+
+
+block talias:
+  # bug #5148
+  type
+    A = enum foo, bar
+    B = A
+
+  echo B.foo
+
+
+
+block thole:
+  type Holed = enum
+    hFirst = (0,"first")
+    hSecond = (32,"second")
+    hThird = (64,"third")
+    
+  var x = @[0,32,64] # This is just to avoid the compiler inlining the value of the enum
+
+  echo Holed(x[0]),ord Holed(x[0]),Holed(x[1]),ord Holed(x[1]),Holed(x[2]),ord Holed(x[2])
+
+
+
+block toffset:
+  const
+    strValB = "my value B"
+
+  type
+    TMyEnum = enum
+      valueA = (1, "my value A"),
+      valueB = strValB & "conc",
+      valueC,
+      valueD = (4, "abc")
+
+  proc getValue(i:int): TMyEnum = TMyEnum(i)
+
+  # trick the optimizer with a variable:
+  var x = getValue(4)
+  echo getValue(1), ord(valueA), getValue(2), ord(valueB), getValue(3), getValue(4), ord(valueD), x
+
+
+
+block tnamedfields:
+  const strValB = "my value B"
+
+  type
+    TMyEnum = enum
+      valueA = (0, "my value A"),
+      valueB = strValB & "conc",
+      valueC,
+      valueD = (3, "abc"),
+      valueE = 4
+
+  # trick the optimizer with a variable:
+  var x = valueD
+  echo valueA, ord(valueA), valueB, ord(valueB), valueC, valueD, ord(valueD), x
+  doAssert $x == $valueD, $x
+  doAssert $x == "abc", $x
+
+
+block tfakeOptions:
+  type
+    TFakeOption = enum
+      fakeNone, fakeForceFullMake, fakeBoehmGC, fakeRefcGC, fakeRangeCheck,
+      fakeBoundsCheck, fakeOverflowCheck, fakeNilCheck, fakeAssert, fakeLineDir,
+      fakeWarns, fakeHints, fakeListCmd, fakeCompileOnly,
+      fakeSafeCode,             # only allow safe code
+      fakeStyleCheck, fakeOptimizeSpeed, fakeOptimizeSize, fakeGenDynLib,
+      fakeGenGuiApp, fakeStackTrace
+
+    TFakeOptionset = set[TFakeOption]
+
+  var
+    gFakeOptions: TFakeOptionset = {fakeRefcGC, fakeRangeCheck, fakeBoundsCheck,
+      fakeOverflowCheck, fakeAssert, fakeWarns, fakeHints, fakeLineDir, fakeStackTrace}
+    compilerArgs: int
+    gExitcode: int8
+
+
+
+block nonzero: # bug #6959
+  type SomeEnum = enum
+    A = 10
+    B
+    C
+  let slice = SomeEnum.low..SomeEnum.high
+
+block size_one_byte: # bug #15752
+  type
+    Flag = enum
+      Disabled = 0x00
+      Enabled = 0xFF
+
+  static:
+    assert 1 == sizeof(Flag)
+
+block: # bug #12589
+  when not defined(i386):
+    type
+      OGRwkbGeometryType {.size: sizeof(cuint).} = enum
+        wkbPoint25D = 0x80000001.cuint, wkbLineString25D = 0x80000002,
+        wkbPolygon25D = 0x80000003
+
+    proc typ(): OGRwkbGeometryType =
+      return wkbPoint25D
+
+    when not defined(gcRefc):
+      doAssert $typ() == "wkbPoint25D"
+
+    block: # bug #21280
+      type
+        Test = enum
+          B = 19
+          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/tenum_invalid.nim b/tests/enum/tenum_invalid.nim
new file mode 100644
index 000000000..8ae0a1057
--- /dev/null
+++ b/tests/enum/tenum_invalid.nim
@@ -0,0 +1,8 @@
+discard """
+cmd: "nim check $file"
+"""
+
+type
+  Test = enum
+    A = 9.0 #[tt.Error
+        ^ ordinal type expected; given: float]#
diff --git a/tests/enum/tenum_no_rtti.nim b/tests/enum/tenum_no_rtti.nim
new file mode 100644
index 000000000..2e5c74b35
--- /dev/null
+++ b/tests/enum/tenum_no_rtti.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''A
+B'''
+  cmd: '''nim c --gc:arc $file'''
+"""
+type
+  Enum = enum A, B, C
+  EnumRange = range[A .. B]
+proc test_a(x: Enum): string = $x
+proc test_b(x: EnumRange): string = $x
+echo test_a(A)
+echo test_b(B)
diff --git a/tests/enum/tenum_self.nim b/tests/enum/tenum_self.nim
new file mode 100644
index 000000000..27b1c3204
--- /dev/null
+++ b/tests/enum/tenum_self.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "1 can't be converted to ErrorFoo"
+"""
+
+
+type
+  Foo = enum
+    Bar = 0.Foo
+
+  ErrorFoo = enum
+    eBar = 1.ErrorFoo
diff --git a/tests/enum/tenumfieldpragma.nim b/tests/enum/tenumfieldpragma.nim
new file mode 100644
index 000000000..604a8f019
--- /dev/null
+++ b/tests/enum/tenumfieldpragma.nim
@@ -0,0 +1,22 @@
+discard """
+  nimout: '''tenumfieldpragma.nim(20, 10) Warning: d is deprecated [Deprecated]
+tenumfieldpragma.nim(21, 10) Warning: e is deprecated [Deprecated]
+tenumfieldpragma.nim(22, 10) Warning: f is deprecated [Deprecated]
+'''
+"""
+
+type
+  A = enum
+    a
+    b = "abc"
+    c = (10, "def")
+    d {.deprecated.}
+    e {.deprecated.} = "ghi"
+    f {.deprecated.} = (20, "jkl")
+
+var v1 = a
+var v2 = b
+var v3 = c
+var v4 = d
+var v5 = e
+var v6 = f
diff --git a/tests/enum/tenumfieldpragmanoannot.nim b/tests/enum/tenumfieldpragmanoannot.nim
new file mode 100644
index 000000000..47f920827
--- /dev/null
+++ b/tests/enum/tenumfieldpragmanoannot.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "annotation to deprecated not supported here"
+  line: 8
+"""
+
+type
+  A = enum
+    a {.deprecated: "njshd".}
+
+var v1 = a
diff --git a/tests/enum/tenumitems.nim b/tests/enum/tenumitems.nim
new file mode 100644
index 000000000..76f368f8a
--- /dev/null
+++ b/tests/enum/tenumitems.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "attempting to call routine: 'items'"
+  line: 7
+"""
+
+type a = enum b,c,d
+a.items()
diff --git a/tests/enum/tenumitems2.nim b/tests/enum/tenumitems2.nim
new file mode 100644
index 000000000..db4c6b554
--- /dev/null
+++ b/tests/enum/tenumitems2.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "A\nB\nC"
+"""
+
+type TAlphabet = enum
+  A, B, C
+
+iterator items(E: typedesc[enum]): E =
+  for v in low(E)..high(E):
+    yield v
+
+for c in TAlphabet:
+  echo($c)
+
diff --git a/tests/enum/tenummix.nim b/tests/enum/tenummix.nim
new file mode 100644
index 000000000..8c306bae1
--- /dev/null
+++ b/tests/enum/tenummix.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "type mismatch"
+  file: "tenummix.nim"
+  line: 11
+"""
+
+type
+  TE1 = enum eA, eB
+  TE2 = enum eC, eD
+
+assert eA != eC
diff --git a/tests/enum/toverloadable_enums.nim b/tests/enum/toverloadable_enums.nim
new file mode 100644
index 000000000..9bb551467
--- /dev/null
+++ b/tests/enum/toverloadable_enums.nim
@@ -0,0 +1,120 @@
+discard """
+  output: '''B
+0
+E2-B'''
+joinable: false
+"""
+
+{.experimental: "overloadableEnums".}
+
+type
+  E1 = enum
+    value1,
+    value2
+  E2 = enum
+    value1,
+    value2 = 4
+
+const
+  Lookuptable = [
+    E1.value1: "1",
+    value2: "2"
+  ]
+
+when false:
+  const
+    Lookuptable: array[E1, string] = [
+      value1: "1",
+      value2: "2"
+    ]
+
+
+proc p(e: E1): int =
+  # test that the 'case' statement is smart enough:
+  case e
+  of value1: echo "A"
+  of value2: echo "B"
+
+
+let v = p value2 # ERROR: ambiguous!
+# (value2|value2)  nkClosedSymChoice -> nkSym
+
+proc x(p: int) = discard
+proc x(p: string) = discard
+
+proc takeCallback(param: proc(p: int)) = discard
+
+takeCallback x
+
+echo ord v
+
+block: # https://github.com/nim-lang/RFCs/issues/8
+  type
+    Enum1 = enum
+      A, B, C
+    Enum2 = enum
+      A, Z
+
+  proc f(e: Enum1): int = ord(e)
+  proc g(e: Enum2): int = ord(e)
+
+  proc h(e: Enum1): int = ord(e)
+  proc h(e: Enum2): int = ord(e)
+
+  let fA = f(A) # Type of A is well defined
+  let gA = g(A) # Same as above
+
+  let hA1 = h(Enum1.A) # A requires disambiguation
+  let hA2 = h(Enum2.A) # Similarly
+  let hA3 = h(B)
+  let hA4 = h(B)
+  let x = ord(Enum1.A) # Also
+  doAssert fA == 0
+  doAssert gA == 0
+  doAssert hA1 == 0
+  doAssert hA2 == 0
+  doAssert x == 0
+  doAssert hA3 == 1
+  doAssert hA4 == 1
+
+# bug #18769
+proc g3[T](x: T, e: E2): int =
+  case e
+  of value1: echo "E2-A"        # Error: type mismatch: got 'E1' for 'value1' but expected 'E2 = enum'
+  of value2: echo "E2-B"
+
+let v5 = g3(99, E2.value2)
+
+block: # only allow enums to overload enums
+  # mirrors behavior without overloadableEnums
+  proc foo() = discard
+  block:
+    type Foo = enum foo
+    doAssert foo is Foo
+    foo()
+
+import macros
+block: # test with macros/templates
+  type
+    Enum1 = enum
+      value01, value02
+    Enum2 = enum
+      value01, value10
+
+  macro isOneM(a: untyped): bool =
+    result = newCall(bindSym"==", a, ident"value01")
+
+  macro isOneMS(a: untyped): bool =
+    result = newCall(bindSym"==", a, bindSym"value01")
+
+  template isOneT(a: untyped): bool =
+    a == value01
+
+  let e1 = Enum1.value01
+  let e2 = Enum2.value01
+  doAssert isOneM(e1)
+  doAssert isOneM(e2)
+  doAssert isOneMS(e1)
+  doAssert isOneMS(e2)
+  doAssert isOneT(e1)
+  doAssert isOneT(e2)
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
new file mode 100644
index 000000000..3cf335440
--- /dev/null
+++ b/tests/enum/tpure_enums_conflict.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "-d:testsConciseTypeMismatch"
+"""
+
+# 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
+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/tredefinition.nim b/tests/enum/tredefinition.nim
new file mode 100644
index 000000000..615ca6b1c
--- /dev/null
+++ b/tests/enum/tredefinition.nim
@@ -0,0 +1,9 @@
+discard """
+  cmd: '''nim check --hints:off $file'''
+  action: reject
+nimout: '''
+tredefinition.nim(9, 25) Error: redefinition of 'Key_a'; previous declaration here: tredefinition.nim(9, 18)
+'''
+"""
+
+type Key* = enum Key_A, Key_a
\ No newline at end of file
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/m8794.nim b/tests/errmsgs/m8794.nim
new file mode 100644
index 000000000..12e61cf54
--- /dev/null
+++ b/tests/errmsgs/m8794.nim
@@ -0,0 +1,2 @@
+type Foo3* = object
+  a1: int
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/mb.nim b/tests/errmsgs/mb.nim
new file mode 100644
index 000000000..2d21e2396
--- /dev/null
+++ b/tests/errmsgs/mb.nim
@@ -0,0 +1,2 @@
+type
+  typ* = distinct string
diff --git a/tests/errmsgs/mc.nim b/tests/errmsgs/mc.nim
new file mode 100644
index 000000000..79d7431df
--- /dev/null
+++ b/tests/errmsgs/mc.nim
@@ -0,0 +1,3 @@
+
+type
+  typ* = distinct int
diff --git a/tests/errmsgs/t10251.nim b/tests/errmsgs/t10251.nim
new file mode 100644
index 000000000..19adf02eb
--- /dev/null
+++ b/tests/errmsgs/t10251.nim
@@ -0,0 +1,19 @@
+discard """
+  action:reject
+  cmd: "nim check $options $file"
+  nimout: '''
+t10251.nim(19, 23) Error: redefinition of 'goo1'; previous declaration here: t10251.nim(19, 11)
+'''
+"""
+
+# line 10
+type
+  Enum1 = enum
+    foo, bar, baz
+  Enum2 = enum
+    foo, bar, baz
+
+
+type
+  Enum3 {.pure.} = enum # fixed (by accident?) in https://github.com/nim-lang/Nim/pull/18263
+    goo0, goo1, goo2, goo1
diff --git a/tests/errmsgs/t10376.nim b/tests/errmsgs/t10376.nim
new file mode 100644
index 000000000..814c860dc
--- /dev/null
+++ b/tests/errmsgs/t10376.nim
@@ -0,0 +1,32 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "finalizer must be a direct reference to a proc"
+  line: 30
+"""
+
+type
+  A = ref object
+
+proc my_callback(a: A) {. nimcall .} =
+  discard
+
+proc foo(callback: proc(a: A) {. nimcall .}) =
+  var x1: A
+  new(x1, proc (x: A) {.nimcall.} = discard)
+  var x2: A
+  new(x2, func (x: A) {.nimcall.} = discard)
+
+  var x3: A
+  proc foo1(a: A) {.nimcall.} = discard
+  new(x3, foo1)
+  var x4: A
+  func foo2(a: A) {.nimcall.} = discard
+  new(x4, foo2)
+
+  var x5: A
+  new(x5, my_callback)
+
+  var x6: A
+  new(x6, callback)
+
+foo(my_callback)
diff --git a/tests/errmsgs/t10489_a.nim b/tests/errmsgs/t10489_a.nim
new file mode 100644
index 000000000..c762ce876
--- /dev/null
+++ b/tests/errmsgs/t10489_a.nim
@@ -0,0 +1,9 @@
+discard """
+errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe.}' for let. Did you mean to call the macro with '()'?"
+line: 9
+"""
+
+macro m(body: untyped): untyped =
+  body
+
+let x1 = m
diff --git a/tests/errmsgs/t10489_b.nim b/tests/errmsgs/t10489_b.nim
new file mode 100644
index 000000000..df05f0e6e
--- /dev/null
+++ b/tests/errmsgs/t10489_b.nim
@@ -0,0 +1,9 @@
+discard """
+errormsg: "invalid type: 'macro (body: untyped): untyped{.noSideEffect, gcsafe.}' for const. Did you mean to call the macro with '()'?"
+line: 9
+"""
+
+macro m(body: untyped): untyped =
+  body
+
+const x2 = m
diff --git a/tests/errmsgs/t10542.nim b/tests/errmsgs/t10542.nim
new file mode 100644
index 000000000..b57dbf18b
--- /dev/null
+++ b/tests/errmsgs/t10542.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--hintaserror:ConvFromXtoItselfNotNeeded"
+"""
+
+# bug #10542
+
+proc f(args: varargs[string, string], length: int) =
+  doAssert args.len == length
+
+# main use case that requires type conversion (no warning here)
+f("a", "b", 2)
+f("a", 1)
+
+
+proc m(args: varargs[cstring, cstring]) =
+  doAssert args.len == 2
+
+# main use case that requires type conversion (no warning here)
+m("a", "b")
+
+# if an argument already is cstring there's a warning
+let x: cstring = "x"
+m("a", x)
+m(x, "a")
\ No newline at end of file
diff --git a/tests/errmsgs/t10594.nim b/tests/errmsgs/t10594.nim
new file mode 100644
index 000000000..d27dd6433
--- /dev/null
+++ b/tests/errmsgs/t10594.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "expression has no address"
+  line: 7
+"""
+
+template foo(v: varargs[int]) = addr v 
+foo(1, 2)
diff --git a/tests/errmsgs/t10734.nim b/tests/errmsgs/t10734.nim
new file mode 100644
index 000000000..4e73db7cd
--- /dev/null
+++ b/tests/errmsgs/t10734.nim
@@ -0,0 +1,20 @@
+discard """
+  cmd: "nim check $file"
+  errormsg: ""
+  nimout: '''
+t10734.nim(19, 1) Error: invalid indentation
+t10734.nim(19, 6) Error: invalid indentation
+t10734.nim(20, 7) Error: expression expected, but found '[EOF]'
+t10734.nim(18, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()'
+t10734.nim(19, 6) Error: undeclared identifier: 'p'
+t10734.nim(19, 6) Error: expression 'p' has no type (or is ambiguous)
+t10734.nim(19, 6) Error: 'p' cannot be assigned to
+t10734.nim(17, 3) Hint: 'T' is declared but not used [XDeclaredButNotUsed]
+'''
+"""
+
+type
+  T = object
+    a:
+proc p =
+  case
\ No newline at end of file
diff --git a/tests/errmsgs/t10735.nim b/tests/errmsgs/t10735.nim
new file mode 100644
index 000000000..a39cd196e
--- /dev/null
+++ b/tests/errmsgs/t10735.nim
@@ -0,0 +1,68 @@
+discard """
+  cmd: "nim check $file"
+  errormsg: "illformed AST: case buf[pos]"
+  nimout: '''
+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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 1
+  required type for a: WideCStringObj
+  but expression 'buf' is of type: cstring
+template `[]`(s: string; i: int): char
+  first type mismatch at position: 1
+  required type for s: string
+  but expression 'buf' is of type: cstring
+
+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
+"""
+
+let buf: cstring
+case buf[pos]
+else:
+  case buf[pos]
diff --git a/tests/errmsgs/t1154.nim b/tests/errmsgs/t1154.nim
new file mode 100644
index 000000000..fee9d0ad6
--- /dev/null
+++ b/tests/errmsgs/t1154.nim
@@ -0,0 +1,11 @@
+discard """
+errormsg: "invalid type: 'untyped' in this context: 'proc (a: varargs[untyped])' for proc"
+line: 8
+"""
+
+import typetraits
+
+proc foo(a:varargs[untyped]) =
+  echo a[0].type.name
+
+foo(1)
diff --git a/tests/errmsgs/t12844.nim b/tests/errmsgs/t12844.nim
new file mode 100644
index 000000000..a274b72b4
--- /dev/null
+++ b/tests/errmsgs/t12844.nim
@@ -0,0 +1,13 @@
+discard """
+cmd: "nim check $file"
+errormsg: "invalid type: 'template (args: varargs[string])' for var. Did you mean to call the template with '()'?"
+nimout: '''
+t12844.nim(11, 7) Error: invalid type: 'template (args: varargs[string])' for const. Did you mean to call the template with '()'?
+t12844.nim(12, 5) Error: invalid type: 'template (args: varargs[string])' for var. Did you mean to call the template with '()'?'''
+"""
+
+template z*(args: varargs[string, `$`]) =
+  discard
+const x = z
+var y = z
+
diff --git a/tests/errmsgs/t14444.nim b/tests/errmsgs/t14444.nim
new file mode 100644
index 000000000..27365236e
--- /dev/null
+++ b/tests/errmsgs/t14444.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "--hints:off"
+  exitcode: "1"
+  output: '''
+t14444.nim(13)           t14444
+fatal.nim(53)            sysFatal
+Error: unhandled exception: index out of bounds, the container is empty [IndexDefect]
+'''
+"""
+
+when true: # bug #14444
+  var i: string
+  i[10] = 'j'
+  echo i
\ No newline at end of file
diff --git a/tests/errmsgs/t16654.nim b/tests/errmsgs/t16654.nim
new file mode 100644
index 000000000..b2b57619b
--- /dev/null
+++ b/tests/errmsgs/t16654.nim
@@ -0,0 +1,12 @@
+discard """
+  cmd: "nim check $options $file"
+  errormsg: "type mismatch: got <int literal(1), proc (r: GenericParam): auto>"
+"""
+
+when true: # bug #16654
+  func fn[T](a: T, op: proc(a: T): float) = discard
+  proc main() =
+    let v = 1
+    proc bar(r: auto): auto = v
+    fn(1, bar)
+  main()
diff --git a/tests/errmsgs/t17460.nim b/tests/errmsgs/t17460.nim
new file mode 100644
index 000000000..bb8e21198
--- /dev/null
+++ b/tests/errmsgs/t17460.nim
@@ -0,0 +1,19 @@
+discard """
+  cmd: "nim check $options $file"
+  errormsg: "tuple expected for tuple unpacking, but got 'array[0..2, int]'"
+"""
+
+iterator xclusters*[T](a: openArray[T]; s: static[int]): array[s, T] {.inline.} =
+  var result: array[s, T] # iterators have no default result variable
+  var i = 0
+  while i < len(a):
+    for j, x in mpairs(result):
+      x = a[(i + j) mod len(a)]
+    yield result
+    inc(i)
+
+proc m =
+  for (i, j, k) in xclusters([1, 2, 3, 4, 5], 3):
+    echo i, j, k
+
+m()
diff --git a/tests/errmsgs/t18327.nim b/tests/errmsgs/t18327.nim
new file mode 100644
index 000000000..686a1bd0c
--- /dev/null
+++ b/tests/errmsgs/t18327.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "parameter 'n' requires a type"
+"""
+
+proc fn3(n) = discard
\ No newline at end of file
diff --git a/tests/errmsgs/t18886.nim b/tests/errmsgs/t18886.nim
new file mode 100644
index 000000000..8ed160c64
--- /dev/null
+++ b/tests/errmsgs/t18886.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t18886.nim(18, 24) Error: ambiguous identifier: 'bar' -- you need a helper proc to disambiguate the following:
+  t18886.bar: proc (i: ptr int){.noSideEffect, gcsafe.}
+  t18886.bar: proc (i: ptr char){.noSideEffect, gcsafe.}
+'''
+"""
+
+type Foo = (proc(_: pointer): void)
+
+
+proc bar(i: ptr[int]) = discard
+proc bar(i: ptr[char]) = discard
+
+
+let fooBar = cast[Foo](bar)
\ No newline at end of file
diff --git a/tests/errmsgs/t18983.nim b/tests/errmsgs/t18983.nim
new file mode 100644
index 000000000..3451875cb
--- /dev/null
+++ b/tests/errmsgs/t18983.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "illegal recursion in type 'A'"
+"""
+
+type
+  A* = A
+  B = (A,)
diff --git a/tests/errmsgs/t19224.nim b/tests/errmsgs/t19224.nim
new file mode 100644
index 000000000..7a9ecb2e7
--- /dev/null
+++ b/tests/errmsgs/t19224.nim
@@ -0,0 +1,12 @@
+discard """
+cmd: "nim check --hints:off $file"
+errormsg: ""
+nimout: '''
+t19224.nim(10, 10) Error: cannot infer element type of items([])
+t19224.nim(12, 10) Error: cannot infer element type of items(@[])
+'''
+"""
+
+for _ in []: discard
+
+for _ in @[]: discard
diff --git a/tests/errmsgs/t19882.nim b/tests/errmsgs/t19882.nim
new file mode 100644
index 000000000..1f2f95ab7
--- /dev/null
+++ b/tests/errmsgs/t19882.nim
@@ -0,0 +1,10 @@
+
+discard """
+  errormsg: "cannot instantiate 'A[T, P]' inside of type definition: 'init'; Maybe generic arguments are missing?"
+"""
+type A[T,P] = object
+  b:T
+  c:P
+proc init(): ref A =      
+  new(result)
+var a = init()
diff --git a/tests/errmsgs/t19882_2.nim b/tests/errmsgs/t19882_2.nim
new file mode 100644
index 000000000..7f3055a5d
--- /dev/null
+++ b/tests/errmsgs/t19882_2.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "cannot instantiate: 'A[T]'; the object's generic parameters cannot be inferred and must be explicitly given"
+"""
+type A[T] = object
+var a = A()
\ No newline at end of file
diff --git a/tests/errmsgs/t21257.nim b/tests/errmsgs/t21257.nim
new file mode 100644
index 000000000..eecdb1dfe
--- /dev/null
+++ b/tests/errmsgs/t21257.nim
@@ -0,0 +1,20 @@
+discard """
+  action: compile
+  cmd: "nim check $file" 
+"""
+
+type AC_WINCTRL_Fields* = distinct uint8
+
+type AC_STATUSA_WSTATE0* {.pure.} = enum
+  ABOVE = 0x0,
+  INSIDE = 0x1,
+  BELOW = 0x2,
+
+type AC_WINCTRL_WINTSEL0* {.pure.} = enum
+  ABOVE = 0x0,
+  INSIDE = 0x1,
+  BELOW = 0x2,
+  OUTSIDE = 0x3,
+
+proc write*(WINTSEL0: AC_WINCTRL_WINTSEL0 = ABOVE) =
+  discard
diff --git a/tests/errmsgs/t22097.nim b/tests/errmsgs/t22097.nim
new file mode 100644
index 000000000..bb24ee8d3
--- /dev/null
+++ b/tests/errmsgs/t22097.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "type mismatch: got <uint8>"
+"""
+
+proc toUInt16(x: var uint16) =
+  discard
+
+var x = uint8(1)
+toUInt16 x
diff --git a/tests/errmsgs/t22284.nim b/tests/errmsgs/t22284.nim
new file mode 100644
index 000000000..827155e6b
--- /dev/null
+++ b/tests/errmsgs/t22284.nim
@@ -0,0 +1,25 @@
+discard """
+  errormsg: "j(uRef, proc (config: F; sources: auto) {.raises: [].} = discard ) can raise an unlisted exception: Exception"
+"""
+
+import std/macros
+
+macro h(): untyped =
+  result = newTree(nnkStmtList)
+  result.add quote do:
+    new int
+
+type F = object
+
+proc j[SecondarySources](
+    uRef: ref SecondarySources,
+    u: proc (config: F, sources: ref SecondarySources)): F =
+  u(result, uRef)
+
+template programMain(body: untyped) =
+  proc main {.raises: [].} = body  # doesn't SIGSEGV without this {.raises: [].}
+  main()
+
+programMain:
+  var uRef = h()
+  discard j(uRef, u = proc(config: F, sources: auto) {.raises: [].} = discard)
\ No newline at end of file
diff --git a/tests/errmsgs/t22753.nim b/tests/errmsgs/t22753.nim
new file mode 100644
index 000000000..8a504109a
--- /dev/null
+++ b/tests/errmsgs/t22753.nim
@@ -0,0 +1,52 @@
+discard """
+cmd: "nim check --hints:off $file"
+errormsg: "type mismatch"
+nimoutFull: true
+nimout: '''
+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: 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: 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: 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: 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: 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: 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: 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: 3
+  required type for val: char
+  but expression '9' is of type: int literal(9)
+
+expression: x[0] = 9
+'''
+"""
+
+var x: array[3] # bug #22753
+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/t22996.nim b/tests/errmsgs/t22996.nim
new file mode 100644
index 000000000..3a51fd8b0
--- /dev/null
+++ b/tests/errmsgs/t22996.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "invalid type: 'typedesc[string]' for const"
+"""
+
+# bug #22996
+type MyObject = ref object
+  _ = string
diff --git a/tests/errmsgs/t23060.nim b/tests/errmsgs/t23060.nim
new file mode 100644
index 000000000..abb79bcc3
--- /dev/null
+++ b/tests/errmsgs/t23060.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "undeclared identifier: '♔♕♖♗♘♙'"
+"""
+
+♔♕♖♗♘♙ = 1
\ No newline at end of file
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/t23435.nim b/tests/errmsgs/t23435.nim
new file mode 100644
index 000000000..5e2e4c82a
--- /dev/null
+++ b/tests/errmsgs/t23435.nim
@@ -0,0 +1,12 @@
+discard """
+  outputsub: "Error: unhandled exception: value out of range: -15 notin 0 .. 9223372036854775807 [RangeDefect]"
+  exitcode: "1"
+"""
+
+# bug #23435
+proc foo() =
+  for _ in @[1, 3, 5]:
+    discard "abcde"[25..<10]
+    break
+
+foo()
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/t2614.nim b/tests/errmsgs/t2614.nim
new file mode 100644
index 000000000..031ecb9d1
--- /dev/null
+++ b/tests/errmsgs/t2614.nim
@@ -0,0 +1,21 @@
+discard """
+  cmd: "nim check $options --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t2614.nim(19, 27) Error: type mismatch: got <array[0..1, proc ()]> but expected 'array[0..1, proc (){.closure.}]'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+t2614.nim(21, 22) Error: type mismatch: got <seq[proc ()]> but expected 'seq[proc (){.closure.}]'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+'''
+"""
+
+proc g
+proc f =
+  if false: g()
+proc g =
+  if false: f()
+
+var a = [f, g] # This works
+var b: array[2, proc()] = [f, g] # Error
+
+var c: seq[proc()] = @[f, g] 
\ No newline at end of file
diff --git a/tests/errmsgs/t4756.nim b/tests/errmsgs/t4756.nim
new file mode 100644
index 000000000..262614ba0
--- /dev/null
+++ b/tests/errmsgs/t4756.nim
@@ -0,0 +1,16 @@
+discard """
+errormsg: "type mismatch: got <string, arr: seq[empty]>"
+line: 15
+"""
+
+# https://github.com/nim-lang/Nim/issues/4756
+
+type
+  Test* = ref object
+    name*: string
+
+proc newTest(name: string, arr: seq): Test =
+    result = Test(name: name)
+
+let test = newTest("test", arr = @[])
+
diff --git a/tests/errmsgs/t5167_1.nim b/tests/errmsgs/t5167_1.nim
new file mode 100644
index 000000000..9f4f208a4
--- /dev/null
+++ b/tests/errmsgs/t5167_1.nim
@@ -0,0 +1,17 @@
+discard """
+errormsg: "'bar' doesn't have a concrete type, due to unspecified generic parameters."
+line: 16
+"""
+
+proc foo[T]() =
+  var y1 = foo[string]
+  var y2 = foo[T]
+
+proc bar[T]() =
+  let x = 0
+
+let good1 = foo[int]
+let good2 = bar[int]
+
+let err = bar
+
diff --git a/tests/errmsgs/t5167_2.nim b/tests/errmsgs/t5167_2.nim
new file mode 100644
index 000000000..17d96ef47
--- /dev/null
+++ b/tests/errmsgs/t5167_2.nim
@@ -0,0 +1,12 @@
+discard """
+cmd: "nim c --threads:on $file"
+errormsg: "'threadFunc' doesn't have a concrete type, due to unspecified generic parameters."
+line: 11
+"""
+
+proc threadFunc[T]() {.thread.} =
+  let x = 0
+
+var thr: Thread[void]
+thr.createThread(threadFunc)
+
diff --git a/tests/errmsgs/t5167_3.nim b/tests/errmsgs/t5167_3.nim
new file mode 100644
index 000000000..2781d3943
--- /dev/null
+++ b/tests/errmsgs/t5167_3.nim
@@ -0,0 +1,25 @@
+discard """
+cmd: "nim c --threads:on $file"
+errormsg: "type mismatch"
+line: 24
+"""
+
+type
+  TGeneric[T] = object
+    x: int
+
+proc foo1[A, B, C, D](x: proc (a: A, b: B, c: C, d: D)) =
+  echo "foo1"
+
+proc foo2(x: proc(x: int)) =
+  echo "foo2"
+
+# The goal of this test is to verify that none of the generic parameters of the
+# proc will be marked as unused. The error message should be "type mismatch" instead
+# of "'bar' doesn't have a concrete type, due to unspecified generic parameters".
+proc bar[A, B, C, D](x: A, y: seq[B], z: array[4, TGeneric[C]], r: TGeneric[D]) =
+  echo "bar"
+
+foo1[int, seq[int], array[4, TGeneric[float]], TGeneric[string]] bar
+foo2 bar
+
diff --git a/tests/errmsgs/t5167_4.nim b/tests/errmsgs/t5167_4.nim
new file mode 100644
index 000000000..dafd7754d
--- /dev/null
+++ b/tests/errmsgs/t5167_4.nim
@@ -0,0 +1,20 @@
+discard """
+errormsg: "type mismatch: got <proc [*missing parameters*](x: int) | proc (x: string){.gcsafe.}>"
+line: 19
+"""
+
+type
+  TGeneric[T] = object
+    x: int
+
+proc foo[B](x: int) =
+  echo "foo1"
+
+proc foo(x: string) =
+  echo "foo2"
+
+proc bar(x: proc (x: int)) =
+  echo "bar"
+
+bar foo
+
diff --git a/tests/errmsgs/t5167_5.nim b/tests/errmsgs/t5167_5.nim
new file mode 100644
index 000000000..dea7e40b3
--- /dev/null
+++ b/tests/errmsgs/t5167_5.nim
@@ -0,0 +1,25 @@
+discard """
+cmd: "nim check --mm:refc $file"
+"""
+# issue #11942
+discard newSeq[system]() #[tt.Error
+               ^ expression 'system' has no type (or is ambiguous)]#
+
+# issue #5167
+template t[B]() =
+  echo "foo1"
+
+macro m[T]: untyped = nil
+
+proc bar(x: proc (x: int)) =
+  echo "bar"
+
+let x = t #[tt.Error
+        ^ 't' has unspecified generic parameters]#
+bar t #[tt.Error
+^ type mismatch: got <template [*missing parameters*]()>]#
+
+let y = m #[tt.Error
+        ^ 'm' has unspecified generic parameters]#
+bar m #[tt.Error
+^ type mismatch: got <macro [*missing parameters*](): untyped{.noSideEffect, gcsafe.}>]#
diff --git a/tests/errmsgs/t5282.nim b/tests/errmsgs/t5282.nim
new file mode 100644
index 000000000..4da49d155
--- /dev/null
+++ b/tests/errmsgs/t5282.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "illegal recursion in type 'x'"
+"""
+
+type x = distinct x
diff --git a/tests/errmsgs/t5870.nim b/tests/errmsgs/t5870.nim
new file mode 100644
index 000000000..96966bcd7
--- /dev/null
+++ b/tests/errmsgs/t5870.nim
@@ -0,0 +1,17 @@
+discard """
+errormsg: "invalid type: 'SomeRefObj' in this context: 'seq[SomeRefObj]' for const"
+line: 14
+"""
+
+# bug #5870
+type SomeRefObj = ref object of RootObj
+    someIntMember: int
+
+proc createSomeRefObj(v: int): SomeRefObj=
+    result.new()
+    result.someIntMember = v
+
+const compileTimeSeqOfRefObjs = @[createSomeRefObj(100500), createSomeRefObj(2)]
+
+for i in 0..1:
+  echo compileTimeSeqOfRefObjs[i].someIntMember
diff --git a/tests/errmsgs/t6281.nim b/tests/errmsgs/t6281.nim
new file mode 100644
index 000000000..59fda5077
--- /dev/null
+++ b/tests/errmsgs/t6281.nim
@@ -0,0 +1,9 @@
+discard """
+errormsg: "invalid type: 'SomeNumber' in this context: 'seq[SomeNumber]' for var"
+line: 6
+"""
+
+var seqwat: seq[SomeNumber] = @[]
+
+proc foo(x: SomeNumber) =
+  seqwat.add(x)
\ No newline at end of file
diff --git a/tests/errmsgs/t6483.nim b/tests/errmsgs/t6483.nim
new file mode 100644
index 000000000..0e977b36d
--- /dev/null
+++ b/tests/errmsgs/t6483.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "request to generate code for .compileTime proc: newSeq"
+  line: 21
+"""
+
+type
+  VarItem = object
+    onode: NimNode
+    nnode: NimNode
+    suffix: string
+
+  VarState = object
+    scopes: seq[VarScope]
+
+  VarScope = object
+    variables: seq[VarItem]
+    children: seq[VarScope]
+
+when true:
+  var scope1 = VarScope(
+    variables: newSeq[VarItem](),
+    children: newSeq[VarScope]()
+  )
+  var scope2 = VarScope(
+    variables: newSeq[VarItem](),
+    children: newSeq[VarScope]()
+  )
+  var state = VarState(scopes: newSeq[VarScope]())
+  state.scopes.add(scope1)
+  state.scopes[0].children.add(scope2)
+  echo($state.scopes)
\ No newline at end of file
diff --git a/tests/errmsgs/t6499.nim b/tests/errmsgs/t6499.nim
new file mode 100644
index 000000000..25e78fdbb
--- /dev/null
+++ b/tests/errmsgs/t6499.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "'chr' is a built-in and cannot be used as a first-class procedure"
+"""
+
+# bug #6499
+let x = (chr, 0)
diff --git a/tests/errmsgs/t6608.nim b/tests/errmsgs/t6608.nim
new file mode 100644
index 000000000..88cbf42fd
--- /dev/null
+++ b/tests/errmsgs/t6608.nim
@@ -0,0 +1,15 @@
+discard """
+  cmd: "nim c --hints:off $file"
+  errormsg: "type mismatch: got <>"
+  nimout: '''t6608.nim(13, 4) Error: type mismatch: got <>
+but expected one of:
+AcceptCB = proc (s: string){.closure.}'''
+"""
+
+type
+  AcceptCB = proc (s: string)
+
+proc x(x: AcceptCB) =
+  x()
+
+x()
diff --git a/tests/errmsgs/t8064.nim b/tests/errmsgs/t8064.nim
new file mode 100644
index 000000000..c35a3abcc
--- /dev/null
+++ b/tests/errmsgs/t8064.nim
@@ -0,0 +1,9 @@
+import tables
+
+values
+
+
+discard """
+  # either this or "expression has no type":
+  errormsg: "ambiguous identifier: 'values' -- use one of the following:"
+"""
diff --git a/tests/errmsgs/t8339.nim b/tests/errmsgs/t8339.nim
new file mode 100644
index 000000000..720e080c0
--- /dev/null
+++ b/tests/errmsgs/t8339.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <seq[int]> but expected 'seq[float]'"
+  line: 8
+"""
+
+import sequtils
+
+var x: seq[float] = @[1].mapIt(it)
diff --git a/tests/errmsgs/t8434.nim b/tests/errmsgs/t8434.nim
new file mode 100644
index 000000000..5d962ee5c
--- /dev/null
+++ b/tests/errmsgs/t8434.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "type mismatch: got <byte, int literal(0)>"
+  nimout: '''but expected one of:
+proc fun0[T1: int | float | object | array | seq](a1: T1; a2: int)
+  first type mismatch at position: 1
+  required type for a1: T1: int or float or object or array or seq
+  but expression 'byte(1)' is of type: byte
+
+expression: fun0(byte(1), 0)
+'''
+"""
+
+proc fun0[T1:int|float|object|array|seq](a1:T1, a2:int)=discard
+
+fun0(byte(1), 0)
diff --git a/tests/errmsgs/t8610.nim b/tests/errmsgs/t8610.nim
new file mode 100644
index 000000000..ec99beae5
--- /dev/null
+++ b/tests/errmsgs/t8610.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "invalid type: 'typedesc[int]' for const"
+"""
+## bug #8610
+const Foo = int
diff --git a/tests/errmsgs/t8794.nim b/tests/errmsgs/t8794.nim
new file mode 100644
index 000000000..36f05dbad
--- /dev/null
+++ b/tests/errmsgs/t8794.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim check $options $file"
+"""
+
+## issue #8794
+
+import m8794
+
+type Foo = object
+  a1: int
+
+discard Foo().a2 #[tt.Error
+             ^ undeclared field: 'a2' for type t8794.Foo [type declared in t8794.nim(9, 6)]]#
+
+type Foo3b = Foo3
+var x2: Foo3b
+
+proc getFun[T](): T =
+  var a: T
+  a
+
+discard getFun[type(x2)]().a3 #[tt.Error
+                          ^ undeclared field: 'a3' for type m8794.Foo3 [type declared in m8794.nim(1, 6)]]#
diff --git a/tests/errmsgs/t9768.nim b/tests/errmsgs/t9768.nim
new file mode 100644
index 000000000..b5ff58367
--- /dev/null
+++ b/tests/errmsgs/t9768.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "unhandled exception: t9768.nim(24, 3) `a < 4`  [AssertionDefect]"
+  file: "std/assertions.nim"
+  matrix: "-d:nimPreviewSlimSystem"
+  nimout: '''
+stack trace: (most recent call last)
+t9768.nim(29, 33)        main
+t9768.nim(24, 11)        foo1
+'''
+"""
+import std/assertions
+
+
+
+
+
+
+
+
+
+## line 20
+
+proc foo1(a: int): auto =
+  doAssert a < 4
+  result = a * 2
+
+proc main()=
+  static:
+    if foo1(1) > 0: discard foo1(foo1(2))
+
+main()
diff --git a/tests/errmsgs/t9908_01.nim b/tests/errmsgs/t9908_01.nim
new file mode 100644
index 000000000..99bc8237d
--- /dev/null
+++ b/tests/errmsgs/t9908_01.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "ordinal type expected; given: string"
+line: 10
+"""
+
+# https://github.com/nim-lang/Nim/issues/9908
+
+type
+  X = enum
+    a = ("a", "b")
diff --git a/tests/errmsgs/t9908_02.nim b/tests/errmsgs/t9908_02.nim
new file mode 100644
index 000000000..4fc60b3df
--- /dev/null
+++ b/tests/errmsgs/t9908_02.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "ordinal type expected; given: float"
+line: 10
+"""
+
+# https://github.com/nim-lang/Nim/pull/9909#issuecomment-445519287
+
+type
+  E = enum
+    myVal = 80.9
diff --git a/tests/errmsgs/ta.nim b/tests/errmsgs/ta.nim
new file mode 100644
index 000000000..31baae773
--- /dev/null
+++ b/tests/errmsgs/ta.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got <mc.typ>"
+  line: 12
+"""
+
+import mb, mc
+
+proc test(testing: mb.typ) =
+  discard
+
+var s: mc.typ
+test(s)
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/tassignunpack.nim b/tests/errmsgs/tassignunpack.nim
new file mode 100644
index 000000000..09d928a54
--- /dev/null
+++ b/tests/errmsgs/tassignunpack.nim
@@ -0,0 +1,3 @@
+var a, b = 0
+(a, b) = 1 #[tt.Error
+         ^ tuple expected for tuple unpacking, but got 'int literal(1)']#
diff --git a/tests/errmsgs/tcall_with_default_arg.nim b/tests/errmsgs/tcall_with_default_arg.nim
new file mode 100644
index 000000000..44752f1ee
--- /dev/null
+++ b/tests/errmsgs/tcall_with_default_arg.nim
@@ -0,0 +1,18 @@
+discard """
+outputsub: '''tcall_with_default_arg.nim(8) fail'''
+exitcode: 1
+"""
+# issue: #5604
+
+proc fail() =
+  raise newException(ValueError, "dead")
+
+proc getDefault(): int = 123
+
+proc bar*(arg1: int = getDefault()) =
+  fail()
+
+proc anotherFoo(input: string) =
+  bar()
+
+anotherFoo("123")
diff --git a/tests/errmsgs/tcannot_capture_builtin.nim b/tests/errmsgs/tcannot_capture_builtin.nim
new file mode 100644
index 000000000..65afa627e
--- /dev/null
+++ b/tests/errmsgs/tcannot_capture_builtin.nim
@@ -0,0 +1,8 @@
+discard """
+errormsg: "'+' is a built-in and cannot be used as a first-class procedure"
+line: 8
+"""
+
+# bug #2050
+
+let v: proc (a, b: int): int = `+`
diff --git a/tests/errmsgs/tcant_overload_by_return_type.nim b/tests/errmsgs/tcant_overload_by_return_type.nim
new file mode 100644
index 000000000..613a896b4
--- /dev/null
+++ b/tests/errmsgs/tcant_overload_by_return_type.nim
@@ -0,0 +1,9 @@
+discard """
+errormsg: "overloaded 'x' leads to ambiguous calls"
+line: 9
+"""
+
+# bug #6393
+
+proc x(): int = 7
+proc x(): string = "strange"
diff --git a/tests/errmsgs/tcase_stmt.nim b/tests/errmsgs/tcase_stmt.nim
new file mode 100644
index 000000000..cf63b9c17
--- /dev/null
+++ b/tests/errmsgs/tcase_stmt.nim
@@ -0,0 +1,29 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+tcase_stmt.nim(22, 7) Error: selector must be of an ordinal type, float or string
+tcase_stmt.nim(28, 6) Error: selector must be of an ordinal type, float or string
+
+
+
+
+
+
+
+'''
+"""
+
+
+
+# bug #19682
+type A = object
+
+case A()
+else:
+  discard
+
+# bug #20283
+
+case @[]
+else: discard
diff --git a/tests/errmsgs/tconceptconstraint.nim b/tests/errmsgs/tconceptconstraint.nim
new file mode 100644
index 000000000..066ec5bdb
--- /dev/null
+++ b/tests/errmsgs/tconceptconstraint.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "cannot instantiate B"
+  nimout: '''
+got: <typedesc[string]>
+but expected: <T: A>
+'''
+"""
+
+type
+  A = concept c
+    advance(c)
+
+  B[T: A] = object
+    child: ref B[T]
+
+proc advance(x: int): int = x + 1
+
+var a: B[int]
+var b: B[string]
+
diff --git a/tests/errmsgs/tconcisetypemismatch.nim b/tests/errmsgs/tconcisetypemismatch.nim
new file mode 100644
index 000000000..3093cc24e
--- /dev/null
+++ b/tests/errmsgs/tconcisetypemismatch.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim c --hints:off -d:testsConciseTypeMismatch $file"
+  errormsg: "type mismatch"
+  nimout: '''
+tconcisetypemismatch.nim(23, 47) Error: type mismatch
+Expression: int(inNanoseconds(t2 - t1)) / 100.5
+  [1] int(inNanoseconds(t2 - t1)): int
+  [2] 100.5: float64
+
+Expected one of (first mismatch at [position]):
+[1] proc `/`(x, y: float): float
+[1] proc `/`(x, y: float32): float32
+[2] proc `/`(x, y: int): float
+'''
+"""
+
+import std/monotimes
+from times import inNanoseconds
+
+let t1 = getMonotime()
+let result = 1 + 2
+let t2 = getMonotime()
+echo "Elapsed: ", (t2 - t1).inNanoseconds.int / 100.5
diff --git a/tests/errmsgs/tconstinfo.nim b/tests/errmsgs/tconstinfo.nim
new file mode 100644
index 000000000..170972b9f
--- /dev/null
+++ b/tests/errmsgs/tconstinfo.nim
@@ -0,0 +1,7 @@
+# https://forum.nim-lang.org/t/9762
+
+const foo = "abc"
+case 'a'
+of foo: echo "should error" #[tt.Error
+   ^ type mismatch: got <string> but expected 'char']#
+else: discard
diff --git a/tests/errmsgs/tconsttypemismatch.nim b/tests/errmsgs/tconsttypemismatch.nim
new file mode 100644
index 000000000..727bfbffb
--- /dev/null
+++ b/tests/errmsgs/tconsttypemismatch.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "type mismatch"
+  file: "tconsttypemismatch.nim"
+  line: 7
+"""
+# bug #2252
+const foo: int = 1000 / 30
diff --git a/tests/errmsgs/tdeclaredlocs.nim b/tests/errmsgs/tdeclaredlocs.nim
new file mode 100644
index 000000000..926ebf217
--- /dev/null
+++ b/tests/errmsgs/tdeclaredlocs.nim
@@ -0,0 +1,92 @@
+discard """
+  action: reject
+  matrix: "--declaredLocs --hints:off"
+  nimoutFull: true
+  nimout: '''
+tdeclaredlocs.nim(92, 3) Error: type mismatch: got <seq[MyInt2]>
+but expected one of:
+proc fn(a: Bam) [proc declared in tdeclaredlocs.nim(86, 6)]
+  first type mismatch at position: 1
+  required type for a: Bam [object declared in tdeclaredlocs.nim(78, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: Goo[MyInt2]) [proc declared in tdeclaredlocs.nim(89, 6)]
+  first type mismatch at position: 1
+  required type for a: Goo[MyInt2{char}] [object declared in tdeclaredlocs.nim(79, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: Goo[cint]) [proc declared in tdeclaredlocs.nim(88, 6)]
+  first type mismatch at position: 1
+  required type for a: Goo[cint{int32}] [object declared in tdeclaredlocs.nim(79, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: array[3, Bar]) [proc declared in tdeclaredlocs.nim(82, 6)]
+  first type mismatch at position: 1
+  required type for a: array[0..2, Bar] [object declared in tdeclaredlocs.nim(74, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: seq[Bar]) [proc declared in tdeclaredlocs.nim(81, 6)]
+  first type mismatch at position: 1
+  required type for a: seq[Bar] [object declared in tdeclaredlocs.nim(74, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: seq[MyInt1]) [proc declared in tdeclaredlocs.nim(80, 6)]
+  first type mismatch at position: 1
+  required type for a: seq[MyInt1{int}] [int declared in tdeclaredlocs.nim(72, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: set[Baz]) [proc declared in tdeclaredlocs.nim(84, 6)]
+  first type mismatch at position: 1
+  required type for a: set[Baz{enum}] [enum declared in tdeclaredlocs.nim(75, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: set[MyInt2]) [proc declared in tdeclaredlocs.nim(83, 6)]
+  first type mismatch at position: 1
+  required type for a: set[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: var SetBaz) [proc declared in tdeclaredlocs.nim(85, 6)]
+  first type mismatch at position: 1
+  required type for a: var SetBaz [enum declared in tdeclaredlocs.nim(75, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+proc fn(a: var ref ptr Bam) [proc declared in tdeclaredlocs.nim(87, 6)]
+  first type mismatch at position: 1
+  required type for a: var ref ptr Bam [object declared in tdeclaredlocs.nim(78, 3)]
+  but expression 'a' is of type: seq[MyInt2{char}] [char declared in tdeclaredlocs.nim(73, 3)]
+
+expression: fn(a)
+'''
+"""
+
+#[
+see also: tests/errmsgs/tsigmatch.nim
+]#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# line 70
+type
+  MyInt1 = int
+  MyInt2 = char
+  Bar = object
+  Baz = enum k0, k1
+  Baz2 = Baz
+  SetBaz = set[Baz2]
+  Bam = ref object
+  Goo[T] = object
+proc fn(a: seq[MyInt1]) = discard
+proc fn(a: seq[Bar]) = discard
+proc fn(a: array[3, Bar]) = discard
+proc fn(a: set[MyInt2]) = discard
+proc fn(a: set[Baz]) = discard
+proc fn(a: var SetBaz) = discard
+proc fn(a: Bam) = discard
+proc fn(a: var ref ptr Bam) = discard
+proc fn(a: Goo[cint]) = discard
+proc fn(a: Goo[MyInt2]) = discard
+
+var a: seq[MyInt2]
+fn(a)
diff --git a/tests/errmsgs/tdetailed_position.nim b/tests/errmsgs/tdetailed_position.nim
new file mode 100644
index 000000000..ecece7972
--- /dev/null
+++ b/tests/errmsgs/tdetailed_position.nim
@@ -0,0 +1,22 @@
+
+discard """
+cmd: "nim check $file"
+errormsg: "type mismatch: got <int literal(1), int literal(2), int literal(3)>"
+nimout: '''
+but expected one of:
+proc main(a, b, c: string)
+  first type mismatch at position: 1
+  required type for a: string
+  but expression '1' is of type: int literal(1)
+
+expression: main(1, 2, 3)
+'''
+"""
+
+const
+  myconst = "abcdefghijklmnopqrstuvwxyz"
+
+proc main(a, b, c: string) {.deprecated: "use foo " & "instead " & myconst.} =
+  return
+
+main(1, 2, 3)
diff --git a/tests/errmsgs/tdistinct_nil.nim b/tests/errmsgs/tdistinct_nil.nim
new file mode 100644
index 000000000..a2b403293
--- /dev/null
+++ b/tests/errmsgs/tdistinct_nil.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim check $file"
+  action: reject
+  nimout: '''
+tdistinct_nil.nim(23, 4) Error: type mismatch: got <typeof(nil)>
+but expected one of:
+proc foo(x: DistinctPointer)
+  first type mismatch at position: 1
+  required type for x: DistinctPointer
+  but expression 'nil' is of type: typeof(nil)
+
+expression: foo(nil)
+'''
+"""
+
+type
+  DistinctPointer = distinct pointer
+
+proc foo(x: DistinctPointer) =
+  discard
+
+foo(DistinctPointer(nil))
+foo(nil)
diff --git a/tests/errmsgs/tdont_show_system.nim b/tests/errmsgs/tdont_show_system.nim
new file mode 100644
index 000000000..164fdd801
--- /dev/null
+++ b/tests/errmsgs/tdont_show_system.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "expression 'true' is of type 'bool' and has to be used (or discarded)"
+  line: 13
+  file: "tdont_show_system.nim"
+"""
+
+# bug #4308
+
+#proc getGameTile: int =
+#  1 > 0
+
+# bug #4905  subsumes the problem of #4308:
+true notin {false}
diff --git a/tests/errmsgs/temptysetparam.nim b/tests/errmsgs/temptysetparam.nim
new file mode 100644
index 000000000..20763feda
--- /dev/null
+++ b/tests/errmsgs/temptysetparam.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "cannot infer the type of parameter 'x'"
+  line: 5
+"""
+proc a(x = {}) = discard
diff --git a/tests/errmsgs/tgcsafety.nim b/tests/errmsgs/tgcsafety.nim
new file mode 100644
index 000000000..66496d364
--- /dev/null
+++ b/tests/errmsgs/tgcsafety.nim
@@ -0,0 +1,32 @@
+discard """
+cmd: "nim check $file"
+errormsg: "type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]>"
+nimout: '''
+tgcsafety.nim(31, 18) Error: type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]>
+but expected one of:
+proc serve(server: AsyncHttpServer; port: Port;
+           callback: proc (request: Request): Future[void] {.closure, gcsafe.};
+           address = ""; assumedDescriptorsPerRequest = -1; domain = AF_INET): owned(
+    Future[void])
+  first type mismatch at position: 3
+  required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.}
+  but expression 'cb' is of type: proc (req: Request): Future[system.void]
+  This expression is not GC-safe. Annotate the proc with {.gcsafe.} to get extended error information.
+
+expression: serve(server, Port(7898), cb)
+'''
+"""
+
+# bug #6186
+
+import asyncdispatch, asynchttpserver
+
+var server = newAsyncHttpServer()
+
+var foo = "foo"
+proc cb(req: Request) {.async.} =
+  var baa = foo & "asds"
+  await req.respond(Http200, baa)
+
+asyncCheck server.serve(Port(7898), cb )
+runForever()
diff --git a/tests/errmsgs/tgeneral_excepts.nim b/tests/errmsgs/tgeneral_excepts.nim
new file mode 100644
index 000000000..8f8be797f
--- /dev/null
+++ b/tests/errmsgs/tgeneral_excepts.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "Only one general except clause is allowed after more specific exceptions"
+"""
+
+try:
+  discard
+except:
+  discard
+except:
+  discard
diff --git a/tests/errmsgs/tgenericconstraint.nim b/tests/errmsgs/tgenericconstraint.nim
new file mode 100644
index 000000000..b51fb3488
--- /dev/null
+++ b/tests/errmsgs/tgenericconstraint.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "cannot instantiate B"
+  nimout: '''
+got: <typedesc[int]>
+but expected: <T: string or float>
+'''
+"""
+
+type
+  B[T: string|float] = object
+    child: ref B[T]
+
+var b: B[int]
+
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
new file mode 100644
index 000000000..8e4c85106
--- /dev/null
+++ b/tests/errmsgs/tinconsistentgensym.nim
@@ -0,0 +1,25 @@
+discard """
+  cmd: "nim check --hints:off $file"
+"""
+
+block:
+  template foo =
+    when false:
+      let x = 123
+    else:
+      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()
+
+block:
+  template foo(y: static bool) =
+    block:
+      when y:
+        let x {.gensym.} = 123
+      else:
+        let x {.inject.} = 456
+      echo x #[tt.Error
+           ^ undeclared identifier: 'x']#
+  foo(false)
+  foo(true)
diff --git a/tests/errmsgs/tinteger_literals.nim b/tests/errmsgs/tinteger_literals.nim
new file mode 100644
index 000000000..f90ab14a1
--- /dev/null
+++ b/tests/errmsgs/tinteger_literals.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim check $file"
+"""
+# high(uint64) + 1
+discard 18446744073709551616'u64 #[tt.Error
+        ^ number out of range: '18446744073709551616'u64' ]#
+# high(int64) + 1
+discard 9223372036854775808'i64 #[tt.Error
+        ^ number out of range: '9223372036854775808'i64' ]#
+# high(int64) + 1
+discard 9223372036854775808 #[tt.Error
+        ^ number out of range: '9223372036854775808' ]#
+discard 300'u8 #[tt.Error
+        ^ number out of range: '300'u8' ]#
diff --git a/tests/errmsgs/tinvalidinout.nim b/tests/errmsgs/tinvalidinout.nim
new file mode 100644
index 000000000..268bcf4d5
--- /dev/null
+++ b/tests/errmsgs/tinvalidinout.nim
@@ -0,0 +1,26 @@
+discard """
+cmd: "nim check $file"
+errormsg: "the 'in' modifier can be used only with imported types"
+nimout: '''
+tinvalidinout.nim(14, 7) Error: the 'out' modifier can be used only with imported types
+tinvalidinout.nim(17, 9) Error: the 'in' modifier can be used only with imported types
+tinvalidinout.nim(18, 9) Error: the 'in' modifier can be used only with imported types
+'''
+"""
+
+type
+  Foo[in T] {.header: "foo.h", importcpp.} = object
+
+  Bar[out X] = object
+    x: int
+
+proc f1[in T](x: T) = discard
+proc f2[in T](x: T) {.importc: "f", header: "foo.h"}
+
+var
+  f: Foo[int]
+  b: Bar[string]
+
+f1 f
+f2 b
+
diff --git a/tests/errmsgs/tmacroerrorproc.nim b/tests/errmsgs/tmacroerrorproc.nim
new file mode 100644
index 000000000..86726af72
--- /dev/null
+++ b/tests/errmsgs/tmacroerrorproc.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "Expected a node of kind nnkCharLit, got nnkCommand"
+  file: "tmacroerrorproc.nim"
+  line: 13
+"""
+# issue #4915
+import macros
+
+macro mixer(n: typed): untyped =
+  expectKind(n[0], nnkCharLit)
+
+mixer:
+  echo "owh"
diff --git a/tests/errmsgs/tmake_tuple_visible.nim b/tests/errmsgs/tmake_tuple_visible.nim
new file mode 100644
index 000000000..90b965c64
--- /dev/null
+++ b/tests/errmsgs/tmake_tuple_visible.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: '''Mixing types and values in tuples is not allowed.'''
+  line: 19
+"""
+
+type
+  NimEdAppWindow = ptr NimEdAppWindowObj
+  NimEdAppWindowObj = object
+    i: int
+
+template gDefineTypeExtended*(tn: typeDesc) =
+  discard
+
+gDefineTypeExtended (NimEdAppWindow)
+
+template xxx*(tn: typeDesc, i: int) =
+  discard
+
+xxx (NimEdAppWindow, 0)
+# bug #6776
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/tmultiple_finally.nim b/tests/errmsgs/tmultiple_finally.nim
new file mode 100644
index 000000000..519a80145
--- /dev/null
+++ b/tests/errmsgs/tmultiple_finally.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "Only one finally is allowed after all other branches"
+"""
+
+try:
+  discard
+finally:
+  discard
+finally:
+  discard
+
+
diff --git a/tests/errmsgs/tnested_empty_seq.nim b/tests/errmsgs/tnested_empty_seq.nim
new file mode 100644
index 000000000..871b0ee85
--- /dev/null
+++ b/tests/errmsgs/tnested_empty_seq.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "invalid type: 'empty' in this context: 'array[0..0, (string, seq[empty])]' for var"
+  line: 8
+"""
+
+# bug #3948
+
+var headers=[("headers", @[])]
diff --git a/tests/errmsgs/tnested_generic_instantiation.nim b/tests/errmsgs/tnested_generic_instantiation.nim
new file mode 100644
index 000000000..ab9ab54cd
--- /dev/null
+++ b/tests/errmsgs/tnested_generic_instantiation.nim
@@ -0,0 +1,24 @@
+discard """
+action: compile
+"""
+
+# bug #4766
+
+type
+  Plain = ref object
+    discard
+
+  Wrapped[T] = object
+    value: T
+
+converter toWrapped[T](value: T): Wrapped[T] =
+  Wrapped[T](value: value)
+
+let result = Plain()
+discard $result
+
+proc foo[T2](a: Wrapped[T2]) =
+  # Error: generic instantiation too nested
+  discard $a
+
+foo(result)
diff --git a/tests/errmsgs/tnested_generic_instantiation2.nim b/tests/errmsgs/tnested_generic_instantiation2.nim
new file mode 100644
index 000000000..c2ec31af8
--- /dev/null
+++ b/tests/errmsgs/tnested_generic_instantiation2.nim
@@ -0,0 +1,27 @@
+discard """
+action: compile
+"""
+
+#[
+bug #4766
+see also: tnested_generic_instantiation.nim
+]#
+
+proc toString*[T](x: T) =
+  for name, value in fieldPairs(x):
+    when compiles(toString(value)):
+      discard
+    toString(value)
+
+type
+  Plain = ref object
+    discard
+
+  Wrapped[T] = object
+    value: T
+
+converter toWrapped[T](value: T): Wrapped[T] =
+  Wrapped[T](value: value)
+
+let result = Plain()
+toString(result)
diff --git a/tests/errmsgs/tnnodeadd.nim b/tests/errmsgs/tnnodeadd.nim
new file mode 100644
index 000000000..61921883e
--- /dev/null
+++ b/tests/errmsgs/tnnodeadd.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "cannot add to node kind: nnkInt8Lit"
+  line: 7
+"""
+import macros
+macro t(x: untyped): untyped =
+  x.add(newEmptyNode())
+t(38'i8)
diff --git a/tests/errmsgs/tnnodeindex.nim b/tests/errmsgs/tnnodeindex.nim
new file mode 100644
index 000000000..5e37e7977
--- /dev/null
+++ b/tests/errmsgs/tnnodeindex.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "index 5 not in 0 .. 2"
+  line: 7
+"""
+import macros
+macro t(x: untyped): untyped =
+  result = x[5]
+t([1, 2, 3])
diff --git a/tests/errmsgs/tnnodeindexkind.nim b/tests/errmsgs/tnnodeindexkind.nim
new file mode 100644
index 000000000..9ea045e66
--- /dev/null
+++ b/tests/errmsgs/tnnodeindexkind.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "cannot set child of node kind: nnkStrLit"
+  line: 7
+"""
+import macros
+macro t(x: untyped): untyped =
+  x[0] = newEmptyNode()
+t("abc")
diff --git a/tests/errmsgs/tnon_concrete_cast.nim b/tests/errmsgs/tnon_concrete_cast.nim
new file mode 100644
index 000000000..9e05c736c
--- /dev/null
+++ b/tests/errmsgs/tnon_concrete_cast.nim
@@ -0,0 +1,47 @@
+discard """
+  errormsg: "cannot cast to a non concrete type: 'ptr SomeNumber'"
+  line: 36
+"""
+
+# https://github.com/nim-lang/Nim/issues/5428
+
+type
+  MemFile = object
+    mem: pointer
+
+proc memfileopen(filename: string, newFileSize: int): MemFile =
+  # just a memfile mock
+  return
+
+type
+  MyData = object
+    member1: seq[int]
+    member2: int
+
+type
+  MyReadWrite = object
+    memfile: MemFile
+    offset: int
+
+# Here, SomeNumber is bound to a concrete type, and that's OK
+proc write(rw: var MyReadWrite; value: SomeNumber): void =
+  (cast[ptr SomeNumber](cast[uint](rw.memfile.mem) + rw.offset.uint))[] = value
+  rw.offset += sizeof(SomeNumber)
+
+# Here, we try to use SomeNumber without binding it to a type. This should
+# produce an error message for now. It's also possible to relax the rules
+# and allow for type-class based type inference in such situations.
+proc write[T](rw: var MyReadWrite; value: seq[T]): void =
+  rw.write value.len
+  let dst  = cast[ptr SomeNumber](cast[uint](rw.memfile.mem) + uint(rw.offset))
+  let src  = cast[pointer](value[0].addr)
+  let size = sizeof(T) * value.len
+  copyMem(dst, src, size)
+  rw.offset += size
+
+proc saveBinFile(arg: var MyData, filename: string): void =
+  var rw: MyReadWrite
+  rw.memfile = memfileOpen(filename, newFileSize = rw.offset)
+  rw.offset = 0
+  rw.write arg.member1
+
diff --git a/tests/errmsgs/tnoop.nim b/tests/errmsgs/tnoop.nim
new file mode 100644
index 000000000..f55f2441a
--- /dev/null
+++ b/tests/errmsgs/tnoop.nim
@@ -0,0 +1,12 @@
+discard """
+  nimout: '''
+  found 'a' [var declared in tnoop.nim(10, 3)]
+  '''
+  file: "tnoop.nim"
+  errormsg: "attempting to call routine: 'a'"
+"""
+
+var
+  a: int
+
+a()
diff --git a/tests/errmsgs/tproc_mismatch.nim b/tests/errmsgs/tproc_mismatch.nim
new file mode 100644
index 000000000..16f319f3b
--- /dev/null
+++ b/tests/errmsgs/tproc_mismatch.nim
@@ -0,0 +1,74 @@
+discard """
+  action: reject
+  cmd: '''nim check --hints:off $options $file'''
+  nimoutFull: true
+  nimout: '''
+tproc_mismatch.nim(38, 52) Error: type mismatch: got <proc (a: int, c: float){.cdecl, noSideEffect, gcsafe.}> but expected 'proc (a: int, c: float){.closure, noSideEffect.}'
+  Calling convention mismatch: got '{.cdecl.}', but expected '{.closure.}'.
+tproc_mismatch.nim(42, 6) Error: type mismatch: got <proc (){.inline, noSideEffect, gcsafe.}>
+but expected one of:
+proc bar(a: proc ())
+  first type mismatch at position: 1
+  required type for a: proc (){.closure.}
+  but expression 'fn1' is of type: proc (){.inline, noSideEffect, gcsafe.}
+  Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'.
+
+expression: bar(fn1)
+tproc_mismatch.nim(46, 8) Error: type mismatch: got <proc (){.inline, noSideEffect, gcsafe.}> but expected 'proc (){.closure.}'
+  Calling convention mismatch: got '{.inline.}', but expected '{.closure.}'.
+tproc_mismatch.nim(51, 8) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+  Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
+tproc_mismatch.nim(55, 8) Error: type mismatch: got <proc (a: int){.noSideEffect, gcsafe.}> but expected 'proc (a: float){.closure.}'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+tproc_mismatch.nim(64, 9) Error: type mismatch: got <proc (a: int)> but expected 'proc (a: int){.closure, gcsafe.}'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.closure.}'.
+  Pragma mismatch: got '{..}', but expected '{.gcsafe.}'.
+tproc_mismatch.nim(72, 9) Error: type mismatch: got <proc (a: int): int{.nimcall.}> but expected 'proc (a: int): int{.cdecl.}'
+  Calling convention mismatch: got '{.nimcall.}', but expected '{.cdecl.}'.
+tproc_mismatch.nim(73, 9) Error: type mismatch: got <proc (a: int): int{.cdecl.}> but expected 'proc (a: int): int{.nimcall.}'
+  Calling convention mismatch: got '{.cdecl.}', but expected '{.nimcall.}'.
+'''
+"""
+
+
+
+block: # CallConv mismatch
+  func a(a: int, c: float) {.cdecl.} = discard
+  var b: proc(a: int, c: float) {.noSideEffect.} = a
+block: # Parameter CallConv mismatch
+  proc fn1() {.inline.} = discard
+  proc bar(a: proc()) = discard
+  bar(fn1)
+block: # CallConv mismatch
+  proc fn1() {.inline.} = discard
+  var fn: proc()
+  fn = fn1
+block: # Pragma mismatch
+  var a = ""
+  proc fn1() = a.add "b"
+  var fn: proc() {.noSideEffect.}
+  fn = fn1
+block: # Fail match not do to Pragma or CallConv
+  proc fn1(a: int) = discard
+  var fn: proc(a: float)
+  fn = fn1
+block: # Infered noSideEffect assign
+  type Foo = ref object
+    x0: int
+  var g0 = Foo(x0: 1)
+  proc fn1(a: int) = g0.x0 = a
+  var fn2: proc(a: int)
+  var fn3: proc(a: int) {.gcsafe.}
+  fn2 = fn1
+  fn3 = fn1
+block: # Indrection through pragmas
+  {.pragma: inl1, inline.}
+  {.pragma: inl2, inline.}
+  {.pragma: p1, nimcall.}
+  {.pragma: p2, cdecl.}
+  var fn1: proc(a: int): int {.inl1, p1.}
+  var fn2: proc(a: int): int {.inl2, p2.}
+  fn2 = fn1
+  fn1 = fn2
+
diff --git a/tests/errmsgs/tproper_stacktrace.nim b/tests/errmsgs/tproper_stacktrace.nim
new file mode 100644
index 000000000..b0a008840
--- /dev/null
+++ b/tests/errmsgs/tproper_stacktrace.nim
@@ -0,0 +1,142 @@
+discard """
+  matrix: "--stackTrace:on --hint:all:off --warnings:off"
+  output: '''ok'''
+"""
+import strscans, strutils
+
+proc raiseTestException*() =
+  raise newException(Exception, "test")
+
+proc matchStackTrace(actualEntries: openArray[StackTraceEntry], expected: string) =
+  var expectedEntries = newSeq[StackTraceEntry]()
+  var i = 0
+
+  template checkEqual(actual, expected: typed, subject: string) =
+    if actual != expected:
+      echo "Unexpected ", subject, " on line ", i
+      echo "Actual: ", actual
+      echo "Expected: ", expected
+      doAssert(false)
+
+  for l in splitLines(expected.strip):
+    var procname, filename: string
+    var line: int
+    if not scanf(l, "$s$w.nim($i) $w", filename, line, procname):
+      doAssert(false, "Wrong expected stack trace")
+    checkEqual(actualEntries[i].filename.`$`.split('/')[^1], filename & ".nim", "file name")
+    if line != 0:
+      checkEqual(actualEntries[i].line, line, "line number")
+    checkEqual($actualEntries[i].procname, procname, "proc name")
+    inc i
+
+  doAssert(i == actualEntries.len, "Unexpected number of lines in stack trace")
+
+template verifyStackTrace*(expectedStackTrace: string, body: untyped) =
+  var verified = false
+  try:
+    body
+  except Exception as e:
+    verified = true
+    # echo "Stack trace:"
+    # echo e.getStackTrace
+    matchStackTrace(e.getStackTraceEntries(), expectedStackTrace)
+
+  doAssert(verified, "No exception was raised")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+when true:
+# <-- Align with line 70 in the text editor
+  block:
+    proc bar() =
+      raiseTestException()
+
+    proc foo() =
+      bar()
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(87) tproper_stacktrace
+      tproper_stacktrace.nim(77) foo
+      tproper_stacktrace.nim(74) bar
+      tproper_stacktrace.nim(8) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      foo()
+
+  block:
+    proc bar(x: int) =
+      raiseTestException()
+
+    template foo(x: int) =
+      bar(x)
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(104) tproper_stacktrace
+      tproper_stacktrace.nim(91) bar
+      tproper_stacktrace.nim(8) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      var x: int
+      foo(x)
+
+  block: #6803
+    proc bar(x = 500) =
+      raiseTestException()
+
+    proc foo() =
+      bar()
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(121) tproper_stacktrace
+      tproper_stacktrace.nim(111) foo
+      tproper_stacktrace.nim(108) bar
+      tproper_stacktrace.nim(8) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      foo()
+
+  block:
+    proc bar() {.stackTrace: off.} =
+      proc baz() = # Stack trace should be enabled
+        raiseTestException()
+      baz()
+
+    proc foo() =
+      bar()
+
+    const expectedStackTrace = """
+      tproper_stacktrace.nim(140) tproper_stacktrace
+      tproper_stacktrace.nim(130) foo
+      tproper_stacktrace.nim(126) baz
+      tproper_stacktrace.nim(8) raiseTestException
+    """
+
+    verifyStackTrace expectedStackTrace:
+      foo()
+
+  echo "ok"
diff --git a/tests/errmsgs/tproper_stacktrace2.nim b/tests/errmsgs/tproper_stacktrace2.nim
new file mode 100644
index 000000000..5a6ca3fcb
--- /dev/null
+++ b/tests/errmsgs/tproper_stacktrace2.nim
@@ -0,0 +1,23 @@
+discard """
+  matrix: "--stackTrace:on"
+  outputsub: '''tproper_stacktrace2.nim(21) main'''
+  exitcode: 1
+"""
+
+proc returnsNil(): ref int = return nil
+
+iterator fields*(a, b: int): int =
+  if a == b:
+    for f in a..b:
+      yield f
+  else:
+    for f in a..b:
+      yield f
+
+proc main(): string =
+  result = ""
+  for i in fields(0, 1):
+    let x = returnsNil()
+    result &= "string literal " & $x[]
+
+echo main()
diff --git a/tests/errmsgs/tproper_stacktrace3.nim b/tests/errmsgs/tproper_stacktrace3.nim
new file mode 100644
index 000000000..97d63e6ec
--- /dev/null
+++ b/tests/errmsgs/tproper_stacktrace3.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--stackTrace:on"
+  outputsub: '''tproper_stacktrace3.nim(22) main'''
+  exitcode: 1
+"""
+
+# bug #5400
+
+type Container = object
+  val: int
+
+proc actualResolver(x: ptr Container): ptr Container = x
+
+template resolve(): untyped = actualResolver(db)
+
+proc myfail(): int =
+  doAssert false
+
+proc main() =
+  var db: ptr Container = nil
+  # actualResolver(db).val = myfail() # actualResolver is not included in stack trace.
+  resolve().val = myfail() # resolve template is included in stack trace.
+
+main()
diff --git a/tests/errmsgs/treportunused.nim b/tests/errmsgs/treportunused.nim
new file mode 100644
index 000000000..46afe163d
--- /dev/null
+++ b/tests/errmsgs/treportunused.nim
@@ -0,0 +1,65 @@
+discard """
+  matrix: "--hint:all:off --hint:XDeclaredButNotUsed"
+  nimoutFull: true
+  nimout: '''
+treportunused.nim(51, 5) Hint: 'A' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(52, 5) Hint: 'B' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(55, 5) Hint: 'D' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(56, 5) Hint: 'E' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(59, 5) Hint: 'G' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(60, 5) Hint: 'H' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(64, 5) Hint: 'K' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(65, 5) Hint: 'L' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(31, 10) Hint: 's1' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(32, 10) Hint: 's2' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(33, 10) Hint: 's3' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(34, 6) Hint: 's4' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(35, 6) Hint: 's5' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(36, 7) Hint: 's6' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(37, 7) Hint: 's7' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(38, 5) Hint: 's8' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(39, 5) Hint: 's9' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(40, 6) Hint: 's10' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(41, 6) Hint: 's11' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(45, 3) Hint: 'v0.99' is declared but not used [XDeclaredButNotUsed]
+treportunused.nim(46, 3) Hint: 'v0.99.99' is declared but not used [XDeclaredButNotUsed]
+'''
+action: compile
+"""
+
+# bug #9764
+iterator s1(a:string): int = discard
+iterator s2(): int = discard
+template s3(): untyped = 123
+proc s4(): int = 123
+proc s5[T](a: T): int = 123
+macro s6(a: int): untyped = discard
+const s7 = 0
+let s8 = 0
+var s9: int
+type s10 = object
+type s11 = type(1.2)
+
+# bug #14407 (requires `compiler/nim.cfg` containing define:nimPreviewFloatRoundtrip)
+let
+  `v0.99` = "0.99"
+  `v0.99.99` = "0.99.99"
+
+block: # bug #18201
+  # Test that unused type aliases raise hint XDeclaredButNotUsed.
+  type
+    A = int
+    B = distinct int
+
+    C = object
+    D = C
+    E = distinct C
+
+    F = string
+    G = F
+    H = distinct F
+
+    J = enum
+      Foo
+    K = J
+    L = distinct J
diff --git a/tests/errmsgs/tshow_asgn.nim b/tests/errmsgs/tshow_asgn.nim
new file mode 100644
index 000000000..28a9acbeb
--- /dev/null
+++ b/tests/errmsgs/tshow_asgn.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "type mismatch: got <int> but expected 'cshort = int16'"
+  line: 12
+  column: 27
+  file: "tshow_asgn.nim"
+"""
+
+# bug #5430
+
+proc random*[T](x: Slice[T]): T =
+  ## For a slice `a .. b` returns a value in the range `a .. b-1`.
+  result = int(x.b - x.a) + x.a
+
+let slice = 10.cshort..15.cshort
+discard slice.random
diff --git a/tests/errmsgs/tsigmatch.nim b/tests/errmsgs/tsigmatch.nim
new file mode 100644
index 000000000..85ed34169
--- /dev/null
+++ b/tests/errmsgs/tsigmatch.nim
@@ -0,0 +1,172 @@
+discard """
+  cmd: "nim check --mm:refc --showAllMismatches:on --hints:off $file"
+  nimout: '''
+tsigmatch.nim(111, 4) Error: type mismatch: got <A, string>
+but expected one of:
+proc f(a: A)
+  first type mismatch at position: 2
+  extra argument given
+proc f(b: B)
+  first type mismatch at position: 1
+  required type for b: B
+  but expression 'A()' is of type: A
+
+expression: f(A(), "extra")
+tsigmatch.nim(125, 6) Error: type mismatch: got <(string, proc (){.gcsafe.})>
+but expected one of:
+proc foo(x: (string, proc ()))
+  first type mismatch at position: 1
+  required type for x: (string, proc (){.closure.})
+  but expression '("foobar", proc () = echo(["Hello!"]))' is of type: (string, proc (){.gcsafe.})
+
+expression: foo(("foobar", proc () = echo(["Hello!"])))
+tsigmatch.nim(132, 11) Error: type mismatch: got <proc (s: string): string{.noSideEffect, gcsafe.}>
+but expected one of:
+proc foo[T, S](op: proc (x: T): S {.cdecl.}): auto
+  first type mismatch at position: 1
+  required type for op: proc (x: T): S{.cdecl.}
+  but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe.}
+proc foo[T, S](op: proc (x: T): S {.safecall.}): auto
+  first type mismatch at position: 1
+  required type for op: proc (x: T): S{.safecall.}
+  but expression 'fun' is of type: proc (s: string): string{.noSideEffect, gcsafe.}
+
+expression: foo(fun)
+tsigmatch.nim(143, 13) Error: type mismatch: got <array[0..0, proc (x: int){.gcsafe.}]>
+but expected one of:
+proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe.}])
+  first type mismatch at position: 1
+  required type for fs: openArray[proc (x: int){.closure, gcsafe.}]
+  but expression '[proc (x: int) {.gcsafe.} = echo [x]]' is of type: array[0..0, proc (x: int){.gcsafe.}]
+
+expression: takesFuncs([proc (x: int) {.gcsafe.} = echo [x]])
+tsigmatch.nim(149, 4) Error: type mismatch: got <int literal(10), a0: int literal(5), string>
+but expected one of:
+proc f(a0: uint8; b: string)
+  first type mismatch at position: 2
+  named param already provided: a0
+
+expression: f(10, a0 = 5, "")
+tsigmatch.nim(156, 4) Error: type mismatch: got <string, string, string, string, string, float64, string>
+but expected one of:
+proc f(a1: int)
+  first type mismatch at position: 1
+  required type for a1: int
+  but expression '"asdf"' is of type: string
+proc f(a1: string; a2: varargs[string]; a3: float; a4: var string)
+  first type mismatch at position: 7
+  required type for a4: var string
+  but expression '"bad"' is immutable, not 'var'
+
+expression: f("asdf", "1", "2", "3", "4", 2.3, "bad")
+tsigmatch.nim(164, 4) Error: type mismatch: got <string, a0: int literal(12)>
+but expected one of:
+proc f(x: string; a0: string)
+  first type mismatch at position: 2
+  required type for a0: string
+  but expression 'a0 = 12' is of type: int literal(12)
+proc f(x: string; a0: var int)
+  first type mismatch at position: 2
+  required type for a0: var int
+  but expression 'a0 = 12' is immutable, not 'var'
+
+expression: f(foo, a0 = 12)
+tsigmatch.nim(171, 7) Error: type mismatch: got <Mystring, string>
+but expected one of:
+proc fun1(a1: MyInt; a2: Mystring)
+  first type mismatch at position: 1
+  required type for a1: MyInt
+  but expression 'default(Mystring)' is of type: Mystring
+proc fun1(a1: float; a2: Mystring)
+  first type mismatch at position: 1
+  required type for a1: float
+  but expression 'default(Mystring)' is of type: Mystring
+
+expression: fun1(default(Mystring), "asdf")
+'''
+  errormsg: "type mismatch"
+"""
+
+
+
+#[
+see also: tests/errmsgs/tdeclaredlocs.nim
+]#
+
+
+
+
+
+## line 100
+when true:
+  # bug #11061 Type mismatch error "first type mismatch at" points to wrong argument/position
+  # Note: the error msg now gives correct position for mismatched argument
+  type
+    A = object of RootObj
+    B = object of A
+block:
+  proc f(b: B) = discard
+  proc f(a: A) = discard
+
+  f(A(), "extra")
+#[
+this one is similar but error msg was even more misleading, since the user
+would think float != float64 where in fact the issue is another param:
+first type mismatch at position: 1; required type: float; but expression 'x = 1.2' is of type: float64
+  proc f(x: string, a0 = 0, a1 = 0, a2 = 0) = discard
+  proc f(x: float, a0 = 0, a1 = 0, a2 = 0) = discard
+  f(x = float(1.2), a0 = 0, a0 = 0)
+]#
+
+block:
+  # bug #7808 Passing tuple with proc leads to confusing errors
+  # Note: the error message now shows `closure` which helps debugging the issue
+  proc foo(x: (string, proc ())) = x[1]()
+  foo(("foobar", proc () = echo("Hello!")))
+
+block:
+  # bug #8305 type mismatch error drops crucial pragma info when there's only 1 argument
+  proc fun(s: string): string {.  .} = discard
+  proc foo[T, S](op: proc (x: T): S {. cdecl .}): auto = 1
+  proc foo[T, S](op: proc (x: T): S {. safecall .}): auto = 1
+  echo foo(fun)
+
+block:
+  # bug #10285 Function signature don't match when inside seq/array/openArray
+  # Note: the error message now shows `closure` which helps debugging the issue
+  # out why it doesn't match
+  proc takesFunc(f: proc (x: int) {.gcsafe.}) =
+    echo "takes single Func"
+  proc takesFuncs(fs: openArray[proc (x: int) {.gcsafe.}]) =
+    echo "takes multiple Func"
+  takesFunc(proc (x: int) {.gcsafe.} = echo x)         # works
+  takesFuncs([proc (x: int) {.gcsafe.} = echo x])      # fails
+
+block:
+  # bug https://github.com/nim-lang/Nim/issues/11061#issuecomment-508970465
+  # better fix for removal of `errCannotBindXTwice` due to #3836
+  proc f(a0: uint8, b: string) = discard
+  f(10, a0 = 5, "")
+
+block:
+  # bug: https://github.com/nim-lang/Nim/issues/11061#issuecomment-508969796
+  # sigmatch gets confused with param/arg position after varargs
+  proc f(a1: int) = discard
+  proc f(a1: string, a2: varargs[string], a3: float, a4: var string) = discard
+  f("asdf", "1", "2", "3", "4", 2.3, "bad")
+
+block:
+  # bug: https://github.com/nim-lang/Nim/issues/11061#issuecomment-508970046
+  # err msg incorrectly said something is immutable
+  proc f(x: string, a0: var int) = discard
+  proc f(x: string, a0: string) = discard
+  var foo = ""
+  f(foo, a0 = 12)
+
+when true:
+  type Mystring = string
+  type MyInt = int
+  proc fun1(a1: MyInt, a2: Mystring) = discard
+  proc fun1(a1: float, a2: Mystring) = discard
+  fun1(Mystring.default, "asdf")
+
diff --git a/tests/errmsgs/tsigmatch2.nim b/tests/errmsgs/tsigmatch2.nim
new file mode 100644
index 000000000..31c966337
--- /dev/null
+++ b/tests/errmsgs/tsigmatch2.nim
@@ -0,0 +1,47 @@
+discard """
+  cmd: "nim check --showAllMismatches:on --hints:off $file"
+  nimout: '''
+tsigmatch2.nim(40, 14) Error: type mismatch: got <float64>
+but expected one of:
+proc foo(args: varargs[string, myproc]): string
+  first type mismatch at position: 1
+  required type for args: varargs[string]
+  but expression '1.2' is of type: float64
+proc foo(i: Foo): string
+  first type mismatch at position: 1
+  required type for i: Foo
+  but expression '1.2' is of type: float64
+
+expression: foo(1.2)
+tsigmatch2.nim(40, 14) Error: expression '' has no type (or is ambiguous)
+tsigmatch2.nim(46, 3) Error: type mismatch: got <int literal(1)>
+but expected one of:
+proc foo(args: varargs[string, myproc])
+  first type mismatch at position: 1
+  required type for args: varargs[string]
+  but expression '1' is of type: int literal(1)
+
+expression: foo 1
+'''
+  errormsg: "type mismatch"
+"""
+
+
+# line 30
+type Foo = object
+block: # issue #13182
+  proc myproc(a: int): string = $("myproc", a)
+  proc foo(args: varargs[string, myproc]): string = $args
+
+  proc foo(i: Foo): string = "in foo(i)"
+  static: doAssert foo(Foo()) == "in foo(i)"
+  static: doAssert foo(1) == """["(\"myproc\", 1)"]"""
+  doAssert not compiles(foo(1.2))
+  discard foo(1.2)
+
+block:
+  proc myproc[T](x: T): string =
+    let temp = 12.isNil
+  proc foo(args: varargs[string, myproc]) = discard
+  foo 1
+static: echo "done"
diff --git a/tests/errmsgs/tsimpletypecheck.nim b/tests/errmsgs/tsimpletypecheck.nim
new file mode 100644
index 000000000..422437d3a
--- /dev/null
+++ b/tests/errmsgs/tsimpletypecheck.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <bool> but expected \'string\'"
+  file: "tsimpletypecheck.nim"
+  line: 10
+"""
+# Test 2
+# Simple type checking
+
+var a: string
+a = false #ERROR
diff --git a/tests/errmsgs/tstaticexprnotype.nim b/tests/errmsgs/tstaticexprnotype.nim
new file mode 100644
index 000000000..8b6735ff8
--- /dev/null
+++ b/tests/errmsgs/tstaticexprnotype.nim
@@ -0,0 +1,5 @@
+discard """
+  action: reject
+"""
+
+let x = static: discard
diff --git a/tests/errmsgs/tstaticexprscope.nim b/tests/errmsgs/tstaticexprscope.nim
new file mode 100644
index 000000000..6969e389e
--- /dev/null
+++ b/tests/errmsgs/tstaticexprscope.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "undeclared identifier: 'z'"
+  line: 11
+"""
+
+# Open a new scope for static expr blocks
+block:
+  let a = static:
+    var z = 123
+    33
+  echo z
diff --git a/tests/errmsgs/tstaticresult.nim b/tests/errmsgs/tstaticresult.nim
new file mode 100644
index 000000000..bc534c7a8
--- /dev/null
+++ b/tests/errmsgs/tstaticresult.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: '''
+invalid type: 'static[int]' in this context: 'proc (x: int): static[int]' for proc
+'''
+"""
+
+proc foo(x: int): static int =
+  x + 123
+
+echo foo(123)
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/ttupleindexoutofbounds.nim b/tests/errmsgs/ttupleindexoutofbounds.nim
new file mode 100644
index 000000000..ae634dddb
--- /dev/null
+++ b/tests/errmsgs/ttupleindexoutofbounds.nim
@@ -0,0 +1,2 @@
+let a = (1, 2)[4] #[tt.Error
+              ^ invalid index 4 in subscript for tuple of length 2]#
diff --git a/tests/errmsgs/ttypeAllowed.nim b/tests/errmsgs/ttypeAllowed.nim
new file mode 100644
index 000000000..fdb4c70b8
--- /dev/null
+++ b/tests/errmsgs/ttypeAllowed.nim
@@ -0,0 +1,28 @@
+discard """
+cmd: "nim check $file"
+errormsg: ""
+nimout: '''
+ttypeAllowed.nim(13, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for let
+ttypeAllowed.nim(17, 7) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for const
+ttypeAllowed.nim(21, 5) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for var
+ttypeAllowed.nim(26, 10) Error: invalid type: 'iterator (a: int, b: int, step: Positive): int{.inline, noSideEffect, gcsafe.}' for result
+'''
+"""
+
+
+let f1 = case true
+  of true:  countup[int]
+  of false: countdown[int]
+
+const f2 = case true
+  of true:  countup[int]
+  of false: countdown[int]
+
+var f3 = case true
+  of true:  countup[int]
+  of false: countdown[int]
+
+proc foobar(): auto =
+  result = case true
+    of true:  countup[int]
+    of false: countdown[int]
diff --git a/tests/errmsgs/tuncheckedarrayvar.nim b/tests/errmsgs/tuncheckedarrayvar.nim
new file mode 100644
index 000000000..9376a0150
--- /dev/null
+++ b/tests/errmsgs/tuncheckedarrayvar.nim
@@ -0,0 +1,7 @@
+discard """
+errormsg: '''
+invalid type: 'UncheckedArray[uint8]' for var
+'''
+"""
+
+var byteUA: UncheckedArray[uint8]
diff --git a/tests/errmsgs/tundeclared_field.nim b/tests/errmsgs/tundeclared_field.nim
new file mode 100644
index 000000000..5668050e0
--- /dev/null
+++ b/tests/errmsgs/tundeclared_field.nim
@@ -0,0 +1,50 @@
+discard """
+cmd: '''nim check --hints:off $file'''
+action: reject
+nimout: '''
+tundeclared_field.nim(25, 12) Error: undeclared field: 'bad1' for type tundeclared_field.A [type declared in tundeclared_field.nim(22, 8)]
+tundeclared_field.nim(30, 17) Error: undeclared field: 'bad2' for type tundeclared_field.A [type declared in tundeclared_field.nim(28, 8)]
+tundeclared_field.nim(36, 4) Error: undeclared field: 'bad3' for type tundeclared_field.A [type declared in tundeclared_field.nim(33, 8)]
+tundeclared_field.nim(42, 12) Error: undeclared field: 'bad4' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)]
+tundeclared_field.nim(43, 4) Error: undeclared field: 'bad5' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)]
+tundeclared_field.nim(44, 23) Error: undeclared field: 'bad6' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)]
+tundeclared_field.nim(46, 19) Error: undeclared field: 'bad7' for type tundeclared_field.B [type declared in tundeclared_field.nim(39, 8)]
+tundeclared_field.nim(50, 13) Error: cannot instantiate Foo [type declared in tundeclared_field.nim(49, 8)]
+'''
+"""
+
+#[
+xxx in future work, generic instantiations (e.g. `B[int]`) should be shown with their instantiation instead of `tundeclared_field.B`,
+maybe using TPreferedDesc.preferResolved or preferMixed
+]#
+# line 20
+block:
+  type A = object
+    a0: int
+  var a: A
+  discard a.bad1
+
+block:
+  type A = object
+    a0: int
+  var a = A(bad2: 0)
+
+block:
+  type A = object
+    a0: int
+  var a: A
+  a.bad3 = 0
+
+block:
+  type B[T] = object
+    b0: int
+  var b: B[int]
+  discard b.bad4
+  b.bad5 = 0
+  var b2 = B[int](bad6: 0)
+  type Bi = B[int]
+  var b3 = Bi(bad7: 0)
+
+block:
+  type Foo[T: SomeInteger] = object
+  var a: Foo[float]
diff --git a/tests/errmsgs/tundeclared_routine.nim b/tests/errmsgs/tundeclared_routine.nim
new file mode 100644
index 000000000..41b1d35f4
--- /dev/null
+++ b/tests/errmsgs/tundeclared_routine.nim
@@ -0,0 +1,44 @@
+discard """
+cmd: '''nim check --hints:off $file'''
+action: reject
+nimout: '''
+tundeclared_routine.nim(24, 17) Error: attempting to call routine: 'myiter'
+  found tundeclared_routine.myiter(a: string) [iterator declared in tundeclared_routine.nim(22, 12)]
+  found tundeclared_routine.myiter() [iterator declared in tundeclared_routine.nim(23, 12)]
+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, 11) Error: undeclared identifier: 'bad5'
+'''
+"""
+
+
+
+
+
+# line 20
+block:
+  iterator myiter(a:string): int = discard
+  iterator myiter(): int = discard
+  let a = myiter(1)
+
+block:
+  proc myPragma():int=discard
+  iterator myPragma():int=discard
+  proc myfun(a:int): int {.myPragma.} = 1
+  let a = myfun(1)
+
+block:
+  type Foo = object
+  var a = Foo()
+  iterator bar3():int=discard
+  let a2 = a.bar3
+
+block:
+  type Foo = object
+  var a = Foo()
+  let a2 = a.bar4
+
+block:
+  let a = bad5(1)
diff --git a/tests/errmsgs/tundeclared_routine_compiles.nim b/tests/errmsgs/tundeclared_routine_compiles.nim
new file mode 100644
index 000000000..21daf82bf
--- /dev/null
+++ b/tests/errmsgs/tundeclared_routine_compiles.nim
@@ -0,0 +1,11 @@
+# D20180828T234921:here
+template foo*(iter: untyped): untyped =
+  when compiles(iter.unexistingField): 0
+  elif compiles(iter.len): 1
+  else: 2
+
+proc foo[A]()=
+  let a2 = @[10, 11]
+  let a3 = foo(pairs(a2))
+
+foo[int]()
diff --git a/tests/errmsgs/tunknown_named_parameter.nim b/tests/errmsgs/tunknown_named_parameter.nim
new file mode 100644
index 000000000..d3dd6cd2d
--- /dev/null
+++ b/tests/errmsgs/tunknown_named_parameter.nim
@@ -0,0 +1,27 @@
+discard """
+cmd: "nim check $file"
+errormsg: "type mismatch: got <string, set[char], maxsplits: int literal(1)>"
+nimout: '''
+func rsplit(s: string; sep: char; maxsplit: int = -1): seq[string]
+  first type mismatch at position: 2
+  required type for sep: char
+  but expression '{':'}' is of type: set[char]
+func rsplit(s: string; sep: string; maxsplit: int = -1): seq[string]
+  first type mismatch at position: 2
+  required type for sep: string
+  but expression '{':'}' is of type: set[char]
+func rsplit(s: string; seps: set[char] = Whitespace; maxsplit: int = -1): seq[
+    string]
+  first type mismatch at position: 3
+  unknown named parameter: maxsplits
+
+expression: rsplit("abc:def", {':'}, maxsplits = 1)
+'''
+"""
+
+
+# bug #8043
+
+
+import strutils
+"abc:def".rsplit({':'}, maxsplits = 1)
diff --git a/tests/errmsgs/tunresolvedinnerproc.nim b/tests/errmsgs/tunresolvedinnerproc.nim
new file mode 100644
index 000000000..7655a5a41
--- /dev/null
+++ b/tests/errmsgs/tunresolvedinnerproc.nim
@@ -0,0 +1,10 @@
+proc wrap[T]() =
+  proc notConcrete[T](x, y: int): int =
+    var dummy: T
+    result = x - y
+
+  var x: proc (x, y: T): int
+  x = notConcrete #[tt.Error
+      ^ 'notConcrete' doesn't have a concrete type, due to unspecified generic parameters.]#
+
+wrap[int]()
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_at_operator.nim b/tests/errmsgs/twrong_at_operator.nim
new file mode 100644
index 000000000..438186f01
--- /dev/null
+++ b/tests/errmsgs/twrong_at_operator.nim
@@ -0,0 +1,21 @@
+discard """
+errormsg: "type mismatch: got <array[0..0, typedesc[int]]>"
+nimout: '''
+twrong_at_operator.nim(21, 30) Error: type mismatch: got <array[0..0, typedesc[int]]>
+but expected one of:
+proc `@`[IDX, T](a: sink array[IDX, T]): seq[T]
+  first type mismatch at position: 1
+  required type for a: sink array[IDX, T]
+  but expression '[int]' is of type: array[0..0, typedesc[int]]
+proc `@`[T](a: openArray[T]): seq[T]
+  first type mismatch at position: 1
+  required type for a: openArray[T]
+  but expression '[int]' is of type: array[0..0, typedesc[int]]
+
+expression: @[int]
+'''
+disabled: "32bit"
+"""
+
+# bug #7331
+var seqOfStrings: seq[int] = @[int]
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/errmsgs/twrongcolon.nim b/tests/errmsgs/twrongcolon.nim
new file mode 100644
index 000000000..06e802eb7
--- /dev/null
+++ b/tests/errmsgs/twrongcolon.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "in expression ' do:"
+nimout: '''
+twrongcolon.nim(10, 12) Error: in expression ' do:
+  890': identifier expected, but found ''
+'''
+
+"""
+
+var n: int : 890
diff --git a/tests/exception/m21261.nim b/tests/exception/m21261.nim
new file mode 100644
index 000000000..11b12fb5b
--- /dev/null
+++ b/tests/exception/m21261.nim
@@ -0,0 +1 @@
+raise (ref Exception)(msg: "something")
\ No newline at end of file
diff --git a/tests/exception/m22469.nim b/tests/exception/m22469.nim
new file mode 100644
index 000000000..201698701
--- /dev/null
+++ b/tests/exception/m22469.nim
@@ -0,0 +1,4 @@
+# ModuleB
+echo "First top-level statement of ModuleB"
+echo high(int) + 1
+echo "ModuleB last statement"
\ No newline at end of file
diff --git a/tests/exception/t13115.nim b/tests/exception/t13115.nim
new file mode 100644
index 000000000..5db8f9107
--- /dev/null
+++ b/tests/exception/t13115.nim
@@ -0,0 +1,31 @@
+const msg = "This char is `" & '\0' & "` and works fine!"
+
+when defined nim_t13115:
+  # bug #13115
+  template fn =
+    raise newException(Exception, msg)
+  when defined nim_t13115_static:
+    static: fn()
+  fn()
+else:
+  import std/[osproc,strformat,os,strutils]
+  proc main =
+    const nim = getCurrentCompilerExe()
+    const file = currentSourcePath
+    for b in "c js cpp".split:
+      # save CI time by avoiding mostly redundant combinations as far as this bug is concerned
+      var opts = case b
+        of "c": @["", "-d:nim_t13115_static", "-d:danger", "-d:debug"]
+        of "js": @["", "-d:nim_t13115_static"]
+        else: @[""]
+
+      for opt in opts:
+        let cmd = fmt"{nim} r -b:{b} -d:nim_t13115 {opt} --hints:off {file}"
+        let (outp, exitCode) = execCmdEx(cmd)
+        when defined windows:
+          # `\0` not preserved on windows
+          doAssert "` and works fine!" in outp, cmd & "\n" & msg
+        else:
+          doAssert msg in outp, cmd & "\n" & msg
+        doAssert exitCode == 1
+  main()
diff --git a/tests/exception/t18620.nim b/tests/exception/t18620.nim
new file mode 100644
index 000000000..ee23f8bac
--- /dev/null
+++ b/tests/exception/t18620.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: "--gc:arc; --gc:refc"
+"""
+
+proc hello() =
+  raise newException(ValueError, "You are wrong")
+
+var flag = false
+
+try:
+  hello()
+except ValueError as e:
+  flag = true
+  doAssert len(getStackTraceEntries(e)) > 0
+  doAssert len(getStackTraceEntries(e)) > 0
+
+doAssert flag
diff --git a/tests/exception/t20613.nim b/tests/exception/t20613.nim
new file mode 100644
index 000000000..6edb69415
--- /dev/null
+++ b/tests/exception/t20613.nim
@@ -0,0 +1,8 @@
+discard """
+  matrix: "; --panics:on"
+"""
+
+func test =
+  if 0 > 10:
+    raiseAssert "hey"
+test()
diff --git a/tests/exception/t21261.nim b/tests/exception/t21261.nim
new file mode 100644
index 000000000..84817d854
--- /dev/null
+++ b/tests/exception/t21261.nim
@@ -0,0 +1,9 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+m21261.nim(1)            m21261
+Error: unhandled exception: something [Exception]
+'''
+"""
+
+import m21261
\ No newline at end of file
diff --git a/tests/exception/t22008.nim b/tests/exception/t22008.nim
new file mode 100644
index 000000000..c0758e7b4
--- /dev/null
+++ b/tests/exception/t22008.nim
@@ -0,0 +1,8 @@
+template detect(v: untyped) =
+  doAssert typeof(v) is int
+
+detect:
+  try:
+    raise (ref ValueError)()
+  except ValueError:
+    42
\ No newline at end of file
diff --git a/tests/exception/t22469.nim b/tests/exception/t22469.nim
new file mode 100644
index 000000000..a76c74967
--- /dev/null
+++ b/tests/exception/t22469.nim
@@ -0,0 +1,16 @@
+discard """
+  exitcode: 1
+  output: '''
+First top-level statement of ModuleB
+m22469.nim(3)            m22469
+fatal.nim(53)            sysFatal
+Error: unhandled exception: over- or underflow [OverflowDefect]
+'''
+"""
+
+# bug #22469
+
+# ModuleA
+import m22469
+echo "ModuleA about to have exception"
+echo high(int) + 1
diff --git a/tests/exception/t9657.nim b/tests/exception/t9657.nim
new file mode 100644
index 000000000..6ac525a70
--- /dev/null
+++ b/tests/exception/t9657.nim
@@ -0,0 +1,12 @@
+discard """
+  action: run
+  exitcode: 1
+  targets: "c cpp"
+  disabled: "openbsd"
+  disabled: "netbsd"
+"""
+
+close stdmsg
+const m = "exception!"
+# see #10343 for details on this test
+discard writeBuffer(stdmsg, cstring(m), m.len)
diff --git a/tests/exception/tcontinuexc.nim b/tests/exception/tcontinuexc.nim
new file mode 100644
index 000000000..b7560a605
--- /dev/null
+++ b/tests/exception/tcontinuexc.nim
@@ -0,0 +1,26 @@
+discard """
+  outputsub: "ECcaught"
+  exitcode: "1"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+try:
+  for i in 0..3:
+    try:
+      genErrors("error!")
+    except ESomething:
+      stdout.write("E")
+    stdout.write("C")
+    raise newException(EsomeotherErr, "bla")
+finally:
+  echo "caught"
+
+#OUT ECcaught
diff --git a/tests/exception/tcpp_imported_exc.nim b/tests/exception/tcpp_imported_exc.nim
new file mode 100644
index 000000000..55a58440f
--- /dev/null
+++ b/tests/exception/tcpp_imported_exc.nim
@@ -0,0 +1,136 @@
+discard """
+matrix: "--mm:refc"
+targets: "cpp"
+output: '''
+caught as std::exception
+expected
+finally1
+finally2
+finally2
+2
+expected
+finally 1
+finally 2
+expected
+cpp exception caught
+'''
+disabled: "windows" # pending bug #18011
+"""
+
+type
+  std_exception* {.importcpp: "std::exception", header: "<exception>".} = object
+  std_runtime_error* {.importcpp: "std::runtime_error", header: "<stdexcept>".} = object
+  std_string* {.importcpp: "std::string", header: "<string>".} = object
+
+proc constructStdString(s: cstring): std_string {.importcpp: "std::string(@)", constructor, header: "<string>".}
+
+proc constructRuntimeError(s: stdstring): std_runtime_error {.importcpp: "std::runtime_error(@)", constructor.}
+
+proc what(ex: std_runtime_error): cstring {.importcpp: "((char *)#.what())".}
+
+proc myexception =
+  raise constructRuntimeError(constructStdString("cpp_exception"))
+
+try:
+  myexception() # raise std::runtime_error
+except std_exception:
+  echo "caught as std::exception"
+  try:
+    raise constructStdString("x")
+  except std_exception:
+    echo "should not happen"
+  except:
+    echo "expected"
+
+doAssert(getCurrentException() == nil)
+
+proc earlyReturn =
+  try:
+    try:
+      myexception()
+    finally:
+      echo "finally1"
+  except:
+    return
+  finally:
+    echo "finally2"
+
+earlyReturn()
+doAssert(getCurrentException() == nil)
+
+
+try:
+  block blk1:
+    try:
+      raise newException(ValueError, "mmm")
+    except:
+      break blk1
+except:
+  echo "should not happen"
+finally:
+  echo "finally2"
+
+doAssert(getCurrentException() == nil)
+
+#--------------------------------------
+
+# raise by pointer and also generic type
+
+type
+  std_vector[T] {.importcpp"std::vector", header"<vector>".} = object
+
+proc newVector[T](len: int): ptr std_vector[T] {.importcpp: "new std::vector<'1>(@)".}
+proc deleteVector[T](v: ptr std_vector[T]) {.importcpp: "delete @; @ = NIM_NIL;".}
+proc len[T](v: std_vector[T]): uint {.importcpp: "size".}
+
+var v = newVector[int](2)
+try:
+  try:
+    try:
+      raise v
+    except ptr std_vector[int] as ex:
+      echo len(ex[])
+      raise newException(ValueError, "msg5")
+    except:
+      echo "should not happen"
+  finally:
+    deleteVector(v)
+except:
+  echo "expected"
+
+doAssert(v == nil)
+doAssert(getCurrentException() == nil)
+
+#--------------------------------------
+
+# mix of Nim and imported exceptions
+try:
+  try:
+    try:
+      raise newException(KeyError, "msg1")
+    except KeyError:
+      raise newException(ValueError, "msg2")
+    except:
+      echo "should not happen"
+    finally:
+      echo "finally 1"
+  except:
+    doAssert(getCurrentExceptionMsg() == "msg2")
+    raise constructStdString("std::string")
+  finally:
+    echo "finally 2"
+except:
+  echo "expected"
+
+doAssert(getCurrentException() == nil)
+
+try:
+  try:
+    myexception()
+  except std_runtime_error as ex:
+    echo "cpp exception caught"
+    raise newException(ValueError, "rewritten " & $ex.what())
+except:
+  doAssert(getCurrentExceptionMsg() == "rewritten cpp_exception")
+
+doAssert(getCurrentException() == nil)
diff --git a/tests/exception/tcpp_imported_exc2.nim b/tests/exception/tcpp_imported_exc2.nim
new file mode 100644
index 000000000..ff299ea3d
--- /dev/null
+++ b/tests/exception/tcpp_imported_exc2.nim
@@ -0,0 +1,10 @@
+discard """
+targets: "cpp"
+output: ""
+"""
+#issue #14369 case 2
+type RuntimeError {.requiresInit, importcpp: "std::runtime_error", header: "<stdexcept>".} = object
+
+proc initRuntimeError(a: cstring): RuntimeError {.importcpp: "std::runtime_error(@)", constructor.}
+try: raise initRuntimeError("foo2")
+except: discard
diff --git a/tests/exception/tdefer1.nim b/tests/exception/tdefer1.nim
new file mode 100644
index 000000000..db46bad27
--- /dev/null
+++ b/tests/exception/tdefer1.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''hi
+1
+hi
+2
+B
+A'''
+"""
+
+# bug #1742
+
+import strutils
+let x = try: parseInt("133a")
+        except: -1
+        finally: echo "hi"
+
+
+template atFuncEnd =
+  defer:
+    echo "A"
+  defer:
+    echo "B"
+
+template testB(): untyped =
+    let a = 0
+    defer: echo "hi"
+    a
+
+proc main =
+  atFuncEnd()
+  echo 1
+  let i = testB()
+  echo 2
+
+main()
diff --git a/tests/exception/tdont_overwrite_typename.nim b/tests/exception/tdont_overwrite_typename.nim
new file mode 100644
index 000000000..d6dca0990
--- /dev/null
+++ b/tests/exception/tdont_overwrite_typename.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "c cpp"
+  output: '''Check passed
+Check passed'''
+"""
+
+# bug #5628
+
+proc checkException(ex: ref Exception) =
+  doAssert(ex.name == cstring"ValueError")
+  doAssert(ex.msg == "SecondException")
+  doAssert(ex.parent != nil)
+  doAssert(ex.parent.name == cstring"KeyError")
+  doAssert(ex.parent.msg == "FirstException")
+  echo "Check passed"
+
+var e: ref Exception
+try:
+  try:
+    raise newException(KeyError, "FirstException")
+  except:
+    raise newException(ValueError, "SecondException", getCurrentException())
+except:
+  e = getCurrentException()
+
+try:
+  checkException(e) # passes here
+  raise e
+except ValueError:
+  checkException(getCurrentException()) # fails here
diff --git a/tests/exception/testindexerroroutput.nims b/tests/exception/testindexerroroutput.nims
new file mode 100644
index 000000000..e282f14b4
--- /dev/null
+++ b/tests/exception/testindexerroroutput.nims
@@ -0,0 +1,23 @@
+mode = ScriptMode.Verbose
+
+case paramStr(3):
+  of "test1":
+    #543
+    block:
+      let s = "abc"
+      discard s[len(s)]
+  of "test2":
+    #537
+    block:
+      var s = "abc"
+      s[len(s)] = 'd'
+  of "test3":
+    #588
+    block:
+      let arr = ['a', 'b', 'c']
+      discard arr[len(arr)]
+  of "test4":
+    #588
+    block:
+      var arr = ['a', 'b', 'c']
+      arr[len(arr)] = 'd'
diff --git a/tests/exception/texcas.nim b/tests/exception/texcas.nim
new file mode 100644
index 000000000..ad6819f11
--- /dev/null
+++ b/tests/exception/texcas.nim
@@ -0,0 +1,43 @@
+discard """
+  targets: "c cpp"
+  output: '''
+Hello
+Hello
+'''
+"""
+proc test[T]() =
+  try:
+    raise newException(T, "Hello")
+  except T as foobar:
+    echo(foobar.msg)
+  doAssert(not declared(foobar))
+
+template testTemplate(excType: typedesc) =
+  try:
+    raise newException(excType, "Hello")
+  except excType as foobar:
+    echo(foobar.msg)
+  doAssert(not declared(foobar))
+
+proc test2() =
+  testTemplate(Exception)
+  doAssert(not declared(foobar))
+
+
+proc testTryAsExpr(i: int) =
+  let x = try: i    
+  except ValueError as ex:
+    echo(ex.msg)
+    -1
+
+test[Exception]()
+test2()
+testTryAsExpr(5)
+
+# see bug #7115
+doAssert(not compiles(
+  try: 
+    echo 1
+  except [KeyError as ex1, ValueError as ex2]:
+    echo 2
+))
diff --git a/tests/exception/texception_inference.nim b/tests/exception/texception_inference.nim
new file mode 100644
index 000000000..7dd01cca1
--- /dev/null
+++ b/tests/exception/texception_inference.nim
@@ -0,0 +1,32 @@
+discard """

+  output: '''good'''

+  cmd: "nim c --gc:orc -d:release $file"

+"""

+

+type

+  Raising[T, E] = object

+

+proc foo[T, Errors](x: proc (x: Raising[T, Errors])) {.raises: Errors.} =

+  discard

+

+proc callback(x: Raising[int, ValueError]) =

+  echo "callback"

+

+proc xy() {.raises: [ValueError].} =

+  foo callback

+

+proc x[E]() {.raises: [E, IOError].} =

+  raise newException(E, "text here")

+

+try:

+  x[ValueError]()

+except ValueError:

+  echo "good"

+

+proc callback2(x: Raising[int, IOError]) =

+  discard

+

+proc foo2[T, OtherErrors](x: proc(x: Raising[T, OtherErrors])) {.raises: [ValueError, OtherErrors].} =

+  discard

+

+foo2 callback2

diff --git a/tests/exception/texceptionbreak.nim b/tests/exception/texceptionbreak.nim
new file mode 100644
index 000000000..b8ce7eead
--- /dev/null
+++ b/tests/exception/texceptionbreak.nim
@@ -0,0 +1,44 @@
+discard """
+  output: "1\n2\n3\n4"
+"""
+
+# First variety
+try:
+  raise newException(OSError, "Problem")
+except OSError:
+  for y in [1, 2, 3]:
+    discard
+  try:
+    discard
+  except OSError:
+    discard
+echo "1"
+
+# Second Variety
+try:
+  raise newException(OSError, "Problem")
+except OSError:
+  for y in [1, 2, 3]:
+    discard
+  for y in [1, 2, 3]:
+    discard
+
+echo "2"
+
+# Third Variety
+try:
+  raise newException(OSError, "Problem")
+except OSError:
+  block label:
+    break label
+
+echo "3"
+
+# Fourth Variety
+block label:
+  try:
+    raise newException(OSError, "Problem")
+  except OSError:
+    break label
+
+echo "4"
diff --git a/tests/exception/texceptions.nim b/tests/exception/texceptions.nim
new file mode 100644
index 000000000..62d24c934
--- /dev/null
+++ b/tests/exception/texceptions.nim
@@ -0,0 +1,130 @@
+discard """
+  disabled: "windows" # no sigsetjmp() there
+  matrix: "-d:nimStdSetjmp; -d:nimSigSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
+  output: '''
+
+BEFORE
+FINALLY
+
+BEFORE
+EXCEPT
+FINALLY
+RECOVER
+
+BEFORE
+EXCEPT: IOError: hi
+FINALLY
+'''
+"""
+
+echo ""
+
+proc no_exception =
+  try:
+    echo "BEFORE"
+
+  except:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: no_exception()
+except: echo "RECOVER"
+
+echo ""
+
+proc reraise_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "")
+
+  except IOError:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: reraise_in_except()
+except: echo "RECOVER"
+
+echo ""
+
+proc return_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "hi")
+
+  except:
+    echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg()
+    return
+
+  finally:
+    echo "FINALLY"
+
+try: return_in_except()
+except: echo "RECOVER"
+
+block: #10417
+  proc moo() {.noreturn.} = discard
+
+  let bar =
+    try:
+      1
+    except:
+      moo()
+
+  doAssert(bar == 1)
+
+# Make sure the VM handles the exceptions correctly
+block:
+  proc fun1(): seq[int] =
+    try:
+      try:
+        raise newException(ValueError, "xx")
+      except:
+        doAssert("xx" == getCurrentExceptionMsg())
+        raise newException(KeyError, "yy")
+    except:
+      doAssert("yy" == getCurrentExceptionMsg())
+      result.add(1212)
+    try:
+      try:
+        raise newException(AssertionDefect, "a")
+      finally:
+        result.add(42)
+    except AssertionDefect:
+      result.add(99)
+    finally:
+      result.add(10)
+    result.add(4)
+    result.add(0)
+    try:
+      result.add(1)
+    except KeyError:
+      result.add(-1)
+    except ValueError:
+      result.add(-1)
+    except IndexDefect:
+      result.add(2)
+    except:
+      result.add(3)
+
+    try:
+      try:
+        result.add(1)
+        return
+      except:
+        result.add(-1)
+      finally:
+        result.add(2)
+    except KeyError:
+      doAssert(false)
+    finally:
+      result.add(3)
+
+  let x1 = fun1()
+  const x2 = fun1()
+  doAssert(x1 == x2)
diff --git a/tests/exception/texceptions2.nim b/tests/exception/texceptions2.nim
new file mode 100644
index 000000000..97fd856a0
--- /dev/null
+++ b/tests/exception/texceptions2.nim
@@ -0,0 +1,130 @@
+discard """
+  disabled: "posix" # already covered by texceptions.nim
+  matrix: "-d:nimStdSetjmp; -d:nimRawSetjmp; -d:nimBuiltinSetjmp"
+  output: '''
+
+BEFORE
+FINALLY
+
+BEFORE
+EXCEPT
+FINALLY
+RECOVER
+
+BEFORE
+EXCEPT: IOError: hi
+FINALLY
+'''
+"""
+
+echo ""
+
+proc no_exception =
+  try:
+    echo "BEFORE"
+
+  except:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: no_exception()
+except: echo "RECOVER"
+
+echo ""
+
+proc reraise_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "")
+
+  except IOError:
+    echo "EXCEPT"
+    raise
+
+  finally:
+    echo "FINALLY"
+
+try: reraise_in_except()
+except: echo "RECOVER"
+
+echo ""
+
+proc return_in_except =
+  try:
+    echo "BEFORE"
+    raise newException(IOError, "hi")
+
+  except:
+    echo "EXCEPT: ", getCurrentException().name, ": ", getCurrentExceptionMsg()
+    return
+
+  finally:
+    echo "FINALLY"
+
+try: return_in_except()
+except: echo "RECOVER"
+
+block: #10417
+  proc moo() {.noreturn.} = discard
+
+  let bar =
+    try:
+      1
+    except:
+      moo()
+
+  doAssert(bar == 1)
+
+# Make sure the VM handles the exceptions correctly
+block:
+  proc fun1(): seq[int] =
+    try:
+      try:
+        raise newException(ValueError, "xx")
+      except:
+        doAssert("xx" == getCurrentExceptionMsg())
+        raise newException(KeyError, "yy")
+    except:
+      doAssert("yy" == getCurrentExceptionMsg())
+      result.add(1212)
+    try:
+      try:
+        raise newException(AssertionDefect, "a")
+      finally:
+        result.add(42)
+    except AssertionDefect:
+      result.add(99)
+    finally:
+      result.add(10)
+    result.add(4)
+    result.add(0)
+    try:
+      result.add(1)
+    except KeyError:
+      result.add(-1)
+    except ValueError:
+      result.add(-1)
+    except IndexDefect:
+      result.add(2)
+    except:
+      result.add(3)
+
+    try:
+      try:
+        result.add(1)
+        return
+      except:
+        result.add(-1)
+      finally:
+        result.add(2)
+    except KeyError:
+      doAssert(false)
+    finally:
+      result.add(3)
+
+  let x1 = fun1()
+  const x2 = fun1()
+  doAssert(x1 == x2)
diff --git a/tests/exception/texcpt1.nim b/tests/exception/texcpt1.nim
new file mode 100644
index 000000000..835f3610a
--- /dev/null
+++ b/tests/exception/texcpt1.nim
@@ -0,0 +1,45 @@
+discard """
+  outputsub: "-6"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+  ESomethingGen[T] = object of Exception
+  ESomethingGenRef[T] = ref object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+proc raiseBla(): int =
+  try:
+    genErrors("errssor!")
+  except ESomething:
+    echo("Error happened")
+  except:
+    raise
+
+proc blah(): int =
+  try:
+    result = raiseBla()
+  except ESomeOtherErr:
+    result = -6
+
+echo blah()
+
+# Issue #7845, raise generic exception
+var x: ref ESomethingGen[int]
+new(x)
+try:
+  raise x
+except ESomethingGen[int] as e:
+  discard
+
+try:
+  raise new(ESomethingGenRef[int])
+except ESomethingGenRef[int] as e:
+  discard
+except:
+  discard
\ No newline at end of file
diff --git a/tests/exception/texcsub.nim b/tests/exception/texcsub.nim
new file mode 100644
index 000000000..463e95613
--- /dev/null
+++ b/tests/exception/texcsub.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "caught!"
+"""
+# Test inheritance for exception matching:
+
+try:
+  raise newException(OSError, "dummy message")
+except Exception:
+  echo "caught!"
+except:
+  echo "wtf!?"
+
+#OUT caught!
diff --git a/tests/exception/tfinally.nim b/tests/exception/tfinally.nim
new file mode 100644
index 000000000..c5b1dd841
--- /dev/null
+++ b/tests/exception/tfinally.nim
@@ -0,0 +1,62 @@
+discard """
+  output: '''
+came
+here
+3
+msg1
+msg2
+finally2
+finally1
+-----------
+except1
+finally1
+except2
+finally2
+'''
+"""
+# Test return in try statement:
+
+proc main: int =
+  try:
+    try:
+      return 1
+    finally:
+      echo("came")
+      return 2
+  finally:
+    echo("here")
+    return 3
+
+echo main() #OUT came here 3
+
+#bug 7204
+proc nested_finally =
+  try:
+    raise newException(KeyError, "msg1")
+  except KeyError as ex:
+    echo ex.msg
+    try:
+      raise newException(ValueError, "msg2")
+    except:
+      echo getCurrentExceptionMsg()
+    finally:
+      echo "finally2"
+  finally:
+    echo "finally1"
+
+nested_finally()
+
+echo "-----------"
+#bug 7414
+try:
+  try:
+    raise newException(Exception, "Hello")
+  except:
+    echo "except1"
+    raise
+  finally:
+    echo "finally1"
+except:
+  echo "except2"
+finally:
+  echo "finally2"
diff --git a/tests/exception/tfinally2.nim b/tests/exception/tfinally2.nim
new file mode 100644
index 000000000..dae1a468a
--- /dev/null
+++ b/tests/exception/tfinally2.nim
@@ -0,0 +1,28 @@
+discard """
+output: '''
+A
+B
+C
+D
+'''
+"""
+# Test break in try statement:
+
+proc main: int =
+  try:
+    block AB:
+      try:
+        try:
+          break AB
+        finally:
+          echo("A")
+        echo("skipped")
+      finally:
+        block B:
+          echo("B")
+      echo("skipped")
+    echo("C")
+  finally:
+    echo("D")
+
+discard main()
diff --git a/tests/exception/tfinally3.nim b/tests/exception/tfinally3.nim
new file mode 100644
index 000000000..9053d397d
--- /dev/null
+++ b/tests/exception/tfinally3.nim
@@ -0,0 +1,27 @@
+discard """
+  outputsub: '''
+false
+Within finally->try
+'''
+  exitCode: 1
+"""
+# Test break in try statement:
+
+proc main: bool =
+  while true:
+    try:
+      return true
+    finally:
+      break
+  return false
+
+echo main() #OUT false
+
+# bug #5871
+try:
+  raise newException(Exception, "First")
+finally:
+  try:
+    raise newException(Exception, "Within finally->try")
+  except:
+    echo getCurrentExceptionMsg()
diff --git a/tests/exception/tfinally4.nim b/tests/exception/tfinally4.nim
new file mode 100644
index 000000000..a7dbbffef
--- /dev/null
+++ b/tests/exception/tfinally4.nim
@@ -0,0 +1,73 @@
+discard """
+  output: '''
+B1
+A1
+1
+B1
+B2
+catch
+A1
+1
+B1
+A1
+A2
+2
+B1
+B2
+catch
+A1
+A2
+0
+B1
+A1
+1
+B1
+B2
+A1
+1
+B1
+A1
+A2
+2
+B1
+B2
+A1
+A2
+3'''
+"""
+
+# More thorough test of return-in-finaly
+
+var raiseEx = true
+var returnA = true
+var returnB = false
+
+proc main: int =
+  try: #A
+    try: #B
+      if raiseEx:
+        raise newException(OSError, "")
+      return 3
+    finally: #B
+      echo "B1"
+      if returnB:
+        return 2
+      echo "B2"
+  except OSError: #A
+    echo "catch"
+  finally: #A
+    echo "A1"
+    if returnA:
+      return 1
+    echo "A2"
+
+for x in [true, false]:
+  for y in [true, false]:
+    for z in [true, false]:
+      # echo "raiseEx: " & $x
+      # echo "returnA: " & $y
+      # echo "returnB: " & $z
+      raiseEx = x
+      returnA = y
+      returnB = z
+      echo main()
diff --git a/tests/exception/tnestedreturn.nim b/tests/exception/tnestedreturn.nim
new file mode 100644
index 000000000..acb83d2c8
--- /dev/null
+++ b/tests/exception/tnestedreturn.nim
@@ -0,0 +1,40 @@
+discard """
+  targets: "c cpp"
+  output: "A\nB\nC\n"
+"""
+
+# Various tests of return nested in double try/except statements
+
+proc test1() =
+
+  defer: echo "A"
+
+  try:
+    raise newException(OSError, "Problem")
+  except OSError:
+    return
+
+test1()
+
+
+proc test2() =
+
+  defer: echo "B"
+
+  try:
+    return
+  except OSError:
+    discard
+
+test2()
+
+proc test3() =
+  try:
+    try:
+      raise newException(OSError, "Problem")
+    except OSError:
+      return
+  finally:
+    echo "C"
+
+test3()
diff --git a/tests/exception/tnestedreturn2.nim b/tests/exception/tnestedreturn2.nim
new file mode 100644
index 000000000..167d09b96
--- /dev/null
+++ b/tests/exception/tnestedreturn2.nim
@@ -0,0 +1,19 @@
+discard """
+  outputsub: "Error: unhandled exception: Problem [OSError]"
+  exitcode: "1"
+"""
+
+proc test4() =
+  try:
+    try:
+      raise newException(OSError, "Problem")
+    except OSError:
+      return
+  finally:
+    discard
+
+# Should cause unhandled exception error,
+# but could cause segmentation fault if
+# exceptions are not handled properly.
+test4()
+raise newException(OSError, "Problem")
diff --git a/tests/exception/treraise.nim b/tests/exception/treraise.nim
new file mode 100644
index 000000000..17a38aa53
--- /dev/null
+++ b/tests/exception/treraise.nim
@@ -0,0 +1,20 @@
+discard """
+  outputsub: "Error: unhandled exception: bla [ESomeOtherErr]"
+  exitcode: "1"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+try:
+  genErrors("errssor!")
+except ESomething:
+  echo("Error happened")
+except:
+  raise
diff --git a/tests/exception/tsetexceptions.nim b/tests/exception/tsetexceptions.nim
new file mode 100644
index 000000000..0e353f43e
--- /dev/null
+++ b/tests/exception/tsetexceptions.nim
@@ -0,0 +1,11 @@
+discard """
+  targets: "c cpp js"
+  joinable: false
+"""
+
+# refs https://github.com/nim-lang/Nim/pull/18247#issuecomment-860877161
+
+let ex = newException(CatchableError, "test")
+setCurrentException(ex)
+doAssert getCurrentException().msg == ex.msg
+doAssert getCurrentExceptionMsg() == ex.msg
diff --git a/tests/exception/tshow_real_exception_name.nim b/tests/exception/tshow_real_exception_name.nim
new file mode 100644
index 000000000..1a708dbd6
--- /dev/null
+++ b/tests/exception/tshow_real_exception_name.nim
@@ -0,0 +1,28 @@
+discard """
+  outputsub: "CustomChildError"
+  exitcode: 1
+"""
+
+type
+  CustomError* = object of Exception
+  CustomChildError* = object of CustomError
+
+  FutureBase* = ref object of RootObj
+    error*: ref Exception
+
+  Future*[T] = ref object of FutureBase
+    v: T
+
+proc fail[T](future: Future[T], error: ref Exception) =
+  future.error = error
+
+proc w1(): Future[int] =
+  result = Future[int]()
+  result.fail(newException(CustomChildError, "abc"))
+
+proc main =
+  var fut = w1()
+  if true:
+    raise fut.error
+
+main()
diff --git a/tests/exception/tunhandledexc.nim b/tests/exception/tunhandledexc.nim
new file mode 100644
index 000000000..6ca311d38
--- /dev/null
+++ b/tests/exception/tunhandledexc.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim $target -d:release $options $file"
+  outputsub: '''tunhandledexc.nim(15)    genErrors
+Error: unhandled exception: bla [ESomeOtherErr]'''
+  exitcode: "1"
+"""
+type
+  ESomething = object of Exception
+  ESomeOtherErr = object of Exception
+
+proc genErrors(s: string) =
+  if s == "error!":
+    raise newException(ESomething, "Test")
+  else:
+    raise newException(EsomeotherErr, "bla")
+
+when true:
+  try: discard except: discard
+
+  try:
+    genErrors("errssor!")
+  except ESomething:
+    echo("Error happened")
diff --git a/tests/exception/twrongexc.nim b/tests/exception/twrongexc.nim
new file mode 100644
index 000000000..d229c5749
--- /dev/null
+++ b/tests/exception/twrongexc.nim
@@ -0,0 +1,8 @@
+discard """
+  outputsub: "Error: unhandled exception:  [ValueError]"
+  exitcode: "1"
+"""
+try:
+  raise newException(ValueError, "")
+except OverflowDefect:
+  echo("Error caught")
diff --git a/tests/exprs/t22604.nim b/tests/exprs/t22604.nim
new file mode 100644
index 000000000..c41cd3dfa
--- /dev/null
+++ b/tests/exprs/t22604.nim
@@ -0,0 +1,36 @@
+# if
+for i in 0..<1:
+  let x =
+    case false
+    of true:
+      42
+    of false:
+      if true:
+        continue
+      else:
+        raiseAssert "Won't get here"
+
+# nested case
+for i in 0..<1:
+  let x =
+    case false
+    of true:
+      42
+    of false:
+      case true
+      of true:
+        continue
+      of false:
+        raiseAssert "Won't get here"
+
+# try except
+for i in 0..<1:
+  let x =
+    case false
+    of true:
+      42
+    of false:
+      try:
+        continue
+      except:
+        raiseAssert "Won't get here"
\ No newline at end of file
diff --git a/tests/exprs/texprstmt.nim b/tests/exprs/texprstmt.nim
new file mode 100644
index 000000000..3c9704650
--- /dev/null
+++ b/tests/exprs/texprstmt.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "expression 'result[1 .. BackwardsIndex(1)]' is of type 'string' and has to be used (or discarded)"
+  line: 10
+"""
+
+# bug #578
+
+proc test: string =
+  result = "blah"
+  result[1 .. ^1]
+
+echo test()
diff --git a/tests/exprs/thighCString.nim b/tests/exprs/thighCString.nim
new file mode 100644
index 000000000..543966df4
--- /dev/null
+++ b/tests/exprs/thighCString.nim
@@ -0,0 +1,6 @@
+discard """
+  output: "5"
+"""
+let test = cstring("foobar")
+
+echo high(test)
diff --git a/tests/exprs/tifexpr_typeinference.nim b/tests/exprs/tifexpr_typeinference.nim
new file mode 100644
index 000000000..ccaea3e80
--- /dev/null
+++ b/tests/exprs/tifexpr_typeinference.nim
@@ -0,0 +1,24 @@
+discard """
+action: compile
+"""
+
+#bug #712
+
+import tables
+
+proc test(): Table[string, string] =
+  discard
+
+proc test2(): Table[string, string] =
+  discard
+
+var x = 5
+let blah =
+  case x
+  of 5:
+    test2()
+  of 2:
+    test()
+  else: test()
+
+echo blah.len
diff --git a/tests/exprs/tresultwarning.nim b/tests/exprs/tresultwarning.nim
new file mode 100644
index 000000000..28dabfdb1
--- /dev/null
+++ b/tests/exprs/tresultwarning.nim
@@ -0,0 +1,6 @@
+discard """
+  nimout: "tresultwarning.nim(6, 7) Warning: Special variable 'result' is shadowed. [ResultShadowed]"
+"""
+
+proc test(): string =
+  var result = "foo"
diff --git a/tests/exprs/tstmtexp.nim b/tests/exprs/tstmtexp.nim
new file mode 100644
index 000000000..0ae866497
--- /dev/null
+++ b/tests/exprs/tstmtexp.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "expression '5' is of type 'int literal(5)' and has to be used (or discarded)"
+  file: "tstmtexp.nim"
+  line: 8
+"""
+# Test 3
+
+1+4
diff --git a/tests/exprs/tstmtexprs.nim b/tests/exprs/tstmtexprs.nim
new file mode 100644
index 000000000..615c36024
--- /dev/null
+++ b/tests/exprs/tstmtexprs.nim
@@ -0,0 +1,163 @@
+discard """
+  output: '''24
+(bar: "bar")
+1244
+6
+abcdefghijklmnopqrstuvwxyz
+145 23
+3
+2'''
+"""
+
+import strutils
+
+const fac4 = (var x = 1; for i in 1..4: x *= i; x)
+
+echo fac4
+
+when true:
+  proc test(foo: proc (x, y: int): bool) =
+    echo foo(5, 5)
+
+
+  type Foo = object
+    bar: string
+
+  proc newfoo(): Foo =
+    result.bar = "bar"
+
+  echo($newfoo())
+
+
+  proc retInt(x, y: int): int =
+    if (var yy = 0; yy != 0):
+      echo yy
+    else:
+      echo(try: parseInt("1244") except ValueError: -1)
+    result = case x
+             of 23: 3
+             of 64:
+                    case y
+                    of 1: 2
+                    of 2: 3
+                    of 3: 6
+                    else: 8
+             else: 1
+
+  echo retInt(64, 3)
+
+  proc buildString(): string =
+    result = ""
+    for x in 'a'..'z':
+      result.add(x)
+
+  echo buildString()
+
+#test(
+#  proc (x, y: int): bool =
+#  if x == 5: return true
+#  if x == 2: return false
+#  if y == 78: return true
+#)
+
+proc q(): int {.discardable.} = 145
+proc p(): int =
+  q()
+
+proc p2(a: int): int =
+  # result enforces a void context:
+  if a == 2:
+    result = 23
+  q()
+
+echo p(), " ", p2(2)
+
+proc semiProblem() =
+  if false: echo "aye"; echo "indeed"
+
+semiProblem()
+
+
+# bug #844
+
+import json
+proc parseResponse(): JsonNode =
+  result = % { "key1": % { "key2": % "value" } }
+  for key, val in result["key1"]:
+    var excMsg = key & "("
+    if (var n=result["key2"]; n != nil):
+      excMsg &= n.str
+    raise newException(CatchableError, excMsg)
+
+
+
+#bug #992
+var se = @[1,2]
+let b = (se[1] = 1; 1)
+
+
+# bug #1161
+
+type
+  PFooBase = ref object of RootRef
+    field: int
+
+  PFoo[T] = ref object of PFooBase
+    field2: T
+
+var testIf =
+  if true:
+    2
+  else:
+    3
+
+var testCase =
+  case 8
+  of 8: 9
+  else: 10
+
+var testTry =
+  try:
+    PFoo[string](field: 3, field2: "asfasf")
+  except:
+    PFooBase(field: 5)
+
+echo(testTry.field)
+
+# bug #6166
+
+proc quo(op: proc (x: int): bool): int =
+  result =
+     if op(3):
+        2
+     else:
+        0
+
+echo(
+  if true:
+     quo do (a: int) -> bool:
+        a mod 2 != 0
+  else:
+     quo do (a: int) -> bool:
+        a mod 3 != 0
+)
+
+# bug #6980
+
+proc fooBool: bool {.discardable.} =
+  true
+
+if true:
+  fooBool()
+else:
+  raise newException(ValueError, "argh")
+
+# bug #5374
+
+proc test1(): int64 {.discardable.} = discard
+proc test2(): int {.discardable.} = discard
+
+if true:
+  test1()
+else:
+  test2()
diff --git a/tests/float/tfloat1.nim b/tests/float/tfloat1.nim
new file mode 100644
index 000000000..d3497f24c
--- /dev/null
+++ b/tests/float/tfloat1.nim
@@ -0,0 +1,12 @@
+discard """
+  outputsub: "Error: unhandled exception: FPU operation caused an overflow [FloatOverflowDefect]"
+  exitcode: "1"
+"""
+# Test new floating point exceptions
+
+{.floatChecks: on.}
+
+var x = 0.8
+var y = 0.0
+
+echo x / y #OUT Error: unhandled exception: FPU operation caused an overflow
diff --git a/tests/float/tfloat2.nim b/tests/float/tfloat2.nim
new file mode 100644
index 000000000..1de63dde3
--- /dev/null
+++ b/tests/float/tfloat2.nim
@@ -0,0 +1,12 @@
+discard """
+  outputsub: "Error: unhandled exception: FPU operation caused a NaN result [FloatInvalidOpDefect]"
+  exitcode: "1"
+"""
+# Test new floating point exceptions
+
+{.floatChecks: on.}
+
+var x = 0.0
+var y = 0.0
+
+echo x / y #OUT Error: unhandled exception: FPU operation caused a NaN result
diff --git a/tests/float/tfloat3.nim b/tests/float/tfloat3.nim
new file mode 100644
index 000000000..215470cfc
--- /dev/null
+++ b/tests/float/tfloat3.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''
+Nim 3.4368930843, 0.3299290698
+C double: 3.4368930843, 0.3299290698'''
+"""
+
+import math, strutils
+
+{.emit: """
+void printFloats(void) {
+  double y = 1.234567890123456789;
+  printf("C double: %.10f, %.10f\n", exp(y), cos(y));
+}
+""".}
+
+proc c_printf(frmt: cstring) {.importc: "printf", header: "<stdio.h>", varargs.}
+proc printFloats {.importc, nodecl.}
+
+var x: float = 1.234567890123456789
+c_printf("Nim %.10f, %.10f\n", exp(x), cos(x))
+printFloats()
diff --git a/tests/float/tfloat4.nim b/tests/float/tfloat4.nim
new file mode 100644
index 000000000..2bb61eb58
--- /dev/null
+++ b/tests/float/tfloat4.nim
@@ -0,0 +1,69 @@
+discard """
+  output: "passed all tests."
+"""
+
+import strutils
+
+proc c_sprintf(buf, fmt: cstring) {.importc:"sprintf", header: "<stdio.h>", varargs.}
+
+proc floatToStr(f: float64): string =
+  var buffer: array[128, char]
+  c_sprintf(cast[cstring](addr buffer), "%.16e", f)
+  result = ""
+  for ch in buffer:
+    if ch == '\0':
+      return
+    add(result, ch)
+
+
+let testFloats = [
+  "0", "-0", "0.", "0.0", "-0.", "-0.0", "-1", "1", "1.", ".3", "3.3", "-.3", "-99.99",
+  "1.1e10", "-2e100", "1.234e-10", "1.234e+10",
+  "-inf", "inf", "+inf",
+  "3.14159265358979323846264338327950288",
+  "1.57079632679489661923132169163975144",
+  "0.785398163397448309615660845819875721",
+  "1.41421356237309504880168872420969808",
+  "0.707106781186547524400844362104849039",
+  "2.71828182845904523536028747135266250",
+  "0.00097656250000000021684043449710088680149056017398834228515625"
+]
+
+when not defined(windows):
+  # Windows' sprintf produces niceties like -1.#INF...
+  for num in testFloats:
+    doAssert num.parseFloat.floatToStr.parseFloat == num.parseFloat
+
+doAssert "0".parseFloat == 0.0
+doAssert "-.1".parseFloat == -0.1
+doAssert "2.5e1".parseFloat == 25.0
+doAssert "1e10".parseFloat == 10_000_000_000.0
+doAssert "0.000_005".parseFloat == 5.000_000e-6
+doAssert "1.234_567e+2".parseFloat == 123.4567
+doAssert "1e1_00".parseFloat == "1e100".parseFloat
+doAssert "3.1415926535897932384626433".parseFloat ==
+       3.1415926535897932384626433
+doAssert "2.71828182845904523536028747".parseFloat ==
+       2.71828182845904523536028747
+doAssert 0.00097656250000000021684043449710088680149056017398834228515625 ==
+     "0.00097656250000000021684043449710088680149056017398834228515625".parseFloat
+doAssert 0.00998333 == ".00998333".parseFloat
+doAssert 0.00128333 == ".00128333".parseFloat
+doAssert 999999999999999.0 == "999999999999999.0".parseFloat
+doAssert 9999999999999999.0 == "9999999999999999.0".parseFloat
+doAssert 0.999999999999999 == ".999999999999999".parseFloat
+doAssert 0.9999999999999999 == ".9999999999999999".parseFloat
+
+# bug #18400
+var s = [-13.888888'f32]
+doAssert $s[0] == "-13.888888"
+var x = 1.23456789012345'f32
+doAssert $x == "1.2345679"
+
+# bug #21847
+doAssert parseFloat"0e+42" == 0.0
+doAssert parseFloat"0e+42949672969" == 0.0
+doAssert parseFloat"0e+42949672970" == 0.0
+doAssert parseFloat"0e+42949623223346323563272970" == 0.0
+
+echo("passed all tests.")
diff --git a/tests/float/tfloat5.nim b/tests/float/tfloat5.nim
new file mode 100644
index 000000000..0708838fc
--- /dev/null
+++ b/tests/float/tfloat5.nim
@@ -0,0 +1,16 @@
+discard """
+output: '''
+0 : 0.0
+0 : 0.0
+0 : 0.0
+0 : 0.0
+'''
+"""
+
+import parseutils
+
+var f: float
+echo "*".parseFloat(f), " : ", f
+echo "/".parseFloat(f), " : ", f
+echo "+".parseFloat(f), " : ", f
+echo "-".parseFloat(f), " : ", f
diff --git a/tests/float/tfloat7.nim b/tests/float/tfloat7.nim
new file mode 100644
index 000000000..a6d7af10b
--- /dev/null
+++ b/tests/float/tfloat7.nim
@@ -0,0 +1,27 @@
+discard """
+output: '''
+passed.
+passed.
+passed.
+passed.
+passed.
+passed.
+passed.
+'''
+"""
+
+import strutils
+template expect_fail(x) =
+  try:
+    discard x
+    echo("expected to fail!")
+  except ValueError:
+    echo("passed.")
+
+expect_fail("1_0._00_0001".parseFloat())
+expect_fail("_1_0_00.0001".parseFloat())
+expect_fail("10.00.01".parseFloat())
+expect_fail("10.00E_01".parseFloat())
+expect_fail("10.00E_01".parseFloat())
+expect_fail("10.00E".parseFloat())
+expect_fail("10.00A".parseFloat())
diff --git a/tests/float/tfloatmod.nim b/tests/float/tfloatmod.nim
new file mode 100644
index 000000000..37546a64c
--- /dev/null
+++ b/tests/float/tfloatmod.nim
@@ -0,0 +1,130 @@
+discard """
+  targets: "c cpp js"
+  output: "ok"
+  exitcode: "0"
+"""
+
+# Test `mod` on float64 both at compiletime and at runtime
+import math
+
+# Testdata from golang
+const testValues: array[10, tuple[f64, expected: float64]] = [
+  (4.9790119248836735e+00, 4.197615023265299782906368e-02),
+  (7.7388724745781045e+00, 2.261127525421895434476482e+00),
+  (-2.7688005719200159e-01, 3.231794108794261433104108e-02),
+  (-5.0106036182710749e+00, 4.989396381728925078391512e+00),
+  (9.6362937071984173e+00, 3.637062928015826201999516e-01),
+  (2.9263772392439646e+00, 1.220868282268106064236690e+00),
+  (5.2290834314593066e+00, 4.770916568540693347699744e+00),
+  (2.7279399104360102e+00, 1.816180268691969246219742e+00),
+  (1.8253080916808550e+00, 8.734595415957246977711748e-01),
+  (-8.6859247685756013e+00, 1.314075231424398637614104e+00)]
+
+const simpleTestData = [
+  (5.0, 3.0, 2.0),
+  (5.0, -3.0, 2.0),
+  (-5.0, 3.0, -2.0),
+  (-5.0, -3.0, -2.0),
+  (10.0, 1.0, 0.0),
+  (10.0, 0.5, 0.0),
+  (10.0, 1.5, 1.0),
+  (-10.0, 1.0, -0.0),
+  (-10.0, 0.5, -0.0),
+  (-10.0, 1.5, -1.0),
+  (1.5, 1.0, 0.5),
+  (1.25, 1.0, 0.25),
+  (1.125, 1.0, 0.125)
+  ]
+
+const specialCases = [
+  (-Inf, -Inf, Nan),
+  (-Inf, -Pi, Nan),
+  (-Inf, 0.0, Nan),
+  (-Inf, Pi, Nan),
+  (-Inf, Inf, Nan),
+  (-Inf, Nan, Nan),
+  (-PI, -Inf, -PI),
+  (-PI, 0.0, Nan),
+  (-PI, Inf, -PI),
+  (-PI, Nan, Nan),
+  (-0.0, -Inf, -0.0),
+  (-0.0, 0.0, Nan),
+  (-0.0, Inf, -0.0),
+  (-0.0, Nan, Nan),
+  (0.0, -Inf, 0.0),
+  (0.0, 0.0, Nan),
+  (0.0, Inf, 0.0),
+  (0.0, Nan, Nan),
+  (PI, -Inf, PI),
+  (PI, 0.0, Nan),
+  (PI, Inf, PI),
+  (PI, Nan, Nan),
+  (Inf, -Inf, Nan),
+  (Inf, -PI, Nan),
+  (Inf, 0.0, Nan),
+  (Inf, PI, Nan),
+  (Inf, Inf, Nan),
+  (Inf, Nan, Nan),
+  (Nan, -Inf, Nan),
+  (Nan, -PI, Nan),
+  (Nan, 0.0, Nan),
+  (Nan, PI, Nan),
+  (Nan, Inf, Nan),
+  (Nan, Nan, Nan)]
+
+const extremeValues = [
+  (5.9790119248836734e+200, 1.1258465975523544, 0.6447968302508578),
+  (1.0e-100, 1.0e100, 1.0e-100)]
+
+proc errmsg(x, y, r, expected: float64): string =
+  $x & " mod " & $y & " == " & $r & " but expected " & $expected
+
+proc golangtest() =
+  let x = 10.0
+  for tpl in testValues:
+    let (y, expected) = tpl
+    let r = x mod y
+    doAssert(r == expected, errmsg(x, y, r, expected))
+
+proc simpletest() =
+  for tpl in simpleTestData:
+    let(x, y, expected) = tpl
+    let r = x mod y
+    doAssert(r == expected, errmsg(x, y, r, expected))
+
+proc testSpecialCases() =
+  proc isnan(f: float64): bool =
+    case classify(f)
+    of fcNan:
+      result = true
+    else:
+      result = false
+
+  for tpl in specialCases:
+    let(x, y, expected) = tpl
+    let r = x mod y
+    doAssert((r == expected) or (r.isnan and expected.isnan),
+              errmsg(x, y, r, expected))
+
+proc testExtremeValues() =
+  for tpl in extremeValues:
+    let (x, y, expected) = tpl
+    let r = x mod y
+    doAssert(r == expected, errmsg(x, y, r, expected))
+
+static:
+  # compiletime evaluation
+  golangtest()
+  simpletest()
+  testSpecialCases()
+  testExtremeValues()
+
+proc main() =
+  # runtime evaluation
+  golangtest()
+  simpletest()
+  testSpecialCases()
+  testExtremeValues()
+
+main()
+echo "ok"
diff --git a/tests/float/tfloatnan.nim b/tests/float/tfloatnan.nim
new file mode 100644
index 000000000..9e3dd94f6
--- /dev/null
+++ b/tests/float/tfloatnan.nim
@@ -0,0 +1,57 @@
+discard """
+output: '''
+Nim: nan
+Nim: nan (float)
+Nim: nan (double)
+'''
+"""
+
+let f = NaN
+echo "Nim: ", f
+
+let f32: float32 = NaN
+echo "Nim: ", f32, " (float)"
+
+let f64: float64 = NaN
+echo "Nim: ", f64, " (double)"
+
+block: # bug #10305
+  # with `-O3 -ffast-math`, generated C/C++ code is not nan compliant
+  # user can pass `--passC:-ffast-math` if he doesn't care.
+  proc fun() =
+    # this was previously failing at compile time with a nim compiler
+    # that was compiled with `nim cpp -d:release`
+    let a1 = 0.0
+    let a = 0.0/a1
+    let b1 = a == 0.0
+    let b2 = a == a
+    doAssert not b1
+    doAssert not b2
+
+  proc fun2(i: int) =
+    # this was previously failing simply with `nim cpp -d:release`; the
+    # difference with above example is that optimization (const folding) can't
+    # take place in this example to hide the non-compliant nan bug.
+    let a = 0.0/(i.float)
+    let b1 = a == 0.0
+    let b2 = a == a
+    doAssert not b1
+    doAssert not b2
+
+  static: fun()
+  fun()
+  fun2(0)
+
+template main() =
+  # xxx move all tests under here
+  block: # bug #16469
+    let a1 = 0.0
+    let a2 = -0.0
+    let a3 = 1.0 / a1
+    let a4 = 1.0 / a2
+    doAssert a3 == Inf
+    doAssert a4 == -Inf
+    doAssert $(a1, a2, a3, a4) == "(0.0, -0.0, inf, -inf)"
+
+static: main()
+main()
diff --git a/tests/float/tfloatrange.nim b/tests/float/tfloatrange.nim
new file mode 100644
index 000000000..d345166f4
--- /dev/null
+++ b/tests/float/tfloatrange.nim
@@ -0,0 +1,50 @@
+discard """
+  cmd: "nim c -d:release --rangeChecks:on $file"
+  disabled: "windows"
+  output: '''StrictPositiveRange
+float
+range fail expected
+range fail expected
+'''
+"""
+import math, fenv
+
+type
+  Positive = range[0.0..Inf]
+  StrictPositive = range[minimumPositiveValue(float)..Inf]
+  Negative32 = range[-maximumPositiveValue(float32) .. -1.0'f32]
+
+proc myoverload(x: float) =
+  echo "float"
+
+proc myoverload(x: Positive) =
+  echo "PositiveRange"
+
+proc myoverload(x: StrictPositive) =
+  echo "StrictPositiveRange"
+
+let x = 9.0.StrictPositive
+myoverload(x)
+myoverload(9.0)
+
+doAssert(sqrt(x) == 3.0)
+
+var z = -10.0
+try:
+  myoverload(StrictPositive(z))
+except:
+  echo "range fail expected"
+
+
+proc strictOnlyProc(x: StrictPositive): bool =
+  if x > 1.0: true else: false
+
+let x2 = 5.0.Positive
+doAssert(strictOnlyProc(x2))
+
+try:
+  let x4 = 0.0.Positive
+  discard strictOnlyProc(x4)
+except:
+  echo "range fail expected"
+
diff --git a/tests/float/tfloats.nim b/tests/float/tfloats.nim
new file mode 100644
index 000000000..aaed2d615
--- /dev/null
+++ b/tests/float/tfloats.nim
@@ -0,0 +1,163 @@
+discard """
+  matrix: "-d:nimPreviewFloatRoundtrip; -u:nimPreviewFloatRoundtrip"
+  targets: "c cpp js"
+"""
+
+#[
+xxx merge all or most float tests into this file
+]#
+
+import std/[fenv, math, strutils]
+import stdtest/testutils
+
+proc equalsOrNaNs(a, b: float): bool =
+  if isNaN(a): isNaN(b)
+  elif a == 0:
+    b == 0 and signbit(a) == signbit(b)
+  else:
+    a == b
+
+template reject(a) =
+  doAssertRaises(ValueError): discard parseFloat(a)
+
+template main =
+  block:
+    proc test(a: string, b: float) =
+      let a2 = a.parseFloat
+      doAssert equalsOrNaNs(a2, b), $(a, a2, b)
+    test "0.00_0001", 1E-6
+    test "0.00__00_01", 1E-6
+    test "0.0_01", 0.001
+    test "0.00_000_1", 1E-6
+    test "0.00000_1", 1E-6
+    test "1_0.00_0001", 10.000001
+    test "1__00.00_0001", 1_00.000001
+    test "inf", Inf
+    test "-inf", -Inf
+    test "-Inf", -Inf
+    test "-INF", -Inf
+    test "NaN", NaN
+    test "-nan", NaN
+    test ".1", 0.1
+    test "-.1", -0.1
+    test "-0", -0.0
+    test "-0", -0'f # see #18246, -0 won't work
+    test ".1e-1", 0.1e-1
+    test "0_1_2_3.0_1_2_3E+0_1_2", 123.0123e12
+    test "0_1_2.e-0", 12e0
+    test "0_1_2e-0", 12e0
+    test "-0e0", -0.0
+    test "-0e-0", -0.0
+
+  reject "a"
+  reject ""
+  reject "e1"
+  reject "infa"
+  reject "infe1"
+  reject "_"
+  reject "1e"
+
+  when false: # gray area; these numbers should probably be invalid
+    reject "1_"
+    reject "1_.0"
+    reject "1.0_"
+
+  block: # bugs mentioned in https://github.com/nim-lang/Nim/pull/18504#issuecomment-881635317
+    block: # example 1
+      let a = 0.1+0.2
+      doAssert a != 0.3
+      when defined(nimPreviewFloatRoundtrip):
+        doAssert $a == "0.30000000000000004"
+      else:
+        whenRuntimeJs: discard
+        do: doAssert $a == "0.3"
+    block: # example 2
+      const a = 0.1+0.2
+      when defined(nimPreviewFloatRoundtrip):
+        doAssert $($a, a) == """("0.30000000000000004", 0.30000000000000004)"""
+      else:
+        whenRuntimeJs: discard
+        do: doAssert $($a, a) == """("0.3", 0.3)"""
+    block: # example 3
+      const a1 = 0.1+0.2
+      let a2 = a1
+      doAssert a1 != 0.3
+      when defined(nimPreviewFloatRoundtrip):
+        doAssert $[$a1, $a2] == """["0.30000000000000004", "0.30000000000000004"]"""
+      else:
+        whenRuntimeJs: discard
+        do: doAssert $[$a1, $a2] == """["0.3", "0.3"]"""
+
+  when defined(nimPreviewFloatRoundtrip):
+    block: # bug #18148
+      var a = 1.1'f32
+      doAssert $a == "1.1", $a # was failing
+
+    block: # bug #18400
+      block:
+        let a1 = 0.1'f32
+        let a2 = 0.2'f32
+        let a3 = a1 + a2
+        var s = ""
+        s.addFloat(a3)
+        whenVMorJs: discard # xxx refs #12884
+        do:
+          doAssert a3 == 0.3'f32
+          doAssert $a3 == "0.3"
+
+      block:
+        let a1 = 0.1
+        let a2 = 0.2
+        let a3 = a1 + a2
+        var s = ""
+        s.addFloat(a3)
+        doAssert a3 != 0.3
+        doAssert $a3 == "0.30000000000000004"
+
+      block:
+        var s = [-13.888888'f32]
+        whenRuntimeJs: discard
+        do:
+          doAssert $s == "[-13.888888]"
+          doAssert $s[0] == "-13.888888"
+
+    block: # bug #7717
+      proc test(f: float) =
+        let f2 = $f
+        let f3 = parseFloat(f2)
+        doAssert equalsOrNaNs(f, f3), $(f, f2, f3)
+      test 1.0 + epsilon(float64)
+      test 1000000.0000000123
+      test log2(100000.0)
+      test maximumPositiveValue(float32)
+      test maximumPositiveValue(float64)
+      test minimumPositiveValue(float32)
+      test minimumPositiveValue(float64)
+
+    block: # bug #12884
+      block: # example 1
+        const x0: float32 = 1.32
+        let x1 = 1.32
+        let x2 = 1.32'f32
+        var x3: float32 = 1.32
+        doAssert $(x0, x1, x2, x3) == "(1.32, 1.32, 1.32, 1.32)"
+      block: # example https://github.com/nim-lang/Nim/issues/12884#issuecomment-564967962
+        let x = float(1.32'f32)
+        when nimvm: discard # xxx prints 1.3
+        else:
+          when not defined(js):
+            doAssert $x == "1.3200000524520874"
+        doAssert $1.32 == "1.32"
+        doAssert $1.32'f32 == "1.32"
+        let x2 = 1.32'f32
+        doAssert $x2 == "1.32"
+      block:
+        var x = 1.23456789012345'f32
+        when nimvm:
+          discard # xxx, refs #12884
+        else:
+          doAssert x == 1.2345679'f32
+          doAssert $x == "1.2345679"
+
+static: main()
+main()
diff --git a/tests/float/tissue5821.nim b/tests/float/tissue5821.nim
new file mode 100644
index 000000000..c4f561f09
--- /dev/null
+++ b/tests/float/tissue5821.nim
@@ -0,0 +1,15 @@
+discard """
+output: "ok"
+"""
+
+proc main(): void =
+  let a: float32 = 47.11'f32
+  doAssert a == 47.11'f32
+
+  let b: float64 = 10.234402823e+38'f64
+  doAssert b != 10.123402823e+38'f64
+  doAssert b == 10.234402823e+38'f64
+
+  echo "ok"
+
+main()
diff --git a/tests/float/tlenientops.nim b/tests/float/tlenientops.nim
new file mode 100644
index 000000000..586580670
--- /dev/null
+++ b/tests/float/tlenientops.nim
@@ -0,0 +1,100 @@
+discard """
+  exitcode: 0
+  output: ""
+"""
+
+import lenientops
+
+proc `~=`[T](a, b: T): bool = abs(a - b) < 1e-7
+
+block: # math binary operators
+  let i = 1
+  let f = 2.0
+
+  doAssert i + f ~= 3
+  doAssert f + i ~= 3
+
+  doAssert i - f ~= -1
+  doAssert f - i ~= 1
+
+  doAssert i * f ~= 2
+  doAssert f * i ~= 2
+
+  doAssert i / f ~= 0.5
+  doAssert f / i ~= 2
+
+block: # comparison operators
+  doAssert 1.int < 2.float
+  doAssert 1.float < 2.int
+  doAssert 1.int <= 2.float
+  doAssert 1.float <= 2.int
+  doAssert 2.int >= 1.float
+  doAssert 2.float >= 1.int
+  doAssert 2.int > 1.float
+  doAssert 2.float > 1.int
+
+block: # all type combinations
+  let i = 1
+  let f = 2.0
+
+  doAssert i.int + f.float ~= 3
+  doAssert i.int + f.float32 ~= 3
+  doAssert i.int + f.float64 ~= 3
+  doAssert i.int8 + f.float ~= 3
+  doAssert i.int8 + f.float32 ~= 3
+  doAssert i.int8 + f.float64 ~= 3
+  doAssert i.int16 + f.float ~= 3
+  doAssert i.int16 + f.float32 ~= 3
+  doAssert i.int16 + f.float64 ~= 3
+  doAssert i.int32 + f.float ~= 3
+  doAssert i.int32 + f.float32 ~= 3
+  doAssert i.int32 + f.float64 ~= 3
+  doAssert i.int64 + f.float ~= 3
+  doAssert i.int64 + f.float32 ~= 3
+  doAssert i.int64 + f.float64 ~= 3
+  doAssert i.uint + f.float ~= 3
+  doAssert i.uint + f.float32 ~= 3
+  doAssert i.uint + f.float64 ~= 3
+  doAssert i.uint8 + f.float ~= 3
+  doAssert i.uint8 + f.float32 ~= 3
+  doAssert i.uint8 + f.float64 ~= 3
+  doAssert i.uint16 + f.float ~= 3
+  doAssert i.uint16 + f.float32 ~= 3
+  doAssert i.uint16 + f.float64 ~= 3
+  doAssert i.uint32 + f.float ~= 3
+  doAssert i.uint32 + f.float32 ~= 3
+  doAssert i.uint32 + f.float64 ~= 3
+  doAssert i.uint64 + f.float ~= 3
+  doAssert i.uint64 + f.float32 ~= 3
+  doAssert i.uint64 + f.float64 ~= 3
+
+  doAssert f.float + i.int  ~= 3
+  doAssert f.float32 + i.int ~= 3
+  doAssert f.float64 + i.int ~= 3
+  doAssert f.float + i.int8 ~= 3
+  doAssert f.float32 + i.int8 ~= 3
+  doAssert f.float64 + i.int8 ~= 3
+  doAssert f.float + i.int16 ~= 3
+  doAssert f.float32 + i.int16 ~= 3
+  doAssert f.float64 + i.int16 ~= 3
+  doAssert f.float + i.int32 ~= 3
+  doAssert f.float32 + i.int32 ~= 3
+  doAssert f.float64 + i.int32 ~= 3
+  doAssert f.float + i.int64 ~= 3
+  doAssert f.float32 + i.int64 ~= 3
+  doAssert f.float64 + i.int64 ~= 3
+  doAssert f.float + i.uint ~= 3
+  doAssert f.float32 + i.uint ~= 3
+  doAssert f.float64 + i.uint ~= 3
+  doAssert f.float + i.uint8 ~= 3
+  doAssert f.float32 + i.uint8 ~= 3
+  doAssert f.float64 + i.uint8 ~= 3
+  doAssert f.float + i.uint16 ~= 3
+  doAssert f.float32 + i.uint16 ~= 3
+  doAssert f.float64 + i.uint16 ~= 3
+  doAssert f.float + i.uint32 ~= 3
+  doAssert f.float32 + i.uint32 ~= 3
+  doAssert f.float64 + i.uint32 ~= 3
+  doAssert f.float + i.uint64 ~= 3
+  doAssert f.float32 + i.uint64 ~= 3
+  doAssert f.float64 + i.uint64 ~= 3
diff --git a/tests/fragmentation/data.nim b/tests/fragmentation/data.nim
new file mode 100644
index 000000000..d14123c0f
--- /dev/null
+++ b/tests/fragmentation/data.nim
@@ -0,0 +1,7629 @@
+
+const sizes* = [
+  643584,
+  140800,
+  802,
+  2464928,
+  488122,
+  1161601,
+  861051,
+  1413,
+  389,
+  2412032,
+  328704,
+  323488,
+  484864,
+  31232,
+  38400,
+  87552,
+  328704,
+  242176,
+  55808,
+  32256,
+  15360,
+  15080,
+  567074,
+  1390,
+  1390,
+  366080,
+  186536,
+  314368,
+  4154,
+  3017582,
+  62658,
+  3874662,
+  227,
+  126616,
+  290,
+  261792,
+  287,
+  151200,
+  293,
+  34976,
+  293,
+  28840,
+  296,
+  20664,
+  314,
+  223232,
+  288,
+  53248,
+  326,
+  12800,
+  312,
+  473600,
+  306,
+  2676224,
+  308,
+  2846720,
+  308,
+  563712,
+  308,
+  567296,
+  308,
+  576000,
+  308,
+  577024,
+  308,
+  577536,
+  308,
+  577536,
+  308,
+  578560,
+  308,
+  578560,
+  308,
+  145920,
+  310,
+  159232,
+  312,
+  364544,
+  310,
+  178176,
+  312,
+  8032448,
+  323,
+  29392,
+  332,
+  35112,
+  394,
+  85768,
+  371,
+  88864,
+  385,
+  23840,
+  385,
+  176128,
+  386,
+  126976,
+  389,
+  24800,
+  401,
+  118784,
+  379,
+  21792,
+  385,
+  259152,
+  385,
+  172032,
+  389,
+  40960,
+  389,
+  114688,
+  403,
+  57344,
+  407,
+  7680,
+  407,
+  126216,
+  373,
+  29952,
+  367,
+  148768,
+  385,
+  27384,
+  362,
+  24832,
+  362,
+  50944,
+  364,
+  20136,
+  302,
+  32416,
+  293,
+  69296,
+  305,
+  36016,
+  308,
+  89784,
+  305,
+  5120,
+  305,
+  49152,
+  320,
+  30424,
+  331,
+  12288,
+  326,
+  62976,
+  69120,
+  72192,
+  503808,
+  77824,
+  382144,
+  163840,
+  88728,
+  1581,
+  1718096,
+  66728,
+  82172,
+  116756,
+  4554752,
+  59342,
+  45794,
+  39284,
+  66384,
+  60294,
+  83748,
+  83748,
+  262148,
+  20320,
+  28288,
+  382,
+  3072,
+  4222976,
+  161,
+  1737888,
+  2975744,
+  487424,
+  258048,
+  113664,
+  372736,
+  261632,
+  5287936,
+  80896,
+  89600,
+  503808,
+  77824,
+  554176,
+  163840,
+  84632,
+  1581,
+  1714000,
+  66728,
+  82172,
+  116756,
+  4571136,
+  59342,
+  45794,
+  39284,
+  66384,
+  60294,
+  83748,
+  83748,
+  262148,
+  20320,
+  28288,
+  4006400,
+  161,
+  2256032,
+  3150336,
+  503296,
+  245760,
+  133120,
+  358400,
+  283136,
+  5296128,
+  10752,
+  507904,
+  315392,
+  11264,
+  921600,
+  7680,
+  118784,
+  166560,
+  13312,
+  5120,
+  18768,
+  52736,
+  8192,
+  77824,
+  6656,
+  106496,
+  389120,
+  733184,
+  53248,
+  36864,
+  36864,
+  655360,
+  139264,
+  802816,
+  169864,
+  77824,
+  10752,
+  94208,
+  17808,
+  40960,
+  36864,
+  749568,
+  45056,
+  188416,
+  28672,
+  16384,
+  69632,
+  102400,
+  11776,
+  10752,
+  290816,
+  36864,
+  36864,
+  667648,
+  53248,
+  49152,
+  200704,
+  45056,
+  40960,
+  77824,
+  10240,
+  9216,
+  77504,
+  161472,
+  163528,
+  26304,
+  26312,
+  96448,
+  99016,
+  19648,
+  19656,
+  127680,
+  127680,
+  364224,
+  323272,
+  73408,
+  71368,
+  24776,
+  138944,
+  128200,
+  27328,
+  48832,
+  37576,
+  32960,
+  52928,
+  40128,
+  89792,
+  80584,
+  25792,
+  499392,
+  504520,
+  163520,
+  167624,
+  36032,
+  36040,
+  138944,
+  127688,
+  4208320,
+  4839104,
+  77504,
+  81608,
+  2768576,
+  2757832,
+  331456,
+  321728,
+  65224,
+  65216,
+  56008,
+  163520,
+  154816,
+  48832,
+  77504,
+  62656,
+  48832,
+  77504,
+  50888,
+  57024,
+  47296,
+  52928,
+  40640,
+  71360,
+  71360,
+  22208,
+  22208,
+  57024,
+  45768,
+  48832,
+  48840,
+  3720896,
+  4037832,
+  790208,
+  868040,
+  230592,
+  230592,
+  20160,
+  20160,
+  29376,
+  31944,
+  1355456,
+  1419976,
+  839360,
+  851656,
+  32960,
+  36040,
+  179904,
+  265920,
+  85696,
+  85696,
+  33472,
+  33472,
+  392896,
+  391872,
+  397008,
+  48832,
+  48832,
+  48832,
+  48832,
+  52928,
+  48832,
+  48832,
+  57024,
+  36032,
+  36032,
+  48832,
+  48840,
+  48840,
+  48832,
+  52928,
+  48832,
+  48832,
+  57024,
+  36032,
+  36032,
+  48848,
+  48848,
+  48848,
+  48848,
+  52944,
+  48848,
+  48848,
+  57040,
+  36048,
+  36048,
+  57024,
+  45760,
+  20160,
+  20160,
+  34528,
+  13024,
+  397312,
+  5120,
+  28672,
+  659456,
+  372736,
+  110592,
+  9216,
+  9728,
+  61440,
+  28672,
+  5632,
+  41984,
+  29736,
+  20056,
+  216632,
+  110184,
+  27032,
+  37472,
+  31592,
+  24376,
+  102728,
+  280912,
+  27472,
+  27936,
+  23392,
+  56624,
+  57216,
+  38744,
+  51016,
+  36696,
+  48896,
+  53024,
+  32032,
+  34120,
+  34120,
+  20256,
+  107848,
+  109928,
+  1267040,
+  46984,
+  496544,
+  1174384,
+  762288,
+  101744,
+  32664,
+  95712,
+  48480,
+  365344,
+  98448,
+  86440,
+  35312,
+  37704,
+  75664,
+  101672,
+  47912,
+  15872,
+  11168,
+  22856,
+  22856,
+  506616,
+  556824,
+  61784,
+  30008,
+  44848,
+  81816,
+  31528,
+  32768,
+  12800,
+  27000,
+  155000,
+  14712,
+  14712,
+  14712,
+  15224,
+  14712,
+  15224,
+  14712,
+  14712,
+  14712,
+  15736,
+  14712,
+  13688,
+  14200,
+  122232,
+  14200,
+  14200,
+  14200,
+  14200,
+  14200,
+  14200,
+  14712,
+  13688,
+  14200,
+  14200,
+  15224,
+  14200,
+  13688,
+  13176,
+  978296,
+  1580408,
+  134520,
+  15224,
+  15736,
+  15736,
+  15736,
+  15736,
+  15736,
+  16248,
+  15736,
+  15736,
+  15224,
+  16760,
+  15224,
+  14712,
+  15224,
+  171384,
+  175480,
+  159096,
+  171384,
+  179576,
+  171384,
+  191864,
+  175480,
+  175480,
+  171384,
+  216440,
+  167288,
+  155000,
+  155000,
+  40312,
+  27000,
+  48504,
+  14200,
+  14200,
+  14712,
+  14200,
+  14200,
+  14200,
+  14712,
+  13688,
+  14200,
+  14200,
+  14712,
+  14712,
+  13688,
+  14200,
+  52600,
+  56696,
+  146704,
+  21792,
+  286720,
+  15360,
+  13824,
+  7168,
+  7168,
+  421888,
+  36864,
+  36864,
+  110592,
+  4608,
+  4096,
+  29576,
+  29576,
+  29576,
+  29576,
+  40840,
+  30088,
+  32136,
+  27368,
+  27528,
+  315392,
+  381,
+  3072,
+  1318,
+  3072,
+  375,
+  3072,
+  378,
+  3072,
+  598016,
+  53248,
+  32768,
+  110592,
+  43696,
+  5283840,
+  196608,
+  139264,
+  397312,
+  249856,
+  163840,
+  864256,
+  372736,
+  532480,
+  36864,
+  5632,
+  110592,
+  5120,
+  129664,
+  110592,
+  10752,
+  3203072,
+  163840,
+  45056,
+  57344,
+  8192,
+  425984,
+  81920,
+  28672,
+  49152,
+  671744,
+  61440,
+  53248,
+  2879488,
+  229376,
+  15360,
+  397312,
+  684032,
+  57344,
+  110592,
+  356352,
+  696320,
+  462848,
+  53248,
+  163840,
+  11776,
+  98304,
+  470240,
+  47328,
+  745472,
+  36864,
+  974848,
+  397312,
+  5062656,
+  544768,
+  401408,
+  290816,
+  36864,
+  188416,
+  28672,
+  40960,
+  630784,
+  81920,
+  6144,
+  24576,
+  32768,
+  446464,
+  65536,
+  126976,
+  53248,
+  131072,
+  11776,
+  389120,
+  3010560,
+  278528,
+  253952,
+  143360,
+  13824,
+  258048,
+  77824,
+  237568,
+  16896,
+  212992,
+  307200,
+  32768,
+  970752,
+  131072,
+  11776,
+  98304,
+  270336,
+  28672,
+  5992448,
+  73728,
+  36864,
+  491520,
+  32768,
+  569344,
+  69632,
+  114688,
+  40960,
+  692224,
+  65536,
+  28672,
+  77824,
+  3584,
+  229376,
+  32768,
+  4096,
+  16896,
+  139264,
+  131072,
+  11264,
+  15360,
+  1282048,
+  335872,
+  49152,
+  634880,
+  835584,
+  81920,
+  98304,
+  622592,
+  61440,
+  7168,
+  839680,
+  81920,
+  5025792,
+  434176,
+  12288,
+  3584,
+  1142784,
+  188416,
+  1630208,
+  311296,
+  540672,
+  36864,
+  507904,
+  102400,
+  2056192,
+  139264,
+  167936,
+  172032,
+  4096,
+  380928,
+  8192,
+  40960,
+  4096,
+  98304,
+  7168,
+  10584,
+  81080,
+  23376,
+  1257472,
+  90112,
+  94208,
+  5120,
+  150168,
+  25600,
+  2553856,
+  69120,
+  220672,
+  51712,
+  1349120,
+  1349120,
+  167424,
+  786432,
+  515584,
+  291328,
+  1681920,
+  33792,
+  102400,
+  102912,
+  60928,
+  44032,
+  631296,
+  44544,
+  11776,
+  408576,
+  138752,
+  1849856,
+  13824,
+  33280,
+  44544,
+  17920,
+  11776,
+  9153536,
+  150016,
+  13824,
+  24576,
+  293888,
+  651264,
+  818176,
+  17920,
+  141312,
+  64512,
+  583168,
+  58368,
+  830976,
+  109568,
+  65536,
+  24576,
+  771584,
+  1545728,
+  1540608,
+  11776,
+  144896,
+  11776,
+  18944,
+  67584,
+  65536,
+  17920,
+  848896,
+  43520,
+  30720,
+  27648,
+  1935872,
+  127488,
+  11264,
+  44032,
+  583168,
+  11264,
+  67584,
+  632320,
+  38400,
+  8470528,
+  127488,
+  257536,
+  30720,
+  111104,
+  286720,
+  1711616,
+  64000,
+  240128,
+  22016,
+  86528,
+  174080,
+  16896,
+  531456,
+  17920,
+  23552,
+  20992,
+  20992,
+  22528,
+  20992,
+  19456,
+  19456,
+  20992,
+  20992,
+  11500544,
+  12260864,
+  368128,
+  14345216,
+  29184,
+  29184,
+  84480,
+  64512,
+  925696,
+  8003072,
+  141312,
+  978432,
+  2305024,
+  6658048,
+  1116160,
+  1593344,
+  1059328,
+  777216,
+  214016,
+  627200,
+  11935232,
+  1840640,
+  12438528,
+  5466624,
+  86528,
+  98816,
+  3358720,
+  145408,
+  126976,
+  73728,
+  78848,
+  94208,
+  348672,
+  76288,
+  2347008,
+  2347008,
+  2176512,
+  237056,
+  1130496,
+  416768,
+  713216,
+  1126400,
+  61440,
+  163328,
+  158208,
+  61440,
+  2173952,
+  681472,
+  33792,
+  15580160,
+  16565248,
+  463360,
+  19202560,
+  47104,
+  116736,
+  89088,
+  10677248,
+  192512,
+  1320448,
+  3324416,
+  8741888,
+  1639936,
+  2320384,
+  1482752,
+  11899392,
+  1028608,
+  296448,
+  921600,
+  15390720,
+  2292224,
+  17390080,
+  6968320,
+  125952,
+  136192,
+  4978176,
+  193536,
+  169984,
+  104960,
+  43520,
+  300,
+  112128,
+  536,
+  110592,
+  536,
+  112128,
+  536,
+  2664448,
+  1060,
+  2664448,
+  1060,
+  2664448,
+  1060,
+  71168,
+  572,
+  72192,
+  572,
+  71168,
+  572,
+  131072,
+  2416,
+  82944,
+  3084,
+  12800,
+  3508,
+  15872,
+  3576,
+  1321984,
+  1364,
+  653312,
+  2124,
+  18492416,
+  2048,
+  6656,
+  344,
+  1219584,
+  416,
+  548864,
+  2444,
+  6656,
+  344,
+  11776,
+  1008,
+  54272,
+  404,
+  63488,
+  404,
+  64000,
+  404,
+  624640,
+  5752,
+  624640,
+  5720,
+  89600,
+  1736,
+  164352,
+  1096,
+  178688,
+  1096,
+  16384,
+  352,
+  326656,
+  1368,
+  315392,
+  1368,
+  699392,
+  1004,
+  54784,
+  360,
+  75776,
+  352,
+  69120,
+  352,
+  61440,
+  352,
+  62976,
+  352,
+  61952,
+  352,
+  53760,
+  360,
+  61440,
+  352,
+  62464,
+  352,
+  33280,
+  320,
+  23552,
+  368,
+  26112,
+  360,
+  26624,
+  324,
+  26112,
+  360,
+  27648,
+  320,
+  27136,
+  320,
+  27136,
+  320,
+  28160,
+  360,
+  27648,
+  320,
+  27648,
+  320,
+  27648,
+  320,
+  33280,
+  320,
+  27648,
+  320,
+  26112,
+  360,
+  29696,
+  320,
+  31232,
+  360,
+  26112,
+  360,
+  27648,
+  320,
+  25088,
+  328,
+  27648,
+  320,
+  26624,
+  320,
+  25088,
+  328,
+  25088,
+  328,
+  25088,
+  328,
+  27648,
+  320,
+  26112,
+  360,
+  27136,
+  320,
+  27136,
+  320,
+  27648,
+  320,
+  23552,
+  368,
+  26624,
+  320,
+  25600,
+  320,
+  25600,
+  320,
+  29696,
+  320,
+  27648,
+  320,
+  26624,
+  324,
+  1927168,
+  928,
+  2015232,
+  928,
+  414720,
+  588,
+  426496,
+  588,
+  327680,
+  708,
+  1290240,
+  2608,
+  83456,
+  308,
+  86016,
+  308,
+  109056,
+  308,
+  100352,
+  348,
+  86016,
+  308,
+  109056,
+  308,
+  83968,
+  308,
+  87040,
+  308,
+  76800,
+  312,
+  87040,
+  308,
+  88576,
+  348,
+  79360,
+  348,
+  79872,
+  308,
+  75264,
+  312,
+  87552,
+  308,
+  76800,
+  312,
+  86528,
+  308,
+  88064,
+  308,
+  80384,
+  348,
+  88576,
+  308,
+  83456,
+  308,
+  79872,
+  308,
+  96768,
+  308,
+  86528,
+  308,
+  78848,
+  348,
+  82944,
+  308,
+  88576,
+  308,
+  87552,
+  308,
+  79360,
+  348,
+  69120,
+  352,
+  83968,
+  308,
+  88064,
+  308,
+  82944,
+  308,
+  70144,
+  352,
+  80384,
+  348,
+  75264,
+  312,
+  96768,
+  308,
+  10240,
+  364,
+  9728,
+  364,
+  9728,
+  364,
+  9728,
+  364,
+  9728,
+  364,
+  9728,
+  364,
+  10240,
+  364,
+  9216,
+  368,
+  9216,
+  368,
+  163840,
+  8280,
+  242176,
+  2980,
+  210432,
+  360,
+  244224,
+  360,
+  209408,
+  360,
+  212480,
+  360,
+  192512,
+  364,
+  206336,
+  360,
+  224768,
+  360,
+  193536,
+  364,
+  206336,
+  360,
+  872960,
+  1232,
+  1231872,
+  1056,
+  809472,
+  888,
+  809472,
+  992,
+  3544576,
+  2160,
+  3544576,
+  2056,
+  3580928,
+  2220,
+  2396160,
+  2568,
+  145408,
+  316,
+  160256,
+  316,
+  145408,
+  316,
+  195584,
+  364,
+  140288,
+  316,
+  126464,
+  324,
+  144896,
+  316,
+  160256,
+  316,
+  139264,
+  316,
+  216064,
+  356,
+  212992,
+  356,
+  144896,
+  316,
+  139264,
+  316,
+  140288,
+  316,
+  196608,
+  364,
+  132608,
+  316,
+  128000,
+  324,
+  249344,
+  356,
+  181760,
+  316,
+  142848,
+  316,
+  228864,
+  356,
+  144896,
+  316,
+  147456,
+  316,
+  141824,
+  316,
+  144896,
+  316,
+  214528,
+  356,
+  210944,
+  356,
+  181760,
+  316,
+  140288,
+  320,
+  142848,
+  316,
+  141824,
+  316,
+  210432,
+  356,
+  128000,
+  324,
+  132608,
+  316,
+  140288,
+  320,
+  126464,
+  324,
+  147456,
+  316,
+  26624,
+  364,
+  24576,
+  364,
+  22016,
+  368,
+  29696,
+  364,
+  22528,
+  368,
+  24576,
+  364,
+  24576,
+  364,
+  24576,
+  364,
+  25088,
+  364,
+  2791936,
+  2000,
+  161280,
+  1048,
+  169472,
+  1048,
+  5100032,
+  2612,
+  5506560,
+  1728,
+  8192,
+  380,
+  101888,
+  5804,
+  104960,
+  3332,
+  99328,
+  2872,
+  8704,
+  388,
+  35328,
+  368,
+  11244032,
+  5592,
+  11244032,
+  5592,
+  10870784,
+  5256,
+  10744320,
+  7916,
+  540160,
+  744,
+  408064,
+  720,
+  58368,
+  4604,
+  58368,
+  4604,
+  52736,
+  5008,
+  1554432,
+  4636,
+  2222080,
+  6712,
+  7168,
+  384,
+  6656,
+  400,
+  6656,
+  372,
+  272384,
+  3816,
+  235008,
+  2760,
+  8192,
+  368,
+  625664,
+  5764,
+  563200,
+  6720,
+  9728,
+  392,
+  7168,
+  404,
+  415744,
+  4688,
+  1320960,
+  6228,
+  7168,
+  376,
+  1756160,
+  4992,
+  1961472,
+  6552,
+  244736,
+  360,
+  2317824,
+  6480,
+  1916928,
+  4832,
+  6656,
+  400,
+  8192,
+  372,
+  7168,
+  372,
+  405504,
+  4152,
+  411136,
+  5580,
+  83456,
+  1784,
+  84992,
+  2280,
+  6943744,
+  6676,
+  8638976,
+  9976,
+  16384,
+  368,
+  366080,
+  5696,
+  294912,
+  6460,
+  366080,
+  5696,
+  8192,
+  380,
+  384000,
+  364,
+  622592,
+  8296,
+  564224,
+  7396,
+  359936,
+  4004,
+  700416,
+  6276,
+  7168,
+  372,
+  1648640,
+  6952,
+  1498624,
+  4620,
+  38912,
+  360,
+  6656,
+  396,
+  8255488,
+  5060,
+  7553024,
+  5084,
+  8255488,
+  5060,
+  8048640,
+  8684,
+  4229120,
+  7476,
+  4243456,
+  9716,
+  57344,
+  372,
+  483840,
+  4016,
+  484352,
+  4468,
+  20480,
+  364,
+  6948352,
+  8444,
+  5271552,
+  5800,
+  9728,
+  364,
+  12800,
+  376,
+  273920,
+  2708,
+  114176,
+  2116,
+  256512,
+  6212,
+  186368,
+  6428,
+  1016320,
+  3228,
+  379904,
+  7256,
+  508928,
+  6568,
+  470528,
+  5128,
+  468480,
+  3764,
+  13023232,
+  5424,
+  12046336,
+  7648,
+  13023232,
+  5424,
+  23040,
+  352,
+  1604096,
+  700,
+  625664,
+  708,
+  608256,
+  656,
+  722944,
+  3524,
+  1263104,
+  4232,
+  243200,
+  3632,
+  60928,
+  720,
+  1249280,
+  2216,
+  233472,
+  1212,
+  110080,
+  1104,
+  1939456,
+  2864,
+  289792,
+  1632,
+  241664,
+  2956,
+  535040,
+  3040,
+  25088,
+  688,
+  38400,
+  544,
+  24576,
+  1816,
+  10240,
+  600,
+  10752,
+  1516,
+  68096,
+  1056,
+  75776,
+  424,
+  723968,
+  2076,
+  1162240,
+  1976,
+  117248,
+  760,
+  117248,
+  3696,
+  140800,
+  892,
+  998400,
+  708,
+  1829888,
+  10068,
+  3081216,
+  10696,
+  1305600,
+  4820,
+  172032,
+  1524,
+  7168,
+  304,
+  578048,
+  2232,
+  505856,
+  2232,
+  7168,
+  288,
+  149504,
+  856,
+  38400,
+  464,
+  196608,
+  1268,
+  198656,
+  1268,
+  752128,
+  2188,
+  799232,
+  2188,
+  164864,
+  1912,
+  197120,
+  1912,
+  261632,
+  1552,
+  259584,
+  1552,
+  601600,
+  1372,
+  583680,
+  1372,
+  19968,
+  832,
+  19968,
+  832,
+  375296,
+  1556,
+  373248,
+  1556,
+  44032,
+  2192,
+  44032,
+  1696,
+  148992,
+  1272,
+  148992,
+  1272,
+  71168,
+  988,
+  71168,
+  988,
+  108032,
+  2516,
+  96768,
+  1772,
+  1223680,
+  3812,
+  1895936,
+  4020,
+  560128,
+  708,
+  392192,
+  656,
+  1083904,
+  2364,
+  294400,
+  1948,
+  446464,
+  1620,
+  451072,
+  1620,
+  1251840,
+  432,
+  611840,
+  5216,
+  47104,
+  620,
+  53248,
+  620,
+  501760,
+  3572,
+  200192,
+  3312,
+  2404352,
+  580,
+  1298944,
+  876,
+  783360,
+  772,
+  111104,
+  504,
+  491008,
+  748,
+  580096,
+  1784,
+  6215680,
+  696,
+  1199616,
+  1832,
+  1252864,
+  2000,
+  314880,
+  1076,
+  346112,
+  2008,
+  11637248,
+  2264,
+  1553920,
+  3336,
+  311296,
+  1268,
+  259584,
+  1652,
+  1376256,
+  2196,
+  1782784,
+  3148,
+  516096,
+  1248,
+  1872896,
+  3692,
+  377856,
+  316,
+  96256,
+  608,
+  62464,
+  804,
+  338432,
+  1500,
+  296960,
+  1512,
+  396800,
+  1652,
+  329216,
+  1424,
+  859648,
+  2168,
+  2535424,
+  3688,
+  1282560,
+  2192,
+  4596736,
+  5784,
+  2210816,
+  2420,
+  139776,
+  760,
+  4002304,
+  4776,
+  4817920,
+  3500,
+  26624,
+  352,
+  488448,
+  2188,
+  1078272,
+  5188,
+  808448,
+  5548,
+  76288,
+  1496,
+  50688,
+  688,
+  603648,
+  4856,
+  600064,
+  3928,
+  49152,
+  368,
+  491008,
+  3236,
+  487936,
+  3120,
+  144896,
+  2216,
+  1013248,
+  6708,
+  805888,
+  6448,
+  114688,
+  320,
+  104448,
+  328,
+  103936,
+  328,
+  112128,
+  320,
+  113152,
+  320,
+  114688,
+  320,
+  110592,
+  320,
+  113664,
+  320,
+  136192,
+  320,
+  122880,
+  320,
+  110592,
+  320,
+  111616,
+  324,
+  113152,
+  320,
+  1485824,
+  4928,
+  690688,
+  10996,
+  737280,
+  12228,
+  108032,
+  924,
+  101888,
+  740,
+  6156288,
+  4976,
+  6376448,
+  6200,
+  548352,
+  1492,
+  441344,
+  1168,
+  1564672,
+  8060,
+  1538560,
+  7084,
+  169472,
+  368,
+  521216,
+  4180,
+  133632,
+  2348,
+  134144,
+  2348,
+  1046016,
+  8576,
+  1351680,
+  4732,
+  1823232,
+  1872,
+  829440,
+  3820,
+  781312,
+  3720,
+  5850112,
+  10748,
+  4831232,
+  10408,
+  119296,
+  2012,
+  118784,
+  2012,
+  19456,
+  1652,
+  9411584,
+  320,
+  9260032,
+  320,
+  367616,
+  4564,
+  360960,
+  4372,
+  69632,
+  7804,
+  68608,
+  6724,
+  1329152,
+  7692,
+  1319424,
+  6936,
+  2029568,
+  3088,
+  115200,
+  4584,
+  139776,
+  5012,
+  2570752,
+  1576,
+  43520,
+  2792,
+  42496,
+  2792,
+  842752,
+  7988,
+  2548224,
+  11824,
+  5488128,
+  1760,
+  260096,
+  7020,
+  706048,
+  3612,
+  740352,
+  5040,
+  16384,
+  380,
+  235520,
+  2536,
+  264704,
+  2652,
+  4364288,
+  8256,
+  4176896,
+  6204,
+  16559104,
+  3220,
+  107008,
+  2052,
+  1103872,
+  3264,
+  1098752,
+  3056,
+  1177600,
+  3856,
+  1028608,
+  3404,
+  663552,
+  2212,
+  665088,
+  2396,
+  140288,
+  560,
+  90112,
+  2736,
+  141824,
+  1284,
+  6045184,
+  13232,
+  4726784,
+  12052,
+  176640,
+  4388,
+  626688,
+  3868,
+  621568,
+  3868,
+  1908224,
+  1820,
+  704512,
+  4976,
+  700928,
+  4584,
+  2672128,
+  7920,
+  2396160,
+  7872,
+  4750848,
+  4916,
+  4597248,
+  5928,
+  345600,
+  7092,
+  318976,
+  7204,
+  31744,
+  676,
+  32256,
+  676,
+  593920,
+  3824,
+  615936,
+  4292,
+  1656320,
+  9112,
+  1626112,
+  9324,
+  177152,
+  2020,
+  5765632,
+  5816,
+  56320,
+  2228,
+  61952,
+  2228,
+  1814528,
+  3612,
+  6656,
+  380,
+  16896,
+  456,
+  31744,
+  844,
+  3265024,
+  9080,
+  4318720,
+  11204,
+  192512,
+  784,
+  188416,
+  784,
+  627200,
+  11148,
+  681472,
+  11644,
+  1456640,
+  4156,
+  306176,
+  2064,
+  305152,
+  1908,
+  2410496,
+  9624,
+  3928576,
+  10028,
+  3820544,
+  9056,
+  5166080,
+  3392,
+  417792,
+  1840,
+  17920,
+  720,
+  17920,
+  720,
+  732672,
+  5100,
+  832512,
+  5676,
+  1738752,
+  4948,
+  1936896,
+  452,
+  1940480,
+  452,
+  68608,
+  3424,
+  68608,
+  3428,
+  211456,
+  4428,
+  203776,
+  4120,
+  467456,
+  3208,
+  423936,
+  4084,
+  701952,
+  5048,
+  474624,
+  5268,
+  2202112,
+  6132,
+  136704,
+  2432,
+  136704,
+  2432,
+  10240,
+  372,
+  35840,
+  824,
+  35840,
+  824,
+  365568,
+  5700,
+  365568,
+  6176,
+  155648,
+  2168,
+  156160,
+  2168,
+  24064,
+  1004,
+  35840,
+  1392,
+  337408,
+  4956,
+  341504,
+  4688,
+  77312,
+  5412,
+  79360,
+  6264,
+  2067456,
+  10360,
+  435712,
+  448,
+  1226240,
+  5600,
+  1228800,
+  5952,
+  16384,
+  324,
+  16896,
+  324,
+  16896,
+  324,
+  16896,
+  328,
+  15872,
+  332,
+  16896,
+  324,
+  17920,
+  324,
+  16384,
+  324,
+  16896,
+  324,
+  16896,
+  324,
+  15872,
+  332,
+  16896,
+  324,
+  18432,
+  324,
+  99328,
+  776,
+  2295296,
+  8784,
+  1970176,
+  7988,
+  175104,
+  7768,
+  183808,
+  8200,
+  23552,
+  1244,
+  364032,
+  4316,
+  955904,
+  6660,
+  1570304,
+  8804,
+  1491968,
+  8444,
+  725504,
+  528,
+  729088,
+  528,
+  172544,
+  928,
+  411648,
+  7312,
+  294400,
+  3532,
+  313344,
+  3416,
+  48640,
+  984,
+  48128,
+  984,
+  48128,
+  1760,
+  160768,
+  900,
+  160768,
+  900,
+  3207680,
+  2016,
+  155136,
+  4012,
+  312320,
+  4680,
+  287232,
+  2888,
+  288768,
+  2888,
+  898560,
+  4116,
+  894464,
+  4116,
+  15360,
+  364,
+  2923520,
+  6556,
+  103936,
+  2668,
+  115200,
+  4552,
+  93696,
+  920,
+  87552,
+  920,
+  384512,
+  1976,
+  374784,
+  1976,
+  122368,
+  2456,
+  4463616,
+  2788,
+  1618432,
+  1200,
+  69632,
+  1672,
+  18432,
+  328,
+  23040,
+  1268,
+  13824,
+  328,
+  80384,
+  2132,
+  363008,
+  5288,
+  363520,
+  5776,
+  47616,
+  2808,
+  206848,
+  1952,
+  214016,
+  2120,
+  1050624,
+  6560,
+  1114112,
+  7476,
+  1883648,
+  1708,
+  710144,
+  9276,
+  937472,
+  12088,
+  3946496,
+  10876,
+  3973632,
+  11776,
+  6656,
+  372,
+  56832,
+  2452,
+  2269696,
+  10188,
+  300544,
+  4128,
+  299520,
+  3920,
+  1971712,
+  7600,
+  1007104,
+  3108,
+  9728,
+  384,
+  7168,
+  364,
+  32256,
+  512,
+  28672,
+  512,
+  640000,
+  1636,
+  24064,
+  1976,
+  272896,
+  3096,
+  167936,
+  3860,
+  1135616,
+  4944,
+  96768,
+  1772,
+  1086464,
+  10516,
+  1362944,
+  7912,
+  62976,
+  656,
+  63488,
+  656,
+  63488,
+  656,
+  115712,
+  320,
+  115200,
+  320,
+  895488,
+  9612,
+  11264,
+  336,
+  271360,
+  2784,
+  394240,
+  9496,
+  53760,
+  784,
+  360448,
+  6288,
+  84480,
+  2488,
+  588288,
+  7708,
+  724480,
+  7052,
+  2811392,
+  12416,
+  2999296,
+  10636,
+  34304,
+  332,
+  38400,
+  336,
+  38400,
+  336,
+  1101312,
+  4140,
+  1100288,
+  4072,
+  13824,
+  332,
+  13312,
+  332,
+  13824,
+  332,
+  12800,
+  336,
+  11776,
+  372,
+  13312,
+  332,
+  13312,
+  332,
+  13312,
+  332,
+  15360,
+  332,
+  13312,
+  332,
+  13824,
+  332,
+  12800,
+  336,
+  13312,
+  332,
+  13312,
+  332,
+  125952,
+  3308,
+  128000,
+  3688,
+  431616,
+  2860,
+  442880,
+  3348,
+  2013184,
+  1400,
+  660992,
+  5236,
+  1506816,
+  5124,
+  707584,
+  3248,
+  706560,
+  3248,
+  1534976,
+  572,
+  1537536,
+  572,
+  2013696,
+  3344,
+  2031616,
+  3344,
+  57856,
+  2364,
+  205824,
+  1748,
+  739328,
+  1232,
+  741376,
+  1232,
+  67584,
+  1316,
+  1430528,
+  2832,
+  429568,
+  620,
+  455680,
+  620,
+  1007616,
+  5588,
+  1282048,
+  2624,
+  1265152,
+  2628,
+  4728320,
+  7148,
+  4441600,
+  6448,
+  4735488,
+  5152,
+  3809280,
+  5136,
+  4013568,
+  5852,
+  97280,
+  1332,
+  978432,
+  3564,
+  72704,
+  2504,
+  28672,
+  376,
+  2288640,
+  7400,
+  2407936,
+  7308,
+  901632,
+  8740,
+  972288,
+  9456,
+  1052160,
+  6812,
+  1026560,
+  6528,
+  1321472,
+  9780,
+  837120,
+  8460,
+  288768,
+  1108,
+  308736,
+  1108,
+  1195520,
+  1948,
+  1198080,
+  1948,
+  181248,
+  5368,
+  144384,
+  4900,
+  776704,
+  348,
+  157696,
+  5076,
+  60928,
+  444,
+  60928,
+  444,
+  209920,
+  5220,
+  246784,
+  756,
+  246272,
+  756,
+  604672,
+  8528,
+  24064,
+  564,
+  24064,
+  564,
+  47104,
+  556,
+  44032,
+  556,
+  321536,
+  2176,
+  332288,
+  2176,
+  204288,
+  2388,
+  204800,
+  2440,
+  107008,
+  912,
+  82432,
+  1448,
+  87552,
+  1996,
+  89088,
+  372,
+  922112,
+  4576,
+  508928,
+  1944,
+  528896,
+  1996,
+  5450240,
+  2776,
+  3680768,
+  15000,
+  3721728,
+  16696,
+  845312,
+  9152,
+  3270656,
+  4144,
+  1602048,
+  852,
+  1606656,
+  852,
+  36864,
+  564,
+  39936,
+  564,
+  214016,
+  3144,
+  576000,
+  4544,
+  580096,
+  4468,
+  627200,
+  6596,
+  1623040,
+  11196,
+  1107456,
+  9700,
+  2272256,
+  13208,
+  2289152,
+  13624,
+  1189376,
+  704,
+  1203712,
+  704,
+  470528,
+  6616,
+  451584,
+  5508,
+  143360,
+  1388,
+  143360,
+  1388,
+  55296,
+  2920,
+  55808,
+  2920,
+  82944,
+  2444,
+  82944,
+  2444,
+  2862592,
+  3168,
+  7680,
+  372,
+  68096,
+  1124,
+  67584,
+  1124,
+  1022976,
+  1240,
+  193024,
+  2660,
+  193536,
+  2660,
+  2833408,
+  1172,
+  195072,
+  1564,
+  512000,
+  2840,
+  131072,
+  3096,
+  313344,
+  2100,
+  89088,
+  2136,
+  86016,
+  2136,
+  1243648,
+  1840,
+  1280512,
+  1840,
+  778752,
+  1040,
+  10240,
+  388,
+  420864,
+  1660,
+  3430400,
+  5764,
+  1161216,
+  736,
+  2591232,
+  9460,
+  1972224,
+  8028,
+  583168,
+  6348,
+  468992,
+  6044,
+  553472,
+  4172,
+  551424,
+  3364,
+  1433600,
+  2712,
+  677376,
+  2552,
+  1743872,
+  5072,
+  1784320,
+  5540,
+  1024512,
+  2564,
+  1110016,
+  3572,
+  5252096,
+  11496,
+  5855744,
+  13532,
+  18944,
+  1000,
+  12800,
+  424,
+  149504,
+  512,
+  9216,
+  312,
+  84480,
+  1308,
+  20992,
+  992,
+  17920,
+  996,
+  36352,
+  1096,
+  15872,
+  996,
+  1478144,
+  1736,
+  83968,
+  432,
+  1655296,
+  2292,
+  1654272,
+  2200,
+  604160,
+  560,
+  27136,
+  2024,
+  43520,
+  656,
+  21504,
+  1316,
+  26624,
+  324,
+  412160,
+  2000,
+  163840,
+  724,
+  155136,
+  724,
+  1257472,
+  7584,
+  1146368,
+  3468,
+  18944,
+  324,
+  2123264,
+  5428,
+  2144768,
+  6080,
+  57344,
+  896,
+  80384,
+  1284,
+  1655808,
+  1172,
+  260608,
+  1280,
+  908800,
+  1356,
+  532480,
+  1196,
+  46592,
+  340,
+  61440,
+  300,
+  50176,
+  300,
+  49664,
+  300,
+  50176,
+  300,
+  49152,
+  300,
+  48640,
+  300,
+  49664,
+  300,
+  49664,
+  300,
+  48640,
+  300,
+  49664,
+  300,
+  42496,
+  340,
+  46080,
+  300,
+  50176,
+  300,
+  44032,
+  304,
+  50176,
+  300,
+  43008,
+  340,
+  48128,
+  300,
+  38400,
+  344,
+  49664,
+  300,
+  43008,
+  340,
+  44032,
+  340,
+  54272,
+  300,
+  50176,
+  300,
+  44032,
+  304,
+  48128,
+  300,
+  43520,
+  340,
+  50176,
+  300,
+  49152,
+  300,
+  44032,
+  304,
+  44032,
+  304,
+  61440,
+  300,
+  52736,
+  340,
+  54272,
+  300,
+  46080,
+  300,
+  49664,
+  300,
+  36864,
+  344,
+  17920,
+  308,
+  16896,
+  312,
+  17920,
+  308,
+  17408,
+  308,
+  17920,
+  308,
+  17920,
+  308,
+  17920,
+  308,
+  17920,
+  308,
+  16896,
+  312,
+  17408,
+  308,
+  17920,
+  308,
+  18432,
+  308,
+  17920,
+  308,
+  17408,
+  308,
+  18432,
+  308,
+  17920,
+  308,
+  18432,
+  308,
+  19456,
+  308,
+  20480,
+  308,
+  18432,
+  308,
+  16384,
+  312,
+  20480,
+  308,
+  16384,
+  312,
+  17920,
+  308,
+  18432,
+  308,
+  18432,
+  308,
+  17408,
+  308,
+  19456,
+  308,
+  721408,
+  1540,
+  20518056,
+  176,
+  25554944,
+  176,
+  17408,
+  1464,
+  17408,
+  1620,
+  78848,
+  296,
+  118784,
+  740,
+  2226688,
+  1360,
+  2097664,
+  1360,
+  2452992,
+  16100,
+  2390528,
+  15368,
+  19825152,
+  2436,
+  536064,
+  1252,
+  12187136,
+  1832,
+  26112,
+  2080,
+  26112,
+  2080,
+  26112,
+  2084,
+  26112,
+  2084,
+  25088,
+  1760,
+  25600,
+  2088,
+  25088,
+  2088,
+  25088,
+  1756,
+  25088,
+  2084,
+  25088,
+  2084,
+  23552,
+  2100,
+  23552,
+  2100,
+  23552,
+  2100,
+  23552,
+  2100,
+  168960,
+  1064,
+  171520,
+  1064,
+  168960,
+  1064,
+  6656,
+  372,
+  7168,
+  368,
+  12288,
+  704,
+  14848,
+  816,
+  3638784,
+  856,
+  3638272,
+  856,
+  3700736,
+  856,
+  11264,
+  484,
+  68096,
+  732,
+  68096,
+  732,
+  68096,
+  732,
+  118272,
+  924,
+  933376,
+  1352,
+  933376,
+  1352,
+  942080,
+  1352,
+  683008,
+  10132,
+  768512,
+  3312,
+  768000,
+  3312,
+  230912,
+  1488,
+  200704,
+  1876,
+  148480,
+  2048,
+  391680,
+  2204,
+  391680,
+  2204,
+  395264,
+  2204,
+  13061632,
+  620,
+  10336768,
+  620,
+  5653504,
+  2256,
+  6656,
+  348,
+  7680,
+  304,
+  1251840,
+  1980,
+  796672,
+  1984,
+  812544,
+  2324,
+  8192,
+  316,
+  8704,
+  304,
+  181248,
+  3020,
+  252928,
+  728,
+  176128,
+  2856,
+  9728,
+  356,
+  174080,
+  3208,
+  10752,
+  360,
+  1075712,
+  556,
+  9216,
+  360,
+  150016,
+  1260,
+  993792,
+  864,
+  27648,
+  300,
+  9489920,
+  900,
+  7684608,
+  900,
+  7966720,
+  1540,
+  2586624,
+  708,
+  1241600,
+  1180,
+  1172992,
+  1336,
+  1838592,
+  1196,
+  10906624,
+  2396,
+  11145728,
+  2580,
+  31232,
+  312,
+  6656,
+  360,
+  10752,
+  316,
+  10240,
+  316,
+  8192,
+  308,
+  8192,
+  308,
+  9216,
+  320,
+  8704,
+  312,
+  460800,
+  768,
+  1172992,
+  752,
+  247808,
+  1088,
+  1645568,
+  584,
+  8704,
+  308,
+  391680,
+  536,
+  769536,
+  1100,
+  243200,
+  8192,
+  304,
+  3034624,
+  1732,
+  8192,
+  296,
+  283648,
+  424,
+  8192,
+  316,
+  8704,
+  316,
+  6656,
+  352,
+  6656,
+  360,
+  19968,
+  316,
+  8192,
+  304,
+  9216,
+  304,
+  9216,
+  300,
+  8192,
+  296,
+  10752,
+  308,
+  26242048,
+  2764,
+  1180672,
+  764,
+  36864,
+  592,
+  522752,
+  536,
+  9728,
+  304,
+  128000,
+  420,
+  273920,
+  300,
+  26624,
+  316,
+  8704,
+  312,
+  1382912,
+  3572,
+  2391552,
+  3368,
+  1316864,
+  3200,
+  8192,
+  312,
+  8704,
+  304,
+  8192,
+  316,
+  636928,
+  1956,
+  251904,
+  752,
+  8192,
+  312,
+  35328,
+  1368,
+  811520,
+  1276,
+  306176,
+  644,
+  408576,
+  1240,
+  12288,
+  316,
+  102400,
+  504,
+  8192,
+  308,
+  2842112,
+  1100,
+  19456,
+  300,
+  32256,
+  332,
+  31744,
+  316,
+  9216,
+  324,
+  9728,
+  324,
+  14336,
+  308,
+  36352,
+  560,
+  9728,
+  320,
+  805888,
+  912,
+  221696,
+  932,
+  802304,
+  592,
+  19939840,
+  3948,
+  8192,
+  304,
+  8192,
+  316,
+  886784,
+  3224,
+  1123840,
+  3024,
+  8192,
+  316,
+  9216,
+  308,
+  8704,
+  300,
+  8704,
+  308,
+  719360,
+  924,
+  702464,
+  972,
+  13918208,
+  4076,
+  13918208,
+  3972,
+  257024,
+  432,
+  94720,
+  600,
+  1904640,
+  1580,
+  122880,
+  1372,
+  122368,
+  1252,
+  13563392,
+  1720,
+  4451328,
+  2520,
+  2031616,
+  572,
+  7577088,
+  748,
+  15872,
+  636,
+  10240,
+  308,
+  8704,
+  308,
+  9728,
+  308,
+  395776,
+  872,
+  8704,
+  304,
+  9728,
+  300,
+  240640,
+  2288,
+  1309184,
+  3864,
+  93696,
+  292,
+  93696,
+  292,
+  95232,
+  292,
+  635392,
+  572,
+  629248,
+  572,
+  629248,
+  572,
+  474624,
+  3184,
+  130560,
+  2420,
+  84480,
+  3088,
+  153088,
+  3444,
+  227840,
+  3116,
+  339456,
+  1420,
+  708096,
+  5904,
+  999936,
+  7792,
+  1446400,
+  2340,
+  1404928,
+  2340,
+  4345344,
+  14076,
+  4835328,
+  15864,
+  411136,
+  1556,
+  411648,
+  1556,
+  605696,
+  1076,
+  605184,
+  1024,
+  13824,
+  808,
+  183296,
+  1680,
+  185856,
+  1680,
+  347136,
+  1428,
+  141824,
+  340,
+  222720,
+  344,
+  721920,
+  2112,
+  4110336,
+  1348,
+  248832,
+  3588,
+  249344,
+  3680,
+  98816,
+  2896,
+  99328,
+  3012,
+  7753728,
+  852,
+  7665664,
+  852,
+  7665664,
+  852,
+  154112,
+  892,
+  155648,
+  892,
+  154112,
+  892,
+  457216,
+  1660,
+  133632,
+  2716,
+  137216,
+  888,
+  136704,
+  888,
+  136704,
+  888,
+  118272,
+  1832,
+  122368,
+  736,
+  135680,
+  736,
+  135680,
+  736,
+  63488,
+  300,
+  80384,
+  572,
+  81920,
+  572,
+  80384,
+  572,
+  104960,
+  3084,
+  166912,
+  2416,
+  14848,
+  3508,
+  18944,
+  3576,
+  267264,
+  300,
+  1542656,
+  1364,
+  765952,
+  2124,
+  23862784,
+  2048,
+  596480,
+  2444,
+  72704,
+  404,
+  72704,
+  404,
+  61440,
+  404,
+  129024,
+  504,
+  105984,
+  540,
+  108032,
+  1736,
+  28160,
+  320,
+  30720,
+  320,
+  26112,
+  328,
+  28160,
+  324,
+  28160,
+  320,
+  28160,
+  324,
+  29184,
+  320,
+  26112,
+  328,
+  28672,
+  320,
+  28672,
+  320,
+  26112,
+  328,
+  27136,
+  320,
+  28672,
+  320,
+  34304,
+  320,
+  28672,
+  320,
+  27648,
+  320,
+  27648,
+  320,
+  29184,
+  320,
+  26112,
+  328,
+  28672,
+  320,
+  27136,
+  320,
+  34304,
+  320,
+  29184,
+  320,
+  30720,
+  320,
+  28672,
+  320,
+  29184,
+  320,
+  28672,
+  320,
+  28672,
+  320,
+  2295296,
+  928,
+  2386432,
+  928,
+  561664,
+  588,
+  445952,
+  708,
+  577536,
+  588,
+  88064,
+  308,
+  88576,
+  308,
+  97792,
+  308,
+  81408,
+  308,
+  88064,
+  308,
+  77824,
+  312,
+  89088,
+  308,
+  97792,
+  308,
+  89088,
+  308,
+  83968,
+  308,
+  87040,
+  308,
+  84480,
+  308,
+  85504,
+  308,
+  81408,
+  308,
+  89600,
+  308,
+  110080,
+  308,
+  87552,
+  308,
+  110080,
+  308,
+  76288,
+  312,
+  84480,
+  308,
+  89600,
+  308,
+  83968,
+  308,
+  87552,
+  308,
+  88576,
+  308,
+  87040,
+  308,
+  76288,
+  312,
+  85504,
+  308,
+  77824,
+  312,
+  288768,
+  2980,
+  193536,
+  8280,
+  1096192,
+  1232,
+  1049088,
+  992,
+  1049088,
+  888,
+  4356608,
+  2160,
+  4356608,
+  2056,
+  2875904,
+  2568,
+  161792,
+  316,
+  127488,
+  324,
+  146432,
+  316,
+  148480,
+  316,
+  146432,
+  316,
+  144384,
+  316,
+  141312,
+  316,
+  148480,
+  316,
+  145920,
+  316,
+  129024,
+  324,
+  141312,
+  316,
+  182784,
+  316,
+  141824,
+  320,
+  142848,
+  316,
+  127488,
+  324,
+  146432,
+  316,
+  133632,
+  316,
+  161792,
+  316,
+  140288,
+  316,
+  144384,
+  316,
+  129024,
+  324,
+  133632,
+  316,
+  140288,
+  316,
+  141824,
+  320,
+  142848,
+  316,
+  145920,
+  316,
+  146432,
+  316,
+  182784,
+  316,
+  190464,
+  1048,
+  6645760,
+  2612,
+  7172608,
+  1728,
+  130048,
+  5804,
+  129536,
+  3332,
+  14091776,
+  5592,
+  13456896,
+  7916,
+  13585920,
+  5256,
+  671232,
+  744,
+  65536,
+  5008,
+  71168,
+  4604,
+  2784256,
+  6712,
+  339456,
+  3816,
+  709120,
+  6720,
+  1713152,
+  6228,
+  2441216,
+  6552,
+  2871296,
+  6480,
+  541184,
+  5580,
+  93696,
+  2280,
+  11535872,
+  9976,
+  473600,
+  5696,
+  386048,
+  6460,
+  800768,
+  8296,
+  953344,
+  6276,
+  2007040,
+  6952,
+  11059712,
+  5060,
+  10085888,
+  5084,
+  10799104,
+  8684,
+  5849600,
+  9716,
+  633344,
+  4468,
+  9155072,
+  8444,
+  327168,
+  2708,
+  235008,
+  6428,
+  1310720,
+  3228,
+  476160,
+  7256,
+  634368,
+  5128,
+  16174592,
+  5424,
+  15025152,
+  7648,
+  1963008,
+  700,
+  308224,
+  3632,
+  82944,
+  720,
+  1541632,
+  2216,
+  304640,
+  1212,
+  132608,
+  1104,
+  2478592,
+  2864,
+  383488,
+  1632,
+  302592,
+  2956,
+  29184,
+  688,
+  50176,
+  544,
+  30208,
+  1816,
+  12800,
+  600,
+  13312,
+  1516,
+  79872,
+  1056,
+  94720,
+  424,
+  148992,
+  760,
+  148992,
+  3696,
+  221696,
+  892,
+  225280,
+  1524,
+  8704,
+  304,
+  8192,
+  288,
+  188416,
+  856,
+  53760,
+  464,
+  1364480,
+  2364,
+  91648,
+  500,
+  1593856,
+  432,
+  2812416,
+  580,
+  135680,
+  504,
+  664064,
+  328,
+  626688,
+  748,
+  548864,
+  1120,
+  720896,
+  1784,
+  1544192,
+  1832,
+  1606144,
+  2000,
+  4137472,
+  3300,
+  7470592,
+  2380,
+  387584,
+  1076,
+  440320,
+  2008,
+  739840,
+  1608,
+  13512704,
+  2264,
+  1871360,
+  3336,
+  381440,
+  1268,
+  332288,
+  1652,
+  1762304,
+  2196,
+  214016,
+  1252,
+  2290176,
+  3148,
+  671232,
+  1248,
+  1467392,
+  2232,
+  80896,
+  608,
+  2438144,
+  3692,
+  489984,
+  316,
+  117760,
+  608,
+  437760,
+  1500,
+  377344,
+  1512,
+  175616,
+  760,
+  744448,
+  3928,
+  111616,
+  320,
+  112640,
+  324,
+  123904,
+  320,
+  113152,
+  320,
+  114176,
+  320,
+  114176,
+  320,
+  111616,
+  320,
+  116224,
+  320,
+  105472,
+  328,
+  114688,
+  320,
+  105472,
+  328,
+  137216,
+  320,
+  115712,
+  320,
+  882688,
+  12228,
+  155136,
+  2348,
+  144384,
+  2012,
+  23040,
+  1652,
+  89600,
+  7804,
+  161280,
+  5012,
+  754688,
+  3868,
+  34304,
+  676,
+  816128,
+  11644,
+  372736,
+  1908,
+  551424,
+  5268,
+  86016,
+  6264,
+  16896,
+  332,
+  17920,
+  324,
+  17920,
+  324,
+  18944,
+  324,
+  17920,
+  324,
+  18432,
+  324,
+  19968,
+  324,
+  17408,
+  332,
+  17920,
+  324,
+  17920,
+  324,
+  17920,
+  324,
+  17920,
+  324,
+  17920,
+  328,
+  241152,
+  8200,
+  919040,
+  528,
+  913408,
+  528,
+  371712,
+  2888,
+  1105920,
+  4116,
+  2182656,
+  1708,
+  1213440,
+  12088,
+  524288,
+  9496,
+  460800,
+  6288,
+  3119616,
+  12416,
+  47104,
+  336,
+  14848,
+  332,
+  16384,
+  332,
+  14848,
+  332,
+  13824,
+  336,
+  13824,
+  336,
+  14336,
+  332,
+  14336,
+  332,
+  14336,
+  332,
+  14848,
+  332,
+  14848,
+  332,
+  14848,
+  332,
+  14336,
+  332,
+  14336,
+  332,
+  913920,
+  3248,
+  2378240,
+  3344,
+  998912,
+  1232,
+  60416,
+  556,
+  233472,
+  2388,
+  4872192,
+  16696,
+  1746432,
+  852,
+  1432576,
+  704,
+  1444352,
+  704,
+  98304,
+  2444,
+  218112,
+  2660,
+  4998144,
+  716,
+  5272064,
+  716,
+  240128,
+  1564,
+  1604608,
+  1840,
+  1565696,
+  1840,
+  1565696,
+  1840,
+  1497088,
+  736,
+  22016,
+  1000,
+  14848,
+  424,
+  1531392,
+  2684,
+  188928,
+  512,
+  10240,
+  312,
+  97792,
+  1308,
+  24064,
+  992,
+  20480,
+  996,
+  44544,
+  1096,
+  18432,
+  996,
+  31744,
+  2024,
+  51712,
+  656,
+  25600,
+  1316,
+  35328,
+  324,
+  611328,
+  1444,
+  526848,
+  2000,
+  26112,
+  324,
+  7213568,
+  1568,
+  2115072,
+  1172,
+  316416,
+  1280,
+  646144,
+  1196,
+  1097216,
+  1356,
+  47104,
+  300,
+  50688,
+  300,
+  51200,
+  300,
+  51200,
+  300,
+  51200,
+  300,
+  45056,
+  304,
+  49664,
+  300,
+  47104,
+  300,
+  51200,
+  300,
+  49664,
+  300,
+  50688,
+  300,
+  62464,
+  300,
+  51200,
+  300,
+  50688,
+  300,
+  50688,
+  300,
+  49664,
+  300,
+  55296,
+  300,
+  45056,
+  304,
+  51200,
+  300,
+  45056,
+  304,
+  50688,
+  300,
+  55296,
+  300,
+  49664,
+  300,
+  51200,
+  300,
+  62464,
+  300,
+  51200,
+  300,
+  50688,
+  300,
+  45056,
+  304,
+  19456,
+  308,
+  19456,
+  308,
+  18944,
+  308,
+  19456,
+  308,
+  18944,
+  308,
+  18944,
+  308,
+  22016,
+  308,
+  22016,
+  308,
+  20992,
+  308,
+  18944,
+  308,
+  19456,
+  308,
+  18432,
+  308,
+  18944,
+  308,
+  19456,
+  308,
+  18944,
+  308,
+  19456,
+  308,
+  19456,
+  308,
+  17920,
+  312,
+  18944,
+  308,
+  18432,
+  308,
+  19456,
+  308,
+  17920,
+  312,
+  19456,
+  308,
+  17920,
+  312,
+  20992,
+  308,
+  19456,
+  308,
+  18944,
+  308,
+  17920,
+  312,
+  910848,
+  1540,
+  22551712,
+  176,
+  98816,
+  296,
+  139264,
+  740,
+  2679296,
+  1360,
+  2817024,
+  1360,
+  23356416,
+  2436,
+  650752,
+  1252,
+  14530048,
+  1832,
+  29696,
+  2080,
+  29184,
+  2084,
+  26624,
+  2100,
+  13312,
+  484,
+  73728,
+  732,
+  73728,
+  732,
+  74240,
+  732,
+  143872,
+  924,
+  303104,
+  1488,
+  12712448,
+  620,
+  7215616,
+  2256,
+  9216,
+  304,
+  1687552,
+  1980,
+  1063424,
+  1984,
+  1082880,
+  2324,
+  9728,
+  316,
+  10752,
+  304,
+  349696,
+  728,
+  1405440,
+  556,
+  169984,
+  1260,
+  1175552,
+  864,
+  31744,
+  300,
+  10212352,
+  900,
+  9414656,
+  1540,
+  3118080,
+  708,
+  1555456,
+  1180,
+  1391616,
+  1336,
+  2229760,
+  1196,
+  12569600,
+  2396,
+  35328,
+  312,
+  12288,
+  316,
+  12800,
+  316,
+  9216,
+  308,
+  9216,
+  308,
+  10240,
+  320,
+  10240,
+  312,
+  1125376,
+  1128,
+  547328,
+  768,
+  1424384,
+  752,
+  295424,
+  1088,
+  1996288,
+  584,
+  10752,
+  308,
+  486912,
+  536,
+  1000960,
+  1100,
+  334336,
+  9216,
+  304,
+  9728,
+  296,
+  338944,
+  424,
+  9216,
+  316,
+  10240,
+  316,
+  22528,
+  316,
+  9216,
+  304,
+  10752,
+  304,
+  10752,
+  300,
+  9216,
+  296,
+  12800,
+  308,
+  2764,
+  1433600,
+  764,
+  642048,
+  536,
+  314880,
+  300,
+  10240,
+  312,
+  1701888,
+  3200,
+  3041280,
+  3368,
+  1785344,
+  3572,
+  9216,
+  312,
+  10240,
+  304,
+  9728,
+  316,
+  867840,
+  1948,
+  300544,
+  752,
+  10240,
+  312,
+  41984,
+  1368,
+  932352,
+  1276,
+  345600,
+  644,
+  517120,
+  1240,
+  15360,
+  316,
+  111104,
+  504,
+  9216,
+  308,
+  3349504,
+  1100,
+  24576,
+  300,
+  36864,
+  332,
+  36352,
+  316,
+  10752,
+  324,
+  10752,
+  324,
+  16896,
+  308,
+  41472,
+  560,
+  11264,
+  320,
+  950272,
+  912,
+  260608,
+  932,
+  989184,
+  592,
+  24750080,
+  3948,
+  9216,
+  304,
+  9216,
+  316,
+  917504,
+  3224,
+  1547776,
+  3024,
+  9216,
+  316,
+  10752,
+  308,
+  10752,
+  300,
+  9728,
+  308,
+  872448,
+  924,
+  814592,
+  972,
+  16530944,
+  4076,
+  16530944,
+  3972,
+  290304,
+  432,
+  111616,
+  600,
+  2162688,
+  1580,
+  15892480,
+  1720,
+  5285888,
+  2520,
+  2543616,
+  572,
+  8998912,
+  748,
+  18944,
+  636,
+  10240,
+  308,
+  11776,
+  308,
+  11264,
+  308,
+  480256,
+  872,
+  10240,
+  304,
+  11264,
+  300,
+  267264,
+  2288,
+  108544,
+  292,
+  107008,
+  292,
+  107008,
+  292,
+  841728,
+  572,
+  847872,
+  572,
+  842240,
+  572,
+  219136,
+  304,
+  105984,
+  3088,
+  167424,
+  2420,
+  292352,
+  3116,
+  195584,
+  3444,
+  1740288,
+  2340,
+  1792000,
+  2340,
+  5146624,
+  1348,
+  176640,
+  892,
+  174592,
+  892,
+  174592,
+  892,
+  611840,
+  1660,
+  154112,
+  888,
+  155648,
+  888,
+  154112,
+  888,
+  197632,
+  1832,
+  301609,
+  338048,
+  64512,
+  135,
+  16384,
+  3170304,
+  1474560,
+  1474560,
+  16384,
+  3170304,
+  1024,
+  1024,
+  4096,
+  77728,
+  77728,
+  4669,
+  1224608,
+  1209752,
+  115616,
+  76696,
+  76704,
+  45472,
+  75680,
+  75680,
+  45472,
+  79264,
+  79264,
+  45984,
+  80288,
+  80288,
+  46488,
+  74144,
+  74144,
+  74136,
+  74144,
+  44960,
+  77728,
+  77728,
+  45984,
+  77728,
+  77728,
+  75168,
+  75168,
+  76704,
+  76704,
+  45472,
+  79264,
+  79264,
+  79256,
+  79264,
+  45984,
+  76704,
+  76696,
+  78752,
+  78752,
+  45984,
+  77216,
+  77216,
+  45472,
+  67488,
+  67488,
+  42912,
+  66976,
+  66976,
+  42912,
+  75680,
+  75680,
+  75680,
+  75672,
+  1056664,
+  75680,
+  75680,
+  45472,
+  77728,
+  77728,
+  45472,
+  77728,
+  77720,
+  45976,
+  76704,
+  76704,
+  45472,
+  76696,
+  76704,
+  45984,
+  54176,
+  76192,
+  76192,
+  77208,
+  77216,
+  44960,
+  77216,
+  77216,
+  76704,
+  76704,
+  77216,
+  77216,
+  76192,
+  76192,
+  44960,
+  75168,
+  75168,
+  45472,
+  77208,
+  77216,
+  4662,
+  6534,
+  63904,
+  63904,
+  42400,
+  63904,
+  63904,
+  42400,
+  3695719,
+  3878410,
+  1985867,
+  2373000,
+  174959,
+  177414,
+  143754,
+  145419,
+  162331,
+  164347,
+  154427,
+  156245,
+  44859,
+  85862,
+  86178,
+  49091,
+  77728,
+  395314,
+  1,
+  95648,
+  99744,
+  76704,
+  45472,
+  75672,
+  45472,
+  79264,
+  45984,
+  80288,
+  46496,
+  74144,
+  74144,
+  44960,
+  77728,
+  45984,
+  77720,
+  75160,
+  76696,
+  45472,
+  79264,
+  79264,
+  45984,
+  76696,
+  78752,
+  45976,
+  77208,
+  45472,
+  67488,
+  42904,
+  66976,
+  42912,
+  75672,
+  75680,
+  812440,
+  75672,
+  45472,
+  77728,
+  45472,
+  77728,
+  45984,
+  76704,
+  45472,
+  76696,
+  45984,
+  83352,
+  54176,
+  76184,
+  77208,
+  44960,
+  77216,
+  76704,
+  77216,
+  76192,
+  44952,
+  75168,
+  45472,
+  77216,
+  4662,
+  63904,
+  42400,
+  63904,
+  42392,
+  92576,
+  12704,
+  12192,
+  67584,
+  1477720,
+  7680,
+  7680,
+  962048,
+  958976,
+  6480,
+  34390,
+  136606,
+  136606,
+  156118,
+  556304,
+  556304,
+  556304,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  8774,
+  8774,
+  8774,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  136606,
+  556304,
+  556304,
+  556304,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  8774,
+  2560,
+  1024,
+  15360,
+  10752,
+  2560,
+  12288,
+  52736,
+  6656,
+  3072,
+  8582,
+  3,
+  16777270,
+  4606392,
+  70144,
+  808,
+  1233,
+  2222,
+  2090,
+  1120,
+  1317,
+  2038,
+  2574,
+  1544,
+  1215,
+  1277,
+  2053,
+  2088,
+  1560,
+  1815,
+  2177,
+  1483,
+  846,
+  1590,
+  2724,
+  1676,
+  2430,
+  1197,
+  1429,
+  1310,
+  1873,
+  1914,
+  13868,
+  8116,
+  5632,
+  11423,
+  78336,
+  6996,
+  5120,
+  1151,
+  1848,
+  1898,
+  1137,
+  1802,
+  2593,
+  4506,
+  2839,
+  410,
+  1093,
+  610,
+  848,
+  422,
+  12109,
+  5756,
+  2092,
+  5260,
+  3584,
+  5120,
+  2620,
+  80896,
+  4680,
+  3584,
+  229,
+  12800,
+  592,
+  1963,
+  1068,
+  1080,
+  701,
+  369,
+  711,
+  1485,
+  540,
+  613,
+  3148,
+  1390,
+  2432,
+  1488,
+  1282,
+  711,
+  531,
+  682,
+  468,
+  3728,
+  9216,
+  15256,
+  152064,
+  3280,
+  8192,
+  1219,
+  2204,
+  382,
+  1470,
+  734,
+  347,
+  2381,
+  370,
+  1069,
+  832,
+  1943,
+  11026,
+  1535,
+  714,
+  17920,
+  11776,
+  1141,
+  1029,
+  610,
+  384,
+  141662,
+  8016,
+  13824,
+  29602,
+  176128,
+  7380,
+  11776,
+  22718,
+  1636,
+  2557,
+  2804,
+  1756,
+  1223,
+  7091,
+  6746,
+  1323,
+  1139,
+  5106,
+  1825,
+  1624,
+  15593,
+  2462,
+  1932,
+  2563,
+  1575,
+  3258,
+  1591,
+  1921,
+  2920,
+  2226,
+  20053,
+  10426,
+  894,
+  4608,
+  7152,
+  78848,
+  814,
+  4096,
+  1050,
+  2221,
+  5322,
+  858,
+  779,
+  5310,
+  1861,
+  4670,
+  6144,
+  17152,
+  17920,
+  4106,
+  5632,
+  1200,
+  1200,
+  1192,
+  1204,
+  3594,
+  1206,
+  1192,
+  1131,
+  1131,
+  1123,
+  1135,
+  2313,
+  1137,
+  1123,
+  8508,
+  40057,
+  1648,
+  15872,
+  20463,
+  1062,
+  7168,
+  14398,
+  2560,
+  972,
+  6144,
+  1022,
+  918,
+  1398,
+  1737,
+  1445,
+  1185,
+  747,
+  1218,
+  1307,
+  712,
+  1331,
+  1022,
+  1277,
+  43151,
+  4245,
+  3898,
+  9216,
+  25149,
+  55808,
+  3496,
+  8192,
+  2351,
+  2054,
+  660,
+  248,
+  321,
+  3578,
+  1242,
+  1770,
+  2523,
+  2706,
+  2691,
+  2270,
+  1902,
+  1276,
+  476,
+  34272,
+  408,
+  4096,
+  3977,
+  2560,
+  396,
+  3584,
+  2214,
+  10719,
+  751,
+  427,
+  1150,
+  796,
+  4968,
+  37376,
+  63654,
+  79360,
+  4368,
+  28160,
+  10240,
+  27648,
+  5063,
+  2292,
+  712,
+  5480,
+  2769,
+  446,
+  218,
+  526,
+  3584,
+  2800,
+  44032,
+  504,
+  3584,
+  22016,
+  137,
+  252,
+  181,
+  17920,
+  5966,
+  164860,
+  489984,
+  14848,
+  5366,
+  951,
+  770,
+  9728,
+  12213,
+  23982,
+  11079,
+  567,
+  54687,
+  3011,
+  7220,
+  13312,
+  23306,
+  66560,
+  6424,
+  11264,
+  42483,
+  16946,
+  453,
+  49790,
+  5766,
+  3584,
+  2653,
+  85504,
+  5062,
+  3584,
+  2755,
+  311,
+  879,
+  1004,
+  717,
+  2301,
+  2009,
+  540,
+  1537,
+  836,
+  1365,
+  510,
+  488,
+  5025,
+  651,
+  11264,
+  2194,
+  1402,
+  1224,
+  1576,
+  868,
+  1592,
+  384,
+  1468,
+  1556,
+  1530,
+  1736,
+  16622,
+  75264,
+  9216,
+  1732,
+  1176,
+  1014,
+  1324,
+  760,
+  1240,
+  358,
+  1180,
+  1234,
+  1180,
+  1198,
+  27598,
+  781,
+  3102,
+  2192,
+  3130,
+  2135,
+  3091,
+  389,
+  3053,
+  3160,
+  3137,
+  3144,
+  3051,
+  1626,
+  1712,
+  1695,
+  1711,
+  1564,
+  1326,
+  772,
+  1492,
+  2048,
+  21039,
+  6740,
+  16384,
+  28156,
+  64512,
+  6210,
+  13312,
+  4208,
+  607,
+  4161,
+  2886,
+  1025,
+  555,
+  377,
+  1274,
+  663,
+  490,
+  2004,
+  1078,
+  1402,
+  4082,
+  1459,
+  2770,
+  1100,
+  663,
+  757,
+  654,
+  746,
+  1052,
+  760,
+  2089,
+  636,
+  1394,
+  640,
+  10752,
+  1314,
+  20594,
+  5772,
+  10752,
+  13349,
+  81408,
+  5012,
+  9216,
+  838,
+  2078,
+  548,
+  2218,
+  913,
+  945,
+  962,
+  1775,
+  909,
+  931,
+  1491,
+  47126,
+  4108,
+  6656,
+  12750,
+  78848,
+  3694,
+  6144,
+  2672,
+  3062,
+  94720,
+  949,
+  62743,
+  1154,
+  5120,
+  7501,
+  2560,
+  1064,
+  4608,
+  8826,
+  25358,
+  1396,
+  1332,
+  22025,
+  370,
+  7680,
+  11953,
+  12800,
+  330,
+  6656,
+  1408,
+  2046,
+  2749,
+  1158,
+  1051,
+  1078,
+  2763,
+  11286,
+  1226,
+  1220,
+  1221,
+  1604,
+  6656,
+  7379,
+  67584,
+  1464,
+  5632,
+  729,
+  1129,
+  645,
+  3054,
+  838,
+  394,
+  5120,
+  4621,
+  64512,
+  392,
+  4608,
+  592,
+  645,
+  471,
+  1248,
+  7168,
+  6613,
+  81920,
+  1188,
+  6144,
+  139,
+  1084,
+  1204,
+  1082,
+  645,
+  1928,
+  4192,
+  18369,
+  4979,
+  7110,
+  1390,
+  6656,
+  11429,
+  78848,
+  1310,
+  6144,
+  1120,
+  805,
+  5314,
+  2613,
+  1016,
+  1097,
+  591,
+  3211,
+  2542,
+  4273,
+  344,
+  402,
+  1584,
+  408,
+  1341,
+  414,
+  222486,
+  65,
+  74064,
+  22528,
+  22528,
+  133,
+  966656,
+  966656,
+  4176,
+  44632,
+  2560,
+  1024,
+  13824,
+  9728,
+  2560,
+  11264,
+  45568,
+  6656,
+  3072,
+  4848952,
+  4669136,
+  10976,
+  10976,
+  11520,
+  10976,
+  11488,
+  12288,
+  13248,
+  12800,
+  13200,
+  12720,
+  9280,
+  9504,
+  9856,
+  10064,
+  9792,
+  12304,
+  12256,
+  12336,
+  12384,
+  10976,
+  12288,
+  10224,
+  10608,
+  9472,
+  10240,
+  35808,
+  36672,
+  36656,
+  37296,
+  36672,
+  37472,
+  80896,
+  70000,
+  80896,
+  70000,
+  916684,
+  866652,
+  653588,
+  649244,
+  189124,
+  182112,
+  182096,
+  189264,
+  183276,
+  188976,
+  186728,
+  182208,
+  180452,
+  188932,
+  183412,
+  184020,
+  167620,
+  414772,
+  410464,
+  415776,
+  410988,
+  10992,
+  13552,
+  17760,
+  1330156,
+  1297136,
+  1094912,
+  1133324,
+  963568,
+  1056136,
+  1723352,
+  809512,
+  857200,
+  822568,
+  219524,
+  227628,
+  227684,
+  229412,
+  7216,
+  6352,
+  6672,
+  6672,
+  7232,
+  7216,
+  6336,
+  5168,
+  4320,
+  5200,
+  4640,
+  5168,
+  5168,
+  4304,
+  245572,
+  229444,
+  226704,
+  224248,
+  445180,
+  383780,
+  452056,
+  392232,
+  448368,
+  451860,
+  448788,
+  455620,
+  262288,
+  276064,
+  270728,
+  281096,
+  26432,
+  26544,
+  23440,
+  35888,
+  36032,
+  31760,
+  794216,
+  793256,
+  577340,
+  23408,
+  23440,
+  25024,
+  23440,
+  25024,
+  31712,
+  31776,
+  33344,
+  31808,
+  33360,
+  667232,
+  5600,
+  12896,
+  672300,
+  611212,
+  345208,
+  611556,
+  720012,
+  631992,
+  580168,
+  576004,
+  643852,
+  313856,
+  235848,
+  241972,
+  333636,
+  341072,
+  332036,
+  338776,
+  363200,
+  316440,
+  331128,
+  338140,
+  330012,
+  65,
+  57948,
+  36336,
+  36816,
+  36656,
+  876784,
+  879640,
+  9248,
+  8384,
+  8368,
+  8704,
+  9232,
+  9248,
+  8368,
+  6192,
+  5328,
+  5344,
+  5648,
+  5280,
+  6192,
+  5312,
+  84241,
+  140748,
+  154188,
+  1805996,
+  229912,
+  228504,
+  271648,
+  250668,
+  263504,
+  269048,
+  271832,
+  249924,
+  266156,
+  272460,
+  219644,
+  207484,
+  208428,
+  138196,
+  143448,
+  136176,
+  139324,
+  143684,
+  135328,
+  139800,
+  140268,
+  141608,
+  159464,
+  140808,
+  136228,
+  211780,
+  66660,
+  75340,
+  77384,
+  76356,
+  76352,
+  76084,
+  75832,
+  76104,
+  74244,
+  74476,
+  69916,
+  68464,
+  71600,
+  82744,
+  75980,
+  70896,
+  26040,
+  26489,
+  29779,
+  43318,
+  11056,
+  12400,
+  10032,
+  573308,
+  40264,
+  5680,
+  6512,
+  214808,
+  12896,
+  14432,
+  10656,
+  304568,
+  41584,
+  38480,
+  6528,
+  7728,
+  327420,
+  393764,
+  386264,
+  117092,
+  327516,
+  13457192,
+  12598388,
+  5083240,
+  27652,
+  9533888,
+  9749256,
+  840752,
+  291356,
+  271860,
+  8704,
+  290236,
+  9214528,
+  21402208,
+  14439388,
+  12875900,
+  23648676,
+  16246936,
+  12004804,
+  301876,
+  78272,
+  272840,
+  304076,
+  309956,
+  306076,
+  298668,
+  295152,
+  1422772,
+  1377980,
+  1462828,
+  75160,
+  69316,
+  206612,
+  472216,
+  419976,
+  336672,
+  413712,
+  94412,
+  99464,
+  74520,
+  76972,
+  74200,
+  76300,
+  78136,
+  76184,
+  78756,
+  74944,
+  73820,
+  76080,
+  77632,
+  73660,
+  77284,
+  73352,
+  13312,
+  11056,
+  12384,
+  17760,
+  12288,
+  202428,
+  173700,
+  173080,
+  596924,
+  581228,
+  925736,
+  914092,
+  509768,
+  878372,
+  816540,
+  523052,
+  324448,
+  351908,
+  1690384,
+  1383320,
+  441372,
+  941172,
+  439396,
+  448756,
+  2454648,
+  62944,
+  65392,
+  59024,
+  89456,
+  95488,
+  84080,
+  57936,
+  59952,
+  60752,
+  63296,
+  61024,
+  81728,
+  85360,
+  86256,
+  90736,
+  84848,
+  18214352,
+  17064020,
+  944436,
+  932572,
+  997912,
+  987736,
+  25216,
+  32512,
+  24672,
+  20448,
+  37952,
+  19904,
+  26112,
+  24784,
+  28912,
+  24832,
+  29200,
+  21504,
+  19600,
+  23120,
+  19760,
+  23008,
+  69232,
+  73216,
+  65456,
+  72192,
+  95840,
+  67328,
+  90336,
+  102400,
+  64656,
+  66464,
+  65328,
+  68848,
+  64400,
+  89856,
+  92032,
+  90288,
+  98256,
+  89456,
+  18087936,
+  5680,
+  12896,
+  257052,
+  71000,
+  839004,
+  768964,
+  68260,
+  60480,
+  2576,
+  1110940,
+  1093272,
+  826840,
+  884748,
+  254448,
+  244240,
+  225940,
+  252300,
+  243284,
+  211316,
+  223308,
+  163324,
+  166940,
+  163128,
+  165288,
+  164360,
+  157596,
+  161736,
+  160860,
+  166668,
+  155584,
+  159576,
+  158924,
+  229848,
+  5168,
+  5168,
+  5232,
+  6160,
+  5120,
+  5552,
+  5184,
+  5184,
+  5200,
+  5184,
+  6128,
+  5184,
+  7232,
+  6272,
+  6304,
+  6272,
+  5952,
+  6528,
+  5376,
+  7168,
+  5360,
+  5376,
+  6112,
+  5600,
+  6112,
+  5168,
+  7104,
+  7648,
+  6656,
+  8704,
+  7280,
+  6608,
+  7008,
+  6912,
+  6912,
+  122784,
+  84776,
+  14542540,
+  13827216,
+  13760848,
+  13697012,
+  3869801,
+  2964,
+  1555440,
+  12958,
+  16,
+  6686208,
+  3592,
+  3936,
+  358328,
+  3912,
+  788768,
+  354016,
+  3944,
+  25675936,
+  3368788,
+  1000444,
+  2475780,
+  2470724,
+  2944004,
+  93962,
+  398424,
+  696279,
+  278216,
+  278216,
+  95294,
+  24285,
+  76827,
+  75202,
+  79881,
+  91664,
+  73901,
+  63945,
+  94637,
+  47381,
+  76837,
+  75209,
+  78636,
+  87270,
+  73848,
+  63938,
+  123207,
+  170846,
+  163655,
+  167149,
+  190382,
+  153710,
+  181388,
+  192658,
+  161077,
+  155948,
+  173135,
+  167996,
+  175365,
+  175142,
+  193292,
+  176173,
+  208311,
+  184305,
+  152003,
+  166960,
+  191011,
+  172588,
+  179346,
+  181738,
+  193635,
+  172483,
+  173778,
+  196545,
+  168973,
+  133549,
+  137150,
+  133821,
+  135595,
+  137643,
+  133803,
+  135918,
+  138784,
+  134220,
+  134548,
+  133996,
+  136312,
+  134303,
+  140091,
+  139146,
+  134894,
+  142998,
+  136681,
+  134007,
+  136206,
+  137845,
+  134156,
+  135178,
+  137714,
+  139707,
+  138470,
+  136571,
+  141663,
+  136969,
+  820959,
+  837651,
+  841715,
+  852003,
+  858806,
+  815642,
+  836702,
+  862614,
+  816732,
+  829627,
+  824255,
+  838193,
+  831598,
+  855467,
+  849236,
+  832468,
+  890837,
+  856899,
+  821074,
+  813929,
+  851738,
+  822220,
+  834980,
+  854788,
+  859328,
+  857391,
+  831954,
+  870512,
+  851084,
+  60199,
+  54388,
+  55658,
+  55914,
+  55229,
+  54883,
+  55844,
+  56461,
+  55369,
+  55528,
+  55209,
+  55065,
+  55780,
+  54999,
+  55374,
+  55329,
+  58244,
+  55876,
+  55263,
+  54598,
+  55896,
+  55350,
+  55013,
+  55676,
+  55948,
+  55812,
+  57234,
+  56767,
+  55447,
+  51921,
+  50525,
+  50600,
+  51372,
+  50556,
+  50003,
+  50750,
+  51665,
+  52094,
+  50200,
+  50176,
+  50753,
+  50648,
+  50991,
+  51055,
+  50490,
+  51838,
+  50686,
+  50748,
+  49804,
+  50825,
+  50376,
+  50348,
+  50585,
+  50627,
+  50823,
+  52845,
+  50831,
+  50655,
+  80529,
+  1180712,
+  1177049,
+  1166899,
+  1170755,
+  1174183,
+  1156877,
+  1163286,
+  1172109,
+  1175470,
+  1161012,
+  1156568,
+  1165993,
+  1158947,
+  1176781,
+  1181107,
+  1161986,
+  1193441,
+  1171979,
+  1157102,
+  1168877,
+  1180549,
+  1160990,
+  1163072,
+  1172432,
+  1180765,
+  1171788,
+  1165080,
+  1184896,
+  1166673,
+  234710,
+  68593,
+  17013,
+  29907,
+  43386,
+  230849,
+  219577,
+  60300,
+  15070,
+  29907,
+  39939,
+  1586,
+  77849,
+  19410,
+  610,
+  32573,
+  1584,
+  2409,
+  41256,
+  10954,
+  610,
+  19250,
+  975360,
+  18432,
+  286208,
+  9728,
+  2546176,
+  103936,
+  2139136,
+  65536,
+  257024,
+  7680,
+  321,
+  26605,
+  8686,
+  8762,
+  30720,
+  7702016,
+  199168,
+  210432,
+  516,
+  4,
+  117416,
+  116608,
+  1462,
+  20071,
+  1392,
+  294680,
+  9766,
+  162,
+  22020,
+  1527,
+  82,
+  2560,
+  2560,
+  147456,
+  812544,
+  8017408,
+  7378944,
+  40310,
+  40310,
+  33170,
+  33170,
+  177806,
+  177806,
+  2589632,
+  7390720,
+  46287,
+  48350,
+  1618106,
+  912766,
+  1331040,
+  528404,
+  1322024,
+  404904,
+  893472,
+  377968,
+  429472,
+  7393280,
+  188278,
+  3692612,
+  16629137,
+  1523154,
+  1562816,
+  127488,
+  319,
+  1346,
+  8685,
+  5632,
+  5120,
+  162,
+  167,
+  765,
+  977,
+  565,
+  766,
+  368,
+  1136,
+  883,
+  1064,
+  417,
+  354,
+  354,
+  354,
+  529,
+  612,
+  791,
+  2085,
+  406,
+  406,
+  542,
+  595,
+  747,
+  1881,
+  354,
+  354,
+  354,
+  529,
+  529,
+  612,
+  612,
+  791,
+  791,
+  2085,
+  2085,
+  642,
+  1232,
+  2946,
+  2946,
+  4048,
+  4901,
+  8060,
+  22343,
+  2851,
+  2851,
+  3886,
+  4751,
+  7782,
+  21801,
+  2946,
+  2946,
+  4048,
+  4901,
+  8060,
+  22343,
+  569,
+  375,
+  977,
+  977,
+  1252,
+  1826,
+  2338,
+  5709,
+  1010,
+  1010,
+  1270,
+  1775,
+  2227,
+  5481,
+  977,
+  977,
+  1252,
+  1826,
+  2338,
+  5709,
+  893,
+  569,
+  569,
+  689,
+  911,
+  1250,
+  2924,
+  526,
+  526,
+  736,
+  864,
+  1199,
+  2811,
+  569,
+  569,
+  689,
+  911,
+  1250,
+  2924,
+  741,
+  175,
+  184,
+  583,
+  1185,
+  508,
+  496,
+  434,
+  857,
+  654,
+  835,
+  353,
+  547,
+  1357,
+  324,
+  618,
+  502,
+  4,
+  1648,
+  1624,
+  8000,
+  861,
+  1011,
+  991,
+  1005,
+  1058,
+  945,
+  963,
+  939,
+  945,
+  945,
+  905,
+  947,
+  914,
+  930,
+  877,
+  897,
+  884,
+  912,
+  901,
+  897,
+  906,
+  900,
+  885,
+  891,
+  906,
+  906,
+  866,
+  872,
+  928,
+  904,
+  886,
+  931,
+  881,
+  857,
+  897,
+  877,
+  904,
+  889,
+  901,
+  885,
+  839,
+  866,
+  892,
+  908,
+  920,
+  893,
+  901,
+  933,
+  874,
+  880,
+  872,
+  872,
+  896,
+  877,
+  873,
+  869,
+  868,
+  826,
+  820,
+  823,
+  814,
+  817,
+  802,
+  846,
+  1009,
+  1003,
+  988,
+  823,
+  829,
+  808,
+  814,
+  796,
+  805,
+  832,
+  838,
+  862,
+  838,
+  829,
+  803,
+  799,
+  808,
+  827,
+  823,
+  823,
+  862,
+  850,
+  838,
+  841,
+  847,
+  829,
+  838,
+  814,
+  799,
+  808,
+  790,
+  814,
+  835,
+  817,
+  835,
+  823,
+  844,
+  838,
+  814,
+  817,
+  808,
+  811,
+  832,
+  826,
+  826,
+  829,
+  823,
+  844,
+  823,
+  814,
+  829,
+  832,
+  841,
+  855,
+  832,
+  823,
+  850,
+  814,
+  820,
+  823,
+  826,
+  829,
+  829,
+  876,
+  817,
+  835,
+  814,
+  817,
+  826,
+  847,
+  826,
+  826,
+  820,
+  835,
+  796,
+  793,
+  859,
+  799,
+  796,
+  864,
+  832,
+  832,
+  787,
+  808,
+  885,
+  891,
+  882,
+  878,
+  1002,
+  1002,
+  1017,
+  1005,
+  1003,
+  1015,
+  1037,
+  1004,
+  1036,
+  1038,
+  1011,
+  1077,
+  1068,
+  1053,
+  1005,
+  1001,
+  1033,
+  1038,
+  1050,
+  1035,
+  1006,
+  1048,
+  1057,
+  1057,
+  1050,
+  1038,
+  1017,
+  1017,
+  1020,
+  1018,
+  948,
+  1035,
+  1037,
+  1033,
+  981,
+  972,
+  1036,
+  1042,
+  1054,
+  1018,
+  964,
+  998,
+  991,
+  976,
+  982,
+  976,
+  970,
+  979,
+  976,
+  1024,
+  952,
+  955,
+  1018,
+  973,
+  958,
+  1007,
+  921,
+  1050,
+  961,
+  975,
+  981,
+  954,
+  958,
+  1000,
+  979,
+  981,
+  964,
+  973,
+  970,
+  964,
+  968,
+  1010,
+  1012,
+  1027,
+  1046,
+  1012,
+  1004,
+  977,
+  967,
+  976,
+  999,
+  1005,
+  1018,
+  1012,
+  982,
+  974,
+  972,
+  1001,
+  998,
+  998,
+  968,
+  971,
+  1022,
+  1016,
+  995,
+  977,
+  1002,
+  1008,
+  1026,
+  1006,
+  1011,
+  1036,
+  990,
+  999,
+  1006,
+  966,
+  1020,
+  975,
+  929,
+  962,
+  953,
+  1016,
+  1048,
+  1000,
+  1032,
+  1000,
+  1032,
+  1008,
+  1040,
+  982,
+  991,
+  988,
+  982,
+  983,
+  998,
+  1016,
+  979,
+  976,
+  987,
+  1013,
+  1025,
+  1009,
+  1003,
+  974,
+  951,
+  978,
+  969,
+  954,
+  975,
+  975,
+  969,
+  969,
+  956,
+  972,
+  974,
+  1001,
+  1001,
+  1017,
+  996,
+  1000,
+  1024,
+  1009,
+  987,
+  984,
+  993,
+  1023,
+  1053,
+  986,
+  1011,
+  1030,
+  1011,
+  1030,
+  991,
+  991,
+  975,
+  1009,
+  987,
+  954,
+  978,
+  969,
+  966,
+  949,
+  982,
+  974,
+  956,
+  989,
+  989,
+  982,
+  956,
+  956,
+  941,
+  956,
+  986,
+  974,
+  920,
+  980,
+  1056,
+  1056,
+  1052,
+  1009,
+  1014,
+  1020,
+  1008,
+  999,
+  998,
+  1020,
+  984,
+  932,
+  929,
+  953,
+  967,
+  920,
+  932,
+  920,
+  940,
+  973,
+  962,
+  1022,
+  1008,
+  944,
+  957,
+  1045,
+  953,
+  952,
+  943,
+  952,
+  973,
+  952,
+  962,
+  938,
+  981,
+  984,
+  984,
+  998,
+  975,
+  818,
+  470294,
+  1202,
+  1181,
+  1045,
+  1135,
+  1019,
+  981,
+  1153,
+  1019,
+  962,
+  851,
+  961,
+  1206,
+  1011,
+  913,
+  830,
+  1164,
+  865,
+  1232,
+  898,
+  991,
+  970,
+  1206,
+  1168,
+  1169,
+  1214,
+  982,
+  937,
+  924,
+  973,
+  937,
+  956,
+  946,
+  1030,
+  1154,
+  1048,
+  978,
+  1011,
+  1074,
+  837,
+  1116,
+  1020,
+  1000,
+  969,
+  1116,
+  991,
+  1159,
+  1036,
+  1014,
+  912,
+  1092,
+  1067,
+  988,
+  998,
+  1055,
+  881,
+  866,
+  1019,
+  1089,
+  966,
+  1024,
+  1118,
+  1114,
+  923,
+  925,
+  959,
+  961,
+  1000,
+  1206,
+  821,
+  991,
+  824,
+  929,
+  979,
+  1061,
+  1156,
+  1131,
+  944,
+  1183,
+  995,
+  1105,
+  1022,
+  983,
+  1020,
+  920,
+  1039,
+  954,
+  1048,
+  1042,
+  1118,
+  974,
+  1243,
+  1016,
+  930,
+  1030,
+  1068,
+  1130,
+  938,
+  981,
+  1149,
+  1074,
+  959,
+  956,
+  919,
+  941,
+  950,
+  1006,
+  1020,
+  913,
+  1033,
+  867,
+  843,
+  1149,
+  957,
+  1068,
+  964,
+  941,
+  914,
+  999,
+  937,
+  837,
+  1000,
+  1089,
+  963,
+  998,
+  1022,
+  1149,
+  832,
+  855,
+  980,
+  807,
+  1062,
+  938,
+  947,
+  979,
+  1022,
+  992,
+  1030,
+  998,
+  1014,
+  961,
+  940,
+  957,
+  827,
+  1153,
+  866,
+  1114,
+  921,
+  1012,
+  944,
+  1151,
+  887,
+  1060,
+  937,
+  912,
+  1077,
+  923,
+  1037,
+  1071,
+  1192,
+  986,
+  985,
+  968,
+  994,
+  1004,
+  824,
+  1176,
+  990,
+  1040,
+  947,
+  1062,
+  1232,
+  938,
+  1148,
+  1032,
+  911,
+  895,
+  743,
+  774,
+  846,
+  5877760,
+  95104,
+  504,
+  1043968,
+  53760,
+  36,
+  36,
+  829,
+  54230,
+  45,
+  45,
+  811,
+  52828,
+  42,
+  42,
+  1055,
+  166446,
+  65,
+  65,
+  444,
+  98700,
+  53,
+  53,
+  444,
+  98752,
+  33,
+  33,
+  381,
+  1288,
+  36,
+  36,
+  6067,
+  1517020,
+  11222,
+  20076,
+  4034,
+  10124,
+  4510,
+  4150,
+  10500,
+  3816,
+  7532,
+  2500,
+  7060,
+  3124,
+  7660,
+  2560,
+  7612,
+  23024,
+  28740,
+  9932,
+  14572,
+  6256,
+  12140,
+  124744,
+  46912,
+  64756,
+  31,
+  7177,
+  995542,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  819516,
+  6537,
+  819516,
+  30,
+  7177,
+  997498,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  819522,
+  6537,
+  819522,
+  36,
+  318,
+  42996,
+  357050,
+  2242,
+  6108,
+  7442,
+  4242,
+  7500,
+  3228,
+  3686,
+  52958,
+  3754,
+  7356,
+  8924,
+  2766,
+  2846,
+  2770,
+  1479,
+  2558,
+  89110,
+  6336,
+  10140,
+  8106,
+  12492,
+  17880,
+  5428,
+  5946,
+  4008,
+  1648,
+  5276,
+  3424,
+  8372,
+  6578,
+  10812,
+  8294,
+  11572,
+  3202,
+  7772,
+  37872,
+  15974,
+  16396,
+  28690,
+  53252,
+  32834,
+  20812,
+  4288,
+  10052,
+  4746,
+  7788,
+  12934,
+  19588,
+  1154,
+  1012,
+  2764,
+  7052,
+  1008,
+  690,
+  3972,
+  1060,
+  1022,
+  1128,
+  692,
+  3964,
+  2100,
+  1062,
+  2306,
+  6252,
+  1416,
+  962,
+  972,
+  1056,
+  4500,
+  1264,
+  2870,
+  7748,
+  1992,
+  1158,
+  4676,
+  1130,
+  4612,
+  1164,
+  4684,
+  1136,
+  4636,
+  1158,
+  4668,
+  1158,
+  4700,
+  1154,
+  4660,
+  1136,
+  4644,
+  1104,
+  4564,
+  1148,
+  4652,
+  1152,
+  4692,
+  1190,
+  4764,
+  1156,
+  4692,
+  1136,
+  4628,
+  1162,
+  4692,
+  1132,
+  4620,
+  1154,
+  4684,
+  1128,
+  4668,
+  1150,
+  4660,
+  3140,
+  1202,
+  2452,
+  5604,
+  5776,
+  1546,
+  1406,
+  1120,
+  700,
+  3844,
+  680,
+  4012,
+  1116,
+  4532,
+  7646,
+  1316,
+  1014,
+  1128,
+  2570,
+  6876,
+  1472,
+  960,
+  1032,
+  1044,
+  2572,
+  1178,
+  1080,
+  4548,
+  1180,
+  1344,
+  1010,
+  1078,
+  1114,
+  1240,
+  1806,
+  5380,
+  1680,
+  5396,
+  666,
+  3940,
+  1006,
+  2326,
+  6324,
+  1144,
+  4644,
+  1356,
+  1010,
+  1028,
+  6106,
+  974,
+  1126,
+  1478,
+  1058,
+  4500,
+  2694,
+  6996,
+  2652,
+  6972,
+  1162,
+  3266,
+  1176,
+  1108,
+  1842,
+  1084,
+  1208,
+  1112,
+  4580,
+  1016,
+  1182,
+  7232,
+  12444,
+  31632,
+  29344,
+  29344,
+  8156,
+  7756,
+  12784,
+  17044,
+  3426,
+  7668,
+  3952,
+  584,
+  39622,
+  78064,
+  2826,
+  7496,
+  6270,
+  8332,
+  110927,
+  3108,
+  8700,
+  975476,
+  500344,
+  975476,
+  35700,
+  2230,
+  6460,
+  5792,
+  10036,
+  700038,
+  5324,
+  7326,
+  4418,
+  8124,
+  2058,
+  5276,
+  3698,
+  2314,
+  6044,
+  10572,
+  105198,
+  103572,
+  68300,
+  2554,
+  7484,
+  4156,
+  10156,
+  7744,
+  4148,
+  8660,
+  5154,
+  9460,
+  3958,
+  9700,
+  70670,
+  34596,
+  4572,
+  3716,
+  9768,
+  20532,
+  1786,
+  6036,
+  26824,
+  31580,
+  3724,
+  7516,
+  4070,
+  8156,
+  11662,
+  12916,
+  11968,
+  14052,
+  13876,
+  18172,
+  15402,
+  22036,
+  9956,
+  12724,
+  10380,
+  13964,
+  8122,
+  12612,
+  12616,
+  16692,
+  4166,
+  27662,
+  73928,
+  153148,
+  34544,
+  10586,
+  34544,
+  34544,
+  10586,
+  34544,
+  34544,
+  10586,
+  34544,
+  34544,
+  34544,
+  34544,
+  34544,
+  34544,
+  34544,
+  34544,
+  34544,
+  229,
+  10586,
+  229,
+  4134,
+  7628,
+  4010,
+  7148,
+  60840,
+  7160,
+  11332,
+  6450,
+  9740,
+  84218,
+  118548,
+  68062,
+  134140,
+  26432,
+  9832,
+  18844,
+  2864,
+  6574,
+  12300,
+  17868,
+  27084,
+  22396,
+  27068,
+  5378,
+  9844,
+  145968,
+  156116,
+  4588,
+  8668,
+  4754,
+  93080,
+  107772,
+  65972,
+  13482,
+  80568,
+  171806,
+  5730,
+  27262,
+  19720,
+  120372,
+  28978,
+  8198,
+  15558,
+  49800,
+  14466,
+  105144,
+  20416,
+  25830,
+  88896,
+  24836,
+  55742,
+  63380,
+  8450,
+  29398,
+  25790,
+  12086,
+  137326,
+  26092,
+  56996,
+  7526,
+  12050,
+  243776,
+  56662,
+  11166,
+  23974,
+  118782,
+  111928,
+  107186,
+  45598,
+  26536,
+  19476,
+  18622,
+  266006,
+  86868,
+  35708,
+  152552,
+  19952,
+  31048,
+  82068,
+  22124,
+  89728,
+  47188,
+  98330,
+  89444,
+  98810,
+  104296,
+  1574382,
+  94068,
+  152526,
+  205386,
+  80412,
+  216596,
+  126054,
+  38968,
+  5028,
+  66028,
+  100404,
+  144846,
+  40530,
+  35686,
+  137064,
+  88352,
+  28582,
+  8938,
+  11452,
+  20706,
+  46182,
+  44850,
+  19038,
+  10228,
+  88788,
+  72772,
+  16954,
+  143864,
+  97254,
+  254856,
+  10430,
+  16894,
+  832958,
+  24040,
+  5732,
+  106688,
+  23304,
+  9538,
+  9602,
+  8244,
+  8322,
+  76410,
+  23248,
+  12244,
+  24678,
+  24328,
+  8714,
+  16054,
+  17254,
+  8372,
+  29516,
+  142858,
+  9088,
+  61202,
+  38408,
+  111000,
+  21148,
+  6480,
+  75332,
+  15414,
+  103226,
+  24976,
+  81708,
+  85148,
+  158182,
+  53316,
+  27596,
+  13248,
+  98472,
+  10102,
+  43146,
+  58978,
+  230698,
+  55956,
+  91872,
+  32492,
+  36630,
+  26488,
+  36130,
+  19834,
+  25730,
+  18860,
+  71780,
+  44666,
+  27150,
+  6068,
+  23790,
+  61154,
+  99100,
+  6860,
+  4858,
+  31168,
+  242920,
+  75430,
+  216056,
+  103516,
+  157736,
+  207412,
+  13974,
+  15700,
+  8942,
+  11804,
+  318550,
+  364956,
+  3200,
+  8972,
+  2388,
+  4126,
+  5912,
+  12516,
+  86462,
+  76452,
+  9070,
+  790436,
+  1176964,
+  61436,
+  2190,
+  3682,
+  3864,
+  4182,
+  3864,
+  768,
+  49,
+  49,
+  49,
+  705,
+  131728,
+  47,
+  47,
+  705,
+  135800,
+  43838,
+  5884,
+  11804,
+  60908,
+  69412,
+  58210,
+  98652,
+  31186,
+  37644,
+  3452,
+  7972,
+  26808,
+  38398,
+  3852,
+  7828,
+  1044,
+  7892,
+  13524,
+  33988,
+  3386,
+  2208,
+  25160,
+  2982,
+  2712,
+  6404,
+  176484,
+  125868,
+  51026,
+  62572,
+  29228,
+  40564,
+  12568,
+  22628,
+  19112,
+  68176,
+  60244,
+  30092,
+  40810,
+  248286,
+  551212,
+  5276,
+  6980,
+  30894,
+  31930,
+  434302,
+  98426,
+  71644,
+  2656,
+  10542,
+  13516,
+  723666,
+  83830,
+  99418,
+  97762,
+  329418,
+  273392,
+  261692,
+  37444,
+  3174,
+  4370,
+  13582,
+  45834,
+  101928,
+  19080,
+  430184,
+  82502,
+  13446,
+  2140,
+  6166,
+  87594,
+  93928,
+  2460,
+  214348,
+  2154,
+  83726,
+  35016,
+  4186,
+  4794,
+  8618,
+  307862,
+  285242,
+  64914,
+  24424,
+  23620,
+  5292,
+  8186,
+  11886,
+  33690,
+  268356,
+  110094,
+  40642,
+  230496,
+  2380,
+  5136,
+  6788,
+  95530,
+  8470,
+  13622,
+  15068,
+  33734,
+  6066,
+  116538,
+  34764,
+  6694,
+  7100,
+  3798,
+  8272,
+  3442,
+  398670,
+  136934,
+  319876,
+  28282,
+  991868,
+  15784,
+  1014176,
+  243844,
+  526428,
+  45578,
+  3010,
+  7756,
+  15134,
+  2678,
+  18102,
+  8926,
+  10148,
+  2818,
+  8236,
+  20190,
+  20596,
+  6955,
+  1046848,
+  369,
+  1046848,
+  369,
+  12338,
+  3113,
+  91662,
+  471312,
+  76048,
+  15032,
+  3130,
+  128374,
+  530416,
+  75288,
+  16920,
+  3096,
+  139821,
+  486344,
+  75288,
+  125728,
+  89872,
+  89144,
+  90608,
+  404752,
+  1028,
+  19667,
+  28511,
+  65288,
+  11194,
+  155192,
+  315888,
+  36472,
+  316736,
+  13916,
+  3066,
+  126310,
+  401376,
+  76048,
+  12420,
+  3066,
+  115628,
+  400656,
+  75288,
+  125728,
+  89144,
+  89872,
+  404072,
+  212,
+  121440,
+  2810,
+  60778,
+  155128,
+  36472,
+  54392,
+  35424,
+  9033,
+  6668,
+  117460,
+  187392,
+  36472,
+  61632,
+  404072,
+  121440,
+  10476,
+  3114,
+  87177,
+  495376,
+  73480,
+  13106,
+  3130,
+  122503,
+  501216,
+  73512,
+  19440,
+  2716,
+  191560,
+  302464,
+  11126,
+  3093,
+  89526,
+  497424,
+  73480,
+  13024,
+  3097,
+  154115,
+  498672,
+  76784,
+  16988,
+  3097,
+  190046,
+  499184,
+  76784,
+  9802,
+  3097,
+  42986,
+  499184,
+  76784,
+  11446,
+  3315,
+  140902,
+  302296,
+  36472,
+  125728,
+  90608,
+  91936,
+  101216,
+  89888,
+  90608,
+  89888,
+  89144,
+  98496,
+  60608,
+  404752,
+  1081,
+  9697,
+  2777,
+  20667,
+  138512,
+  64168,
+  14848,
+  3049,
+  132659,
+  411120,
+  89072,
+  36472,
+  92144,
+  405488,
+  256,
+  19667,
+  28511,
+  65288,
+  9311,
+  166032,
+  36472,
+  316736,
+  12590,
+  3050,
+  87645,
+  271024,
+  68264,
+  14850,
+  3050,
+  153989,
+  370968,
+  73512,
+  11362,
+  3050,
+  117277,
+  370968,
+  73512,
+  36472,
+  125728,
+  92864,
+  91936,
+  92448,
+  89872,
+  79720,
+  404072,
+  256,
+  9732,
+  3046,
+  84534,
+  357856,
+  76232,
+  9782,
+  3075,
+  20816,
+  131584,
+  73480,
+  5174,
+  2939,
+  12442,
+  3114,
+  92354,
+  468752,
+  73480,
+  15038,
+  3130,
+  128291,
+  529392,
+  73512,
+  17742,
+  3097,
+  176198,
+  523248,
+  76784,
+  11729,
+  3097,
+  44389,
+  522736,
+  76784,
+  36472,
+  125728,
+  90608,
+  91936,
+  89888,
+  90608,
+  80672,
+  404752,
+  1083,
+  11897,
+  2743,
+  22579,
+  131344,
+  73480,
+  16770,
+  3049,
+  144852,
+  442864,
+  89072,
+  36472,
+  92144,
+  80880,
+  405488,
+  260,
+  12717,
+  3043,
+  56912,
+  318944,
+  89072,
+  19667,
+  28511,
+  2236928,
+  2239488,
+  48464,
+  65288,
+  11361,
+  156656,
+  10997,
+  10224,
+  8796,
+  12249,
+  8148,
+  9369,
+  8944,
+  10400,
+  494960,
+  503664,
+  473968,
+  10758,
+  12146,
+  483184,
+  163696,
+  10046,
+  10040,
+  165232,
+  8657,
+  9915,
+  71952,
+  279024,
+  60752,
+  316400,
+  36472,
+  316736,
+  1721576,
+  16797,
+  3050,
+  162256,
+  352024,
+  73512,
+  13277,
+  3050,
+  126428,
+  352024,
+  73512,
+  36472,
+  125728,
+  91936,
+  92448,
+  89872,
+  80672,
+  404072,
+  268,
+  11656,
+  3046,
+  91773,
+  388040,
+  76232,
+  11904,
+  3075,
+  22837,
+  133392,
+  73480,
+  121440,
+  12423,
+  3114,
+  92426,
+  468752,
+  73480,
+  15026,
+  3130,
+  128070,
+  529392,
+  73512,
+  19440,
+  2716,
+  191560,
+  302464,
+  13073,
+  3093,
+  94851,
+  469264,
+  73480,
+  14946,
+  3097,
+  163489,
+  470512,
+  76784,
+  18910,
+  3097,
+  199105,
+  523248,
+  76784,
+  11725,
+  3097,
+  45051,
+  522736,
+  76784,
+  11446,
+  3315,
+  140902,
+  302296,
+  36472,
+  125728,
+  90608,
+  91936,
+  101216,
+  89888,
+  90608]
diff --git a/tests/fragmentation/tfragment_alloc.nim b/tests/fragmentation/tfragment_alloc.nim
new file mode 100644
index 000000000..cd45e2c47
--- /dev/null
+++ b/tests/fragmentation/tfragment_alloc.nim
@@ -0,0 +1,35 @@
+
+discard """
+  output: '''occupied ok: true
+total ok: true'''
+  disabled: "true"
+"""
+
+import strutils, data
+
+proc main =
+  var m = 0
+  for i in 0..1000_000:
+    let size = sizes[i mod sizes.len]
+    let p = alloc(size)
+    if p == nil:
+      quit "could not serve request!"
+    dealloc p
+ #   c_fprintf(stdout, "iteration: %ld size: %ld\n", i, size)
+  when defined(cpu64):
+    # see https://github.com/nim-lang/Nim/issues/8509
+    # this often made appveyor (on windows) fail with out of memory
+    when defined(posix):
+      # bug #7120
+      var x = alloc(((1 shl 29) - 4) * 8)
+      dealloc x
+
+main()
+
+let occ = getOccupiedMem()
+let total = getTotalMem()
+
+# Current values on Win64: 824KiB / 106.191MiB
+
+echo "occupied ok: ", occ < 2 * 1024 * 1024
+echo "total ok: ", total < 120 * 1024 * 1024
diff --git a/tests/fragmentation/tfragment_gc.nim b/tests/fragmentation/tfragment_gc.nim
new file mode 100644
index 000000000..0ae8c3d7f
--- /dev/null
+++ b/tests/fragmentation/tfragment_gc.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''occupied ok: true
+total ok: true'''
+  disabled: "true"
+"""
+
+import strutils, data
+
+proc main =
+  var m = 0
+  # Since the GC test is slower than the alloc test, we only iterate 100_000 times here:
+  for i in 0..100_000:
+    let size = sizes[i mod sizes.len]
+    let p = newString(size)
+ #   c_fprintf(stdout, "iteration: %ld size: %ld\n", i, size)
+
+main()
+
+let occ = getOccupiedMem()
+let total = getTotalMem()
+
+# Concrete values on Win64: 58.152MiB / 188.285MiB
+
+let occupiedOk = occ < 82 * 1024 * 1024
+if not occupiedOk:
+  echo "occupied ", formatSize(occ)
+echo "occupied ok: ", occupiedOk
+let totalOk = total < 230 * 1024 * 1024
+if not totalOk:
+  echo "total peak memory ", formatSize(total)
+echo "total ok: ", totalOk
diff --git a/tests/gc/bintrees.nim b/tests/gc/bintrees.nim
new file mode 100644
index 000000000..5b65bb437
--- /dev/null
+++ b/tests/gc/bintrees.nim
@@ -0,0 +1,54 @@
+# -*- nim -*-
+
+import os, strutils
+
+type
+  PNode = ref TNode
+  TNode {.final, acyclic.} = object
+    left, right: PNode
+    item: int
+
+proc checkTree(node: PNode): int =
+  result = node.item
+  if node.left != nil:
+    inc result, checkTree(node.left) - checkTree(node.right)
+
+proc makeTreeAux(item, depth: int): PNode =
+  new(result)
+  result.item = item
+  if depth > 0:
+    result.left = makeTreeAux(2 * item - 1, depth - 1)
+    result.right = makeTreeAux(2 * item,    depth - 1)
+
+proc makeTree(item, depth: int): PNode =
+  #GC_disable()
+  result = makeTreeAux(item, depth)
+  #GC_enable()
+
+proc main =
+  var n = parseInt(paramStr(1))
+  const minDepth = 4
+  var maxDepth = if minDepth+2 > n: minDepth+2 else: n
+
+  var stretchDepth = maxDepth + 1
+
+  echo("stretch tree of depth ", stretchDepth, "\t check: ", checkTree(
+      makeTree(0, stretchDepth)))
+
+  var longLivedTree = makeTree(0, maxDepth)
+
+  var iterations = 1 shl maxDepth
+  for depth in countup (minDepth, stretchDepth-1, 2):
+    var check = 0
+    for i in 1..iterations:
+      check += checkTree(makeTree(i, depth)) + checkTree(makeTree(-i, depth))
+
+    echo(iterations*2, "\t trees of depth ", depth, "\t check: ", check)
+    iterations = iterations div 4
+
+  echo("long lived tree of depth ", maxDepth, "\t check: ",
+      longLivedTree.checkTree)
+  echo GC_getstatistics()
+
+main()
+
diff --git a/tests/gc/closureleak.nim b/tests/gc/closureleak.nim
new file mode 100644
index 000000000..e67beb513
--- /dev/null
+++ b/tests/gc/closureleak.nim
@@ -0,0 +1,52 @@
+discard """
+  outputsub: "true"
+  disabled: "32bit"
+"""
+
+type
+  TFoo* = object
+    id: int
+    fn: proc() {.closure.}
+var foo_counter = 0
+var alive_foos = newseq[int](0)
+
+when defined(gcDestructors):
+  proc `=destroy`(some: TFoo) =
+    alive_foos.del alive_foos.find(some.id)
+    # TODO: fixme: investigate why `=destroy` requires `some.fn` to be `gcsafe`
+    # the debugging info below came from `symPrototype` in the liftdestructors
+    # proc (){.closure, gcsafe.}, {tfThread, tfHasAsgn, tfCheckedForDestructor, tfExplicitCallConv}
+    # var proc (){.closure, gcsafe.}, {tfHasGCedMem}
+    # it worked by accident with var T destructors because in the sempass2
+    #
+    # let argtype = skipTypes(a.typ, abstractInst) # !!! it does't skip `tyVar`
+    # if argtype.kind == tyProc and notGcSafe(argtype) and not tracked.inEnforcedGcSafe:
+    #   localError(tracked.config, n.info, $n & " is not GC safe")
+    {.cast(gcsafe).}:
+      `=destroy`(some.fn)
+
+else:
+  proc free*(some: ref TFoo) =
+    #echo "Tfoo #", some.id, " freed"
+    alive_foos.del alive_foos.find(some.id)
+
+proc newFoo*(): ref TFoo =
+  when defined(gcDestructors):
+    new result
+  else:
+    new result, free
+
+  result.id = foo_counter
+  alive_foos.add result.id
+  inc foo_counter
+
+for i in 0 ..< 10:
+  discard newFoo()
+
+for i in 0 ..< 10:
+  let f = newFoo()
+  f.fn = proc =
+    echo f.id
+
+GC_fullcollect()
+echo alive_foos.len <= 3
diff --git a/tests/gc/cyclecollector.nim b/tests/gc/cyclecollector.nim
new file mode 100644
index 000000000..2d02a7a3c
--- /dev/null
+++ b/tests/gc/cyclecollector.nim
@@ -0,0 +1,23 @@
+
+# Program to detect bug #1796 reliably
+
+type
+  Node = ref object
+    a, b: Node
+    leaf: string
+
+proc createCycle(leaf: string): Node =
+  new result
+  result.a = result
+  when defined(gcArc) or defined(gcOrc):
+    result.leaf = leaf
+  else:
+    shallowCopy result.leaf, leaf
+
+proc main =
+  for i in 0 .. 100_000:
+    var leaf = "this is the leaf. it allocates"
+    let x = createCycle(leaf)
+    let y = createCycle(leaf)
+
+main()
diff --git a/tests/gc/cycleleak.nim b/tests/gc/cycleleak.nim
new file mode 100644
index 000000000..e355abc96
--- /dev/null
+++ b/tests/gc/cycleleak.nim
@@ -0,0 +1,56 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  Module = object
+    nodes*: seq[PNode]
+    id: int
+
+  PModule = ref Module
+
+  Node = object
+    owner* {.cursor.}: PModule
+    data*: array[0..200, char] # some fat to drain memory faster
+    id: int
+
+  PNode = ref Node
+
+var
+  gid: int
+
+when false:
+  proc finalizeNode(x: PNode) =
+    echo "node id: ", x.id
+  proc finalizeModule(x: PModule) =
+    echo "module id: ", x.id
+
+proc newNode(owner: PModule): PNode =
+  new(result)
+  result.owner = owner
+  inc gid
+  result.id = gid
+
+proc compileModule: PModule =
+  new(result)
+  result.nodes = @[]
+  for i in 0..100:
+    result.nodes.add newNode(result)
+  inc gid
+  result.id = gid
+
+var gModuleCache: PModule
+
+proc loop =
+  for i in 0..1000:
+    gModuleCache = compileModule()
+    gModuleCache = nil
+    GC_fullCollect()
+
+    if getOccupiedMem() > 9_000_000:
+      echo "still a leak! ", getOccupiedMem()
+      quit(1)
+  echo "no leak: ", getOccupiedMem()
+
+loop()
+
diff --git a/tests/gc/foreign_thr.nim b/tests/gc/foreign_thr.nim
new file mode 100644
index 000000000..88ab95113
--- /dev/null
+++ b/tests/gc/foreign_thr.nim
@@ -0,0 +1,88 @@
+discard """
+  output: '''
+Hello from thread
+Hello from thread
+Hello from thread
+Hello from thread
+'''
+  cmd: "nim $target --hints:on --threads:on --tlsEmulation:off $options $file"
+"""
+# Copied from stdlib
+import strutils
+
+const
+  StackGuardSize = 4096
+  ThreadStackMask = 1024*256*sizeof(int)-1
+  ThreadStackSize = ThreadStackMask+1 - StackGuardSize
+
+type ThreadFunc = proc() {.thread.}
+
+when defined(posix):
+  import posix
+
+  proc runInForeignThread(f: ThreadFunc) =
+    proc wrapper(p: pointer): pointer {.noconv.} =
+      let thr = cast[ThreadFunc](p)
+      setupForeignThreadGc()
+      thr()
+      tearDownForeignThreadGc()
+      setupForeignThreadGc()
+      thr()
+      tearDownForeignThreadGc()
+      result = nil
+
+    var attrs {.noinit.}: PthreadAttr
+    doAssert pthread_attr_init(addr attrs) == 0
+    doAssert pthread_attr_setstacksize(addr attrs, ThreadStackSize) == 0
+    var tid: Pthread
+    doAssert pthread_create(addr tid, addr attrs, wrapper, f) == 0
+    doAssert pthread_join(tid, nil) == 0
+
+elif defined(windows):
+  import winlean
+  type
+    WinThreadProc = proc (x: pointer): int32 {.stdcall.}
+
+  proc createThread(lpThreadAttributes: pointer, dwStackSize: DWORD,
+                     lpStartAddress: WinThreadProc,
+                     lpParameter: pointer,
+                     dwCreationFlags: DWORD,
+                     lpThreadId: var DWORD): Handle {.
+    stdcall, dynlib: "kernel32", importc: "CreateThread".}
+
+  proc wrapper(p: pointer): int32 {.stdcall.} =
+    let thr = cast[ThreadFunc](p)
+    setupForeignThreadGc()
+    thr()
+    tearDownForeignThreadGc()
+    setupForeignThreadGc()
+    thr()
+    tearDownForeignThreadGc()
+    result = 0'i32
+
+  proc runInForeignThread(f: ThreadFunc) =
+    var dummyThreadId: DWORD
+    var h = createThread(nil, ThreadStackSize.int32, wrapper.WinThreadProc, cast[pointer](f), 0, dummyThreadId)
+    doAssert h != 0.Handle
+    doAssert waitForSingleObject(h, -1'i32) == 0.DWORD
+
+else:
+  {.fatal: "Unknown system".}
+
+proc runInNativeThread(f: ThreadFunc) =
+  proc wrapper(f: ThreadFunc) {.thread.} =
+    # These operations must be NOP
+    setupForeignThreadGc()
+    tearDownForeignThreadGc()
+    f()
+    f()
+  var thr: Thread[ThreadFunc]
+  createThread(thr, wrapper, f)
+  joinThread(thr)
+
+proc f {.thread.} =
+  var msg = "Hello " & "from thread"
+  echo msg
+
+runInForeignThread(f)
+runInNativeThread(f)
diff --git a/tests/gc/gcbench.nim b/tests/gc/gcbench.nim
new file mode 100644
index 000000000..e29ea762d
--- /dev/null
+++ b/tests/gc/gcbench.nim
@@ -0,0 +1,180 @@
+discard """
+  outputsub: "Success!"
+"""
+
+# This is adapted from a benchmark written by John Ellis and Pete Kovac
+# of Post Communications.
+# It was modified by Hans Boehm of Silicon Graphics.
+#
+# This is no substitute for real applications. No actual application
+# is likely to behave in exactly this way. However, this benchmark was
+# designed to be more representative of real applications than other
+# Java GC benchmarks of which we are aware.
+# It attempts to model those properties of allocation requests that
+# are important to current GC techniques.
+# It is designed to be used either to obtain a single overall performance
+# number, or to give a more detailed estimate of how collector
+# performance varies with object lifetimes. It prints the time
+# required to allocate and collect balanced binary trees of various
+# sizes. Smaller trees result in shorter object lifetimes. Each cycle
+# allocates roughly the same amount of memory.
+# Two data structures are kept around during the entire process, so
+# that the measured performance is representative of applications
+# that maintain some live in-memory data. One of these is a tree
+# containing many pointers. The other is a large array containing
+# double precision floating point numbers. Both should be of comparable
+# size.
+#
+# The results are only really meaningful together with a specification
+# of how much memory was used. It is possible to trade memory for
+# better time performance. This benchmark should be run in a 32 MB
+# heap, though we don't currently know how to enforce that uniformly.
+#
+# Unlike the original Ellis and Kovac benchmark, we do not attempt
+# measure pause times. This facility should eventually be added back
+# in. There are several reasons for omitting it for now.  The original
+# implementation depended on assumptions about the thread scheduler
+# that don't hold uniformly. The results really measure both the
+# scheduler and GC. Pause time measurements tend to not fit well with
+# current benchmark suites. As far as we know, none of the current
+# commercial Java implementations seriously attempt to minimize GC pause
+# times.
+#
+# Known deficiencies:
+# - No way to check on memory use
+# - No cyclic data structures
+# - No attempt to measure variation with object size
+# - Results are sensitive to locking cost, but we don't
+#   check for proper locking
+#
+
+import
+  strutils, times
+
+type
+  PNode = ref TNode
+  TNode {.final, acyclic.} = object
+    left, right: PNode
+    i, j: int
+
+proc newNode(L, r: sink PNode): PNode =
+  new(result)
+  result.left = L
+  result.right = r
+
+const
+  kStretchTreeDepth = 18 # about 16Mb
+  kLongLivedTreeDepth = 16  # about 4Mb
+  kArraySize = 500000  # about 4Mb
+  kMinTreeDepth = 4
+  kMaxTreeDepth = 16
+
+when not declared(withScratchRegion):
+  template withScratchRegion(body: untyped) = body
+
+# Nodes used by a tree of a given size
+proc treeSize(i: int): int = return ((1 shl (i + 1)) - 1)
+
+# Number of iterations to use for a given tree depth
+proc numIters(i: int): int =
+  return 2 * treeSize(kStretchTreeDepth) div treeSize(i)
+
+# Build tree top down, assigning to older objects.
+proc populate(iDepth: int, thisNode: PNode) =
+  if iDepth <= 0:
+    return
+  else:
+    new(thisNode.left)
+    new(thisNode.right)
+    populate(iDepth-1, thisNode.left)
+    populate(iDepth-1, thisNode.right)
+
+# Build tree bottom-up
+proc makeTree(iDepth: int): PNode =
+  if iDepth <= 0:
+    new(result)
+  else:
+    return newNode(makeTree(iDepth-1), makeTree(iDepth-1))
+
+proc printDiagnostics() =
+  echo("Total memory available: " & formatSize(getTotalMem()) & " bytes")
+  echo("Free memory: " & formatSize(getFreeMem()) & " bytes")
+
+proc timeConstruction(depth: int) =
+  var
+    root, tempTree: PNode
+    iNumIters: int
+
+  iNumIters = numIters(depth)
+
+  echo("Creating " & $iNumIters & " trees of depth " & $depth)
+  var t = epochTime()
+  for i in 0..iNumIters-1:
+    new(tempTree)
+    populate(depth, tempTree)
+    tempTree = nil
+  echo("\tTop down construction took " & $(epochTime() - t) & "msecs")
+  t = epochTime()
+  for i in 0..iNumIters-1:
+    tempTree = makeTree(depth)
+    tempTree = nil
+  echo("\tBottom up construction took " & $(epochTime() - t) & "msecs")
+
+type
+  tMyArray = seq[float]
+
+proc main() =
+  var
+    root, longLivedTree, tempTree: PNode
+    myarray: tMyArray
+
+  echo("Garbage Collector Test")
+  echo(" Stretching memory with a binary tree of depth " & $kStretchTreeDepth)
+  printDiagnostics()
+  var t = epochTime()
+
+  # Stretch the memory space quickly
+  withScratchRegion:
+    tempTree = makeTree(kStretchTreeDepth)
+    tempTree = nil
+
+  # Create a long lived object
+  echo(" Creating a long-lived binary tree of depth " &
+        $kLongLivedTreeDepth)
+  new(longLivedTree)
+  populate(kLongLivedTreeDepth, longLivedTree)
+
+  # Create long-lived array, filling half of it
+  echo(" Creating a long-lived array of " & $kArraySize & " doubles")
+  withScratchRegion:
+    newSeq(myarray, kArraySize)
+    for i in 0..kArraySize div 2 - 1:
+      myarray[i] = 1.0 / toFloat(i)
+
+    printDiagnostics()
+
+    var d = kMinTreeDepth
+    while d <= kMaxTreeDepth:
+      withScratchRegion:
+        timeConstruction(d)
+      inc(d, 2)
+
+    if longLivedTree == nil or myarray[1000] != 1.0/1000.0:
+      echo("Failed")
+      # fake reference to LongLivedTree
+      # and array to keep them from being optimized away
+
+  var elapsed = epochTime() - t
+  printDiagnostics()
+  echo("Completed in " & $elapsed & "s. Success!")
+  when declared(getMaxMem):
+    echo "Max memory ", formatSize getMaxMem()
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+when defined(gcDestructors):
+  let mem = getOccupiedMem()
+main()
+when defined(gcDestructors):
+  doAssert getOccupiedMem() == mem
diff --git a/tests/gc/gcemscripten.nim b/tests/gc/gcemscripten.nim
new file mode 100644
index 000000000..cc12b230f
--- /dev/null
+++ b/tests/gc/gcemscripten.nim
@@ -0,0 +1,59 @@
+discard """
+  outputsub: "77\n77"
+"""
+
+## Check how GC/Alloc works in Emscripten
+import strutils
+
+type
+  X = ref XObj
+  XObj = object
+    name: string
+    value: int
+when defined(allow_print):
+  const print = true
+else:
+  const print = false
+
+proc myResult3*(i:int): X {.exportc.} =
+  if print: echo "3"
+  new(result)
+  if print: echo "3-2"
+  result.value = i
+
+proc myResult5*(i:int, x:X):X {.exportc.} =
+  if print: echo "5"
+  system.GC_fullCollect()
+  new(result)
+  if print: echo "5-2"
+  result.value = i
+  x.value = i+1
+  if result.value == x.value:
+    echo "This should not happen. Just allocated variable points to parameter"
+
+proc myResult2*(val: string, i: int): X {.exportc.} =
+  if print: echo "2-1"
+  result = myResult3(i)
+  if print: echo "2-2"
+  system.GC_fullCollect()
+  if print: echo "2-3"
+  var t = new(X)
+  if print: echo "2-4"
+  result.name = val
+  if t.name == "qwe":
+    echo "This should not happen. Variable is GC collected and new one on same place are allocated."
+  if print: echo "2-5"
+
+proc myResult4*(val: string, i: int): X {.exportc.} =
+  if print: echo "4-1"
+  result = myResult5(i, X())
+  if print: echo "4-2"
+
+var x = myResult2("qwe", 77)
+echo intToStr(x.value)
+
+var x2 = myResult4("qwe", 77)
+echo intToStr(x2.value)
+
+
+
diff --git a/tests/gc/gcleak.nim b/tests/gc/gcleak.nim
new file mode 100644
index 000000000..0bf993968
--- /dev/null
+++ b/tests/gc/gcleak.nim
@@ -0,0 +1,29 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TTestObj = object of RootObj
+    x: string
+
+proc makeObj(): TTestObj =
+  result.x = "Hello"
+
+const numIter =
+  # see tests/gc/gcleak2.nim
+  when defined(boehmgc):
+    1_000
+  elif defined(gcMarkAndSweep): 10_000
+  else: 100_000
+
+for i in 1 .. numIter:
+  when defined(gcMarkAndSweep) or defined(boehmgc):
+    GC_fullcollect()
+  var obj = makeObj()
+  if getOccupiedMem() > 300_000: quit("still a leak!")
+#  echo GC_getstatistics()
+
+echo "no leak: ", getOccupiedMem()
diff --git a/tests/gc/gcleak2.nim b/tests/gc/gcleak2.nim
new file mode 100644
index 000000000..bc943dbe7
--- /dev/null
+++ b/tests/gc/gcleak2.nim
@@ -0,0 +1,38 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TTestObj = object of RootObj
+    x: string
+    s: seq[int]
+
+proc makeObj(): TTestObj =
+  result.x = "Hello"
+  result.s = @[1,2,3]
+
+const numIter =
+  when defined(boehmgc):
+    # super slow because GC_fullcollect() at each iteration; especially
+    # on OSX 10.15 where it takes ~170s
+    # `getOccupiedMem` should be constant after each iteration for i >= 3
+    1_000
+  elif defined(gcMarkAndSweep):
+    # likewise, somewhat slow, 1_000_000 would run for 8s
+    # and same remark as above
+    100_000
+  else: 1_000_000
+
+proc inProc() =
+  for i in 1 .. numIter:
+    when defined(gcMarkAndSweep) or defined(boehmgc):
+      GC_fullcollect()
+    var obj: TTestObj
+    obj = makeObj()
+    if getOccupiedMem() > 300_000: quit("still a leak!")
+
+inProc()
+echo "no leak: ", getOccupiedMem()
diff --git a/tests/gc/gcleak3.nim b/tests/gc/gcleak3.nim
new file mode 100644
index 000000000..5e146d69f
--- /dev/null
+++ b/tests/gc/gcleak3.nim
@@ -0,0 +1,26 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+when defined(GC_setMaxPause):
+  GC_setMaxPause 2_000
+
+type
+  TSomething = object
+    s: string
+    s1: string
+var s: seq[TSomething] = @[]
+for i in 0..1024:
+  var obj: TSomething
+  obj.s = "blah"
+  obj.s1 = "asd"
+  s.add(obj)
+
+proc limit*[t](a: var seq[t]) =
+  while s.len > 0:
+    if getOccupiedMem() > 3000_000: quit("still a leak!")
+    s.delete(0)
+
+s.limit()
+echo "no leak: ", getOccupiedMem()
+
diff --git a/tests/gc/gcleak4.nim b/tests/gc/gcleak4.nim
new file mode 100644
index 000000000..a72db67b7
--- /dev/null
+++ b/tests/gc/gcleak4.nim
@@ -0,0 +1,46 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  TExpr {.inheritable.} = object ## abstract base class for an expression
+  PLiteral = ref TLiteral
+  TLiteral = object of TExpr
+    x: int
+    op1: string
+  TPlusExpr = object of TExpr
+    a, b: ref TExpr
+    op2: string
+
+method eval(e: ref TExpr): int {.base.} =
+  # override this base method
+  quit "to override!"
+
+method eval(e: ref TLiteral): int = return e.x
+
+method eval(e: ref TPlusExpr): int =
+  # watch out: relies on dynamic binding
+  return eval(e.a) + eval(e.b)
+
+proc newLit(x: int): ref TLiteral =
+  new(result)
+  result.x = x
+  result.op1 = $getOccupiedMem()
+
+proc newPlus(a, b: sink(ref TExpr)): ref TPlusExpr =
+  new(result)
+  result.a = a
+  result.b = b
+  result.op2 = $getOccupiedMem()
+
+const Limit = when compileOption("gc", "markAndSweep") or compileOption("gc", "boehm"): 5*1024*1024 else: 500_000
+
+for i in 0..50_000:
+  var s: array[0..11, ref TExpr]
+  for j in 0..high(s):
+    s[j] = newPlus(newPlus(newLit(j), newLit(2)), newLit(4))
+    if eval(s[j]) != j+6:
+      quit "error: wrong result"
+  if getOccupiedMem() > Limit: quit("still a leak!")
+
+echo "no leak: ", getOccupiedMem()
diff --git a/tests/gc/gcleak5.nim b/tests/gc/gcleak5.nim
new file mode 100644
index 000000000..f1913831b
--- /dev/null
+++ b/tests/gc/gcleak5.nim
@@ -0,0 +1,25 @@
+discard """
+  output: "success"
+"""
+
+import os, times
+
+proc main =
+  var i = 0
+  for ii in 0..50_000:
+    #while true:
+    var t = getTime()
+    var g = t.utc()
+    #echo isOnStack(addr g)
+
+    if i mod 100 == 0:
+      let om = getOccupiedMem()
+      #echo "memory: ", om
+      if om > 100_000: quit "leak"
+
+    inc(i)
+    sleep(1)
+
+  echo "success"
+
+main()
diff --git a/tests/gctest.nim b/tests/gc/gctest.nim
index f58dc3217..78b78934c 100755..100644
--- a/tests/gctest.nim
+++ b/tests/gc/gctest.nim
@@ -1,5 +1,8 @@
-# Test the garbage collector:
-# This file is not in the test suite because it takes too much time.
+discard """
+  outputsub: "finished"
+"""
+
+# Test the garbage collector.
 
 import
   strutils
@@ -19,7 +22,7 @@ type
     data: string
     sons: seq[TBNode] # directly embedded!
     t: TTable
-    
+
   TCaseKind = enum nkStr, nkWhole, nkList
   PCaseNode = ref TCaseNode
   TCaseNode {.final.} = object
@@ -28,44 +31,37 @@ type
     of nkList: sons: seq[PCaseNode]
     else: unused: seq[string]
 
-  TIdObj* = object of TObject

-    id*: int                  # unique id; use this for comparisons and not the pointers

-  

-  PIdObj* = ref TIdObj

-  PIdent* = ref TIdent

-  TIdent*{.acyclic.} = object of TIdObj

-    s*: string

-    next*: PIdent             # for hash-table chaining

-    h*: int                   # hash value of s

+  TIdObj* = object of RootObj
+    id*: int  # unique id; use this for comparisons and not the pointers
+
+  PIdObj* = ref TIdObj
+  PIdent* = ref TIdent
+  TIdent*{.acyclic.} = object of TIdObj
+    s*: string
+    next*: PIdent             # for hash-table chaining
+    h*: int                   # hash value of s
 
 var
   flip: int
 
 proc newCaseNode(data: string): PCaseNode =
-  new(result)
   if flip == 0:
-    result.kind = nkStr
-    result.data = data
+    result = PCaseNode(kind: nkStr, data: data)
   else:
-    result.kind = nkWhole
-    result.unused = @["", "abc", "abdc"]
+    result = PCaseNode(kind: nkWhole, unused: @["", "abc", "abdc"])
   flip = 1 - flip
-  
+
 proc newCaseNode(a, b: PCaseNode): PCaseNode =
-  new(result)
-  result.kind = nkList
-  result.sons = @[a, b]
-  
+  result = PCaseNode(kind: nkList, sons: @[a, b])
+
 proc caseTree(lvl: int = 0): PCaseNode =
   if lvl == 3: result = newCaseNode("data item")
   else: result = newCaseNode(caseTree(lvl+1), caseTree(lvl+1))
 
-proc finalizeBNode(n: TBNode) = writeln(stdout, n.data)
 proc finalizeNode(n: PNode) =
   assert(n != nil)
   write(stdout, "finalizing: ")
-  if isNil(n.data): writeln(stdout, "nil!")
-  else: writeln(stdout, n.data)
+  writeLine(stdout, "not nil")
 
 var
   id: int = 1
@@ -79,7 +75,7 @@ proc buildTree(depth = 1): PNode =
   inc(id)
 
 proc returnTree(): PNode =
-  writeln(stdout, "creating id: " & $id)
+  writeLine(stdout, "creating id: " & $id)
   new(result, finalizeNode)
   result.data = $id
   new(result.le, finalizeNode)
@@ -89,26 +85,26 @@ proc returnTree(): PNode =
   inc(id)
 
   # now create a cycle:
-  writeln(stdout, "creating id (cyclic): " & $id)
+  writeLine(stdout, "creating id (cyclic): " & $id)
   var cycle: PNode
   new(cycle, finalizeNode)
   cycle.data = $id
   cycle.le = cycle
   cycle.ri = cycle
   inc(id)
-  #writeln(stdout, "refcount: " & $refcount(cycle))
-  #writeln(stdout, "refcount le: " & $refcount(cycle.le))
-  #writeln(stdout, "refcount ri: " & $refcount(cycle.ri))
+  #writeLine(stdout, "refcount: " & $refcount(cycle))
+  #writeLine(stdout, "refcount le: " & $refcount(cycle.le))
+  #writeLine(stdout, "refcount ri: " & $refcount(cycle.ri))
 
 proc printTree(t: PNode) =
   if t == nil: return
-  writeln(stdout, "printing")
-  writeln(stdout, t.data)
+  writeLine(stdout, "printing")
+  writeLine(stdout, t.data)
   printTree(t.le)
   printTree(t.ri)
 
 proc unsureNew(result: var PNode) =
-  writeln(stdout, "creating unsure id: " & $id)
+  writeLine(stdout, "creating unsure id: " & $id)
   new(result, finalizeNode)
   result.data = $id
   new(result.le, finalizeNode)
@@ -144,9 +140,9 @@ proc buildBTree(father: var TBNode) =
     father.t.data = @["ha", "lets", "stress", "it"]
   setSons(father)
 
-proc getIdent(identifier: cstring, length: int, h: int): PIdent = 
-  new(result)

-  result.h = h

+proc getIdent(identifier: cstring, length: int, h: int): PIdent =
+  new(result)
+  result.h = h
   result.s = newString(length)
 
 proc main() =
@@ -154,7 +150,7 @@ proc main() =
   discard getIdent("hall", 4, 0)
   discard getIdent("echo", 4, 0)
   discard getIdent("huch", 4, 0)
-  
+
   var
     father: TBNode
   for i in 1..1_00:
@@ -173,25 +169,42 @@ proc main() =
   var s: seq[string] = @[]
   for i in 1..100:
     add s, "hohoho" # test reallocation
-  writeln(stdout, s[89])
+  writeLine(stdout, s[89])
   write(stdout, "done!\n")
 
 var
-    father: TBNode
-    s: string
-s = ""
-s = ""
-writeln(stdout, repr(caseTree()))
-father.t.data = @["ha", "lets", "stress", "it"]
-father.t.data = @["ha", "lets", "stress", "it"]
-var t = buildTree()
-write(stdout, repr(t^))
-buildBTree(father)
-write(stdout, repr(father))
-
-write(stdout, "starting main...\n")
-main()
-write(stdout, "finished\n")
-GC_fullCollect()
-GC_fullCollect()
-writeln(stdout, GC_getStatistics())
+  father {.threadvar.}: TBNode
+  s {.threadvar.}: string
+
+  fatherAsGlobal: TBNode
+
+proc start =
+  s = ""
+  s = ""
+  writeLine(stdout, repr(caseTree()))
+  father.t.data = @["ha", "lets", "stress", "it"]
+  father.t.data = @["ha", "lets", "stress", "it"]
+  var t = buildTree()
+  write(stdout, repr(t[]))
+  buildBTree(father)
+  write(stdout, repr(father))
+
+  write(stdout, "starting main...\n")
+  main()
+
+  GC_fullCollect()
+  # the M&S GC fails with this call and it's unclear why. Definitely something
+  # we need to fix!
+  #GC_fullCollect()
+  writeLine(stdout, GC_getStatistics())
+  write(stdout, "finished\n")
+
+fatherAsGlobal.t.data = @["ha", "lets", "stress", "it"]
+var tg = buildTree()
+buildBTree(fatherAsGlobal)
+
+var thr: array[8, Thread[void]]
+for i in low(thr)..high(thr):
+  createThread(thr[i], start)
+joinThreads(thr)
+start()
diff --git a/tests/gc/gctest.nim.cfg b/tests/gc/gctest.nim.cfg
new file mode 100644
index 000000000..aed303eef
--- /dev/null
+++ b/tests/gc/gctest.nim.cfg
@@ -0,0 +1 @@
+--threads:on
diff --git a/tests/gc/growobjcrash.nim b/tests/gc/growobjcrash.nim
new file mode 100644
index 000000000..ff1aa7e98
--- /dev/null
+++ b/tests/gc/growobjcrash.nim
@@ -0,0 +1,24 @@
+import std/[cgi, strtabs]
+
+proc handleRequest(query: string): StringTableRef =
+  iterator foo(): StringTableRef {.closure.} =
+    var params = {:}.newStringTable()
+    for key, val in cgi.decodeData(query):
+      params[key] = val
+    yield params
+
+  let x = foo
+  result = x()
+
+const Limit = 5*1024*1024
+
+proc main =
+  var counter = 0
+  for i in 0 .. 10_000:
+    for k, v in handleRequest("nick=Elina2&type=activate"):
+      inc counter
+      if counter mod 100 == 0:
+        if getOccupiedMem() > Limit:
+          quit "but now a leak"
+
+main()
diff --git a/tests/gc/panicoverride.nim b/tests/gc/panicoverride.nim
new file mode 100644
index 000000000..0f28b0b72
--- /dev/null
+++ b/tests/gc/panicoverride.nim
@@ -0,0 +1,14 @@
+
+proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
+proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
+
+{.push stack_trace: off, profiler:off.}
+
+proc rawoutput(s: string) =
+  printf("%s\n", s)
+
+proc panic(s: string) {.noreturn.} =
+  rawoutput(s)
+  exit(1)
+
+{.pop.}
\ No newline at end of file
diff --git a/tests/gc/refarrayleak.nim b/tests/gc/refarrayleak.nim
new file mode 100644
index 000000000..57b489721
--- /dev/null
+++ b/tests/gc/refarrayleak.nim
@@ -0,0 +1,39 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  TNode = object
+    data: array[0..300, char]
+
+  PNode = ref TNode
+
+  TNodeArray = array[0..10, PNode]
+
+  TArrayHolder = object
+    sons: TNodeArray
+
+proc nullify(a: var TNodeArray) =
+  for i in 0..high(a):
+    a[i] = nil
+
+proc newArrayHolder: ref TArrayHolder =
+  new result
+
+  for i in 0..high(result.sons):
+    new result.sons[i]
+
+  nullify result.sons
+
+proc loop =
+  for i in 0..10000:
+    discard newArrayHolder()
+
+  if getOccupiedMem() > 300_000:
+    echo "still a leak! ", getOccupiedMem()
+    quit 1
+  else:
+    echo "no leak: ", getOccupiedMem()
+
+loop()
+
diff --git a/tests/gc/stackrefleak.nim b/tests/gc/stackrefleak.nim
new file mode 100644
index 000000000..7f3fbff43
--- /dev/null
+++ b/tests/gc/stackrefleak.nim
@@ -0,0 +1,32 @@
+discard """
+  outputsub: "no leak: "
+"""
+
+type
+  Cyclic = object
+    sibling: PCyclic
+    data: array[0..200, char]
+
+  PCyclic = ref Cyclic
+
+proc makePair: PCyclic =
+  new(result)
+  new(result.sibling)
+  when not defined(gcDestructors):
+    result.sibling.sibling = result
+
+proc loop =
+  for i in 0..10000:
+    var x = makePair()
+    GC_fullCollect()
+    x = nil
+    GC_fullCollect()
+
+  if getOccupiedMem() > 300_000:
+    echo "still a leak! ", getOccupiedMem()
+    quit(1)
+  else:
+    echo "no leak: ", getOccupiedMem()
+
+loop()
+
diff --git a/tests/gc/tdisable_orc.nim b/tests/gc/tdisable_orc.nim
new file mode 100644
index 000000000..b5f161c79
--- /dev/null
+++ b/tests/gc/tdisable_orc.nim
@@ -0,0 +1,9 @@
+discard """
+  joinable: false
+"""
+
+import std/asyncdispatch
+
+# bug #22256
+GC_disableMarkAndSweep()
+waitFor sleepAsync(1000)
diff --git a/tests/gc/thavlak.nim b/tests/gc/thavlak.nim
new file mode 100644
index 000000000..cfd860e25
--- /dev/null
+++ b/tests/gc/thavlak.nim
@@ -0,0 +1,441 @@
+discard """
+  output: '''Welcome to LoopTesterApp, Nim edition
+Constructing Simple CFG...
+5000 dummy loops
+Constructing CFG...
+Performing Loop Recognition
+1 Iteration
+Another 3 iterations...
+...
+Found 1 loops (including artificial root node) (3)'''
+"""
+
+# bug #3184
+
+import tables, sets
+
+when not declared(withScratchRegion):
+  template withScratchRegion(body: untyped) = body
+
+type
+  BasicBlock = ref object
+    inEdges: seq[BasicBlock]
+    outEdges: seq[BasicBlock]
+    name: int
+
+proc newBasicBlock(name: int): BasicBlock =
+  result = BasicBlock(
+    inEdges: newSeq[BasicBlock](),
+    outEdges: newSeq[BasicBlock](),
+    name: name
+  )
+
+proc hash(x: BasicBlock): int {.inline.} =
+  result = x.name
+
+type
+  BasicBlockEdge = object
+    fr: BasicBlock
+    to: BasicBlock
+
+  Cfg = object
+    basicBlockMap: Table[int, BasicBlock]
+    edgeList: seq[BasicBlockEdge]
+    startNode: BasicBlock
+
+proc newCfg(): Cfg =
+  result = Cfg(
+    basicBlockMap: initTable[int, BasicBlock](),
+    edgeList: newSeq[BasicBlockEdge](),
+    startNode: nil)
+
+proc createNode(self: var Cfg, name: int): BasicBlock =
+  result = self.basicBlockMap.getOrDefault(name)
+  if result == nil:
+    result = newBasicBlock(name)
+    self.basicBlockMap.add name, result
+
+  if self.startNode == nil:
+    self.startNode = result
+
+proc newBasicBlockEdge(cfg: var Cfg, fromName, toName: int) =
+  var result = BasicBlockEdge(
+    fr: cfg.createNode(fromName),
+    to: cfg.createNode(toName)
+  )
+  result.fr.outEdges.add(result.to)
+  result.to.inEdges.add(result.fr)
+  cfg.edgeList.add(result)
+
+type
+  SimpleLoop = ref object
+    basicBlocks: seq[BasicBlock] # TODO: set here
+    children: seq[SimpleLoop] # TODO: set here
+    parent: SimpleLoop
+    header: BasicBlock
+    isRoot, isReducible: bool
+    counter, nestingLevel, depthLevel: int
+
+proc setParent(self: SimpleLoop, parent: SimpleLoop) =
+  self.parent = parent
+  self.parent.children.add self
+
+proc setHeader(self: SimpleLoop, bb: BasicBlock) =
+  self.basicBlocks.add(bb)
+  self.header = bb
+
+proc setNestingLevel(self: SimpleLoop, level: int) =
+  self.nestingLevel = level
+  if level == 0: self.isRoot = true
+
+var loopCounter: int = 0
+
+type
+  Lsg = object
+    loops: seq[SimpleLoop]
+    root: SimpleLoop
+
+proc createNewLoop(self: var Lsg): SimpleLoop =
+  result = SimpleLoop(
+    basicBlocks: newSeq[BasicBlock](),
+    children: newSeq[SimpleLoop](),
+    isReducible: true)
+  loopCounter += 1
+  result.counter = loopCounter
+
+proc addLoop(self: var Lsg, l: SimpleLoop) =
+  self.loops.add l
+
+proc newLsg(): Lsg =
+  result = Lsg(loops: newSeq[SimpleLoop](),
+    root: result.createNewLoop())
+  result.root.setNestingLevel(0)
+  result.addLoop(result.root)
+
+type
+  UnionFindNode = ref object
+    parent {.cursor.}: UnionFindNode
+    bb: BasicBlock
+    l: SimpleLoop
+    dfsNumber: int
+
+proc initNode(self: UnionFindNode, bb: BasicBlock, dfsNumber: int) =
+  self.parent = self
+  self.bb = bb
+  self.dfsNumber = dfsNumber
+
+proc findSet(self: UnionFindNode): UnionFindNode =
+  var nodeList = newSeq[UnionFindNode]()
+  var it {.cursor.} = self
+
+  while it != it.parent:
+    var parent {.cursor.} = it.parent
+    if parent != parent.parent: nodeList.add it
+    it = parent
+
+  for iter in nodeList: iter.parent = it.parent
+  result = it
+
+proc union(self: UnionFindNode, unionFindNode: UnionFindNode) =
+  self.parent = unionFindNode
+
+
+const
+  BB_NONHEADER = 1 # a regular BB
+  BB_REDUCIBLE = 2 # reducible loop
+  BB_SELF = 3 # single BB loop
+  BB_IRREDUCIBLE = 4 # irreducible loop
+  BB_DEAD = 5 # a dead BB
+
+  # # Marker for uninitialized nodes.
+  UNVISITED = -1
+
+  # # Safeguard against pathologic algorithm behavior.
+  MAXNONBACKPREDS = (32 * 1024)
+
+type
+  HavlakLoopFinder = object
+    cfg: Cfg
+    lsg: Lsg
+
+proc newHavlakLoopFinder(cfg: Cfg, lsg: sink Lsg): HavlakLoopFinder =
+  result = HavlakLoopFinder(cfg: cfg, lsg: lsg)
+
+proc isAncestor(w, v: int, last: seq[int]): bool =
+  w <= v and v <= last[w]
+
+proc dfs(currentNode: BasicBlock, nodes: var seq[UnionFindNode],
+         number: var Table[BasicBlock, int],
+         last: var seq[int], current: int) =
+  var stack = @[(currentNode, current)]
+  while stack.len > 0:
+    let (currentNode, current) = stack.pop()
+    nodes[current].initNode(currentNode, current)
+    number[currentNode] = current
+
+    for target in currentNode.outEdges:
+      if number[target] == UNVISITED:
+        stack.add((target, current+1))
+        #result = dfs(target, nodes, number, last, result + 1)
+  last[number[currentNode]] = current
+
+proc findLoops(self: var HavlakLoopFinder): int =
+  var startNode = self.cfg.startNode
+  if startNode == nil: return 0
+  var size = self.cfg.basicBlockMap.len
+
+  var nonBackPreds = newSeq[HashSet[int]]()
+  var backPreds = newSeq[seq[int]]()
+  var number = initTable[BasicBlock, int]()
+  var header = newSeq[int](size)
+  var types = newSeq[int](size)
+  var last = newSeq[int](size)
+  var nodes = newSeq[UnionFindNode]()
+
+  for i in 1..size:
+    nonBackPreds.add initHashSet[int](1)
+    backPreds.add newSeq[int]()
+    nodes.add(UnionFindNode())
+
+  # Step a:
+  #   - initialize all nodes as unvisited.
+  #   - depth-first traversal and numbering.
+  #   - unreached BB's are marked as dead.
+  #
+  for v in self.cfg.basicBlockMap.values: number[v] = UNVISITED
+  dfs(startNode, nodes, number, last, 0)
+
+  # Step b:
+  #   - iterate over all nodes.
+  #
+  #   A backedge comes from a descendant in the DFS tree, and non-backedges
+  #   from non-descendants (following Tarjan).
+  #
+  #   - check incoming edges 'v' and add them to either
+  #     - the list of backedges (backPreds) or
+  #     - the list of non-backedges (nonBackPreds)
+  #
+  for w in 0 ..< size:
+    header[w] = 0
+    types[w]  = BB_NONHEADER
+
+    var nodeW = nodes[w].bb
+    if nodeW != nil:
+      for nodeV in nodeW.inEdges:
+        var v = number[nodeV]
+        if v != UNVISITED:
+          if isAncestor(w, v, last):
+            backPreds[w].add v
+          else:
+            nonBackPreds[w].incl v
+    else:
+      types[w] = BB_DEAD
+
+  # Start node is root of all other loops.
+  header[0] = 0
+
+  # Step c:
+  #
+  # The outer loop, unchanged from Tarjan. It does nothing except
+  # for those nodes which are the destinations of backedges.
+  # For a header node w, we chase backward from the sources of the
+  # backedges adding nodes to the set P, representing the body of
+  # the loop headed by w.
+  #
+  # By running through the nodes in reverse of the DFST preorder,
+  # we ensure that inner loop headers will be processed before the
+  # headers for surrounding loops.
+
+  for w in countdown(size - 1, 0):
+    # this is 'P' in Havlak's paper
+    var nodePool = newSeq[UnionFindNode]()
+
+    var nodeW = nodes[w].bb
+    if nodeW != nil: # dead BB
+      # Step d:
+      for v in backPreds[w]:
+        if v != w:
+          nodePool.add nodes[v].findSet
+        else:
+          types[w] = BB_SELF
+
+      # Copy nodePool to workList.
+      #
+      var workList = newSeq[UnionFindNode]()
+      for x in nodePool: workList.add x
+
+      if nodePool.len != 0: types[w] = BB_REDUCIBLE
+
+      # work the list...
+      #
+      while workList.len > 0:
+        let x = workList[0]
+        workList.del(0)
+
+        # Step e:
+        #
+        # Step e represents the main difference from Tarjan's method.
+        # Chasing upwards from the sources of a node w's backedges. If
+        # there is a node y' that is not a descendant of w, w is marked
+        # the header of an irreducible loop, there is another entry
+        # into this loop that avoids w.
+        #
+
+        # The algorithm has degenerated. Break and
+        # return in this case.
+        #
+        var nonBackSize = nonBackPreds[x.dfsNumber].len
+        if nonBackSize > MAXNONBACKPREDS: return 0
+
+        for iter in nonBackPreds[x.dfsNumber]:
+          var y = nodes[iter]
+          var ydash = y.findSet
+
+          if not isAncestor(w, ydash.dfsNumber, last):
+            types[w] = BB_IRREDUCIBLE
+            nonBackPreds[w].incl ydash.dfsNumber
+          else:
+            if ydash.dfsNumber != w and not nodePool.contains(ydash):
+              workList.add ydash
+              nodePool.add ydash
+
+      # Collapse/Unionize nodes in a SCC to a single node
+      # For every SCC found, create a loop descriptor and link it in.
+      #
+      if nodePool.len > 0 or types[w] == BB_SELF:
+        var l = self.lsg.createNewLoop
+
+        l.setHeader(nodeW)
+        l.isReducible = types[w] != BB_IRREDUCIBLE
+
+        # At this point, one can set attributes to the loop, such as:
+        #
+        # the bottom node:
+        #    iter  = backPreds(w).begin();
+        #    loop bottom is: nodes(iter).node;
+        #
+        # the number of backedges:
+        #    backPreds(w).size()
+        #
+        # whether this loop is reducible:
+        #    types(w) != BB_IRREDUCIBLE
+        #
+        nodes[w].l = l
+
+        for node in nodePool:
+          # Add nodes to loop descriptor.
+          header[node.dfsNumber] = w
+          node.union(nodes[w])
+
+          # Nested loops are not added, but linked together.
+          var nodeL = node.l
+          if nodeL != nil:
+            nodeL.setParent(l)
+          else:
+            l.basicBlocks.add node.bb
+
+        self.lsg.addLoop(l)
+
+  result = self.lsg.loops.len
+
+
+type
+  LoopTesterApp = object
+    cfg: Cfg
+    lsg: Lsg
+
+proc newLoopTesterApp(): LoopTesterApp =
+  result.cfg = newCfg()
+  result.lsg = newLsg()
+
+proc buildDiamond(self: var LoopTesterApp, start: int): int =
+  newBasicBlockEdge(self.cfg, start, start + 1)
+  newBasicBlockEdge(self.cfg, start, start + 2)
+  newBasicBlockEdge(self.cfg, start + 1, start + 3)
+  newBasicBlockEdge(self.cfg, start + 2, start + 3)
+  result = start + 3
+
+proc buildConnect(self: var LoopTesterApp, start1, end1: int) =
+  newBasicBlockEdge(self.cfg, start1, end1)
+
+proc buildStraight(self: var LoopTesterApp, start, n: int): int =
+  for i in 0..n-1:
+    self.buildConnect(start + i, start + i + 1)
+  result = start + n
+
+proc buildBaseLoop(self: var LoopTesterApp, from1: int): int =
+  let header = self.buildStraight(from1, 1)
+  let diamond1 = self.buildDiamond(header)
+  let d11 = self.buildStraight(diamond1, 1)
+  let diamond2 = self.buildDiamond(d11)
+  let footer = self.buildStraight(diamond2, 1)
+
+  self.buildConnect(diamond2, d11)
+  self.buildConnect(diamond1, header)
+  self.buildConnect(footer, from1)
+  result = self.buildStraight(footer, 1)
+
+proc run(self: var LoopTesterApp) =
+  echo "Welcome to LoopTesterApp, Nim edition"
+  echo "Constructing Simple CFG..."
+
+  discard self.cfg.createNode(0)
+  discard self.buildBaseLoop(0)
+  discard self.cfg.createNode(1)
+  self.buildConnect(0, 2)
+
+  echo "5000 dummy loops"
+
+  for i in 1..5000:
+    withScratchRegion:
+      var h = newHavlakLoopFinder(self.cfg, newLsg())
+      discard h.findLoops
+
+  echo "Constructing CFG..."
+  var n = 2
+
+  when true: # not defined(gcOrc):
+    # currently cycle detection is so slow that we disable this part
+    for parlooptrees in 1..10:
+      discard self.cfg.createNode(n + 1)
+      self.buildConnect(2, n + 1)
+      n += 1
+      for i in 1..100:
+        var top = n
+        n = self.buildStraight(n, 1)
+        for j in 1..25: n = self.buildBaseLoop(n)
+        var bottom = self.buildStraight(n, 1)
+        self.buildConnect n, top
+        n = bottom
+      self.buildConnect(n, 1)
+
+  echo "Performing Loop Recognition\n1 Iteration"
+
+  var h = newHavlakLoopFinder(self.cfg, newLsg())
+  var loops = h.findLoops
+
+  echo "Another 3 iterations..."
+
+  var sum = 0
+  for i in 1..3:
+    withScratchRegion:
+      write stdout, "."
+      flushFile(stdout)
+      var hlf = newHavlakLoopFinder(self.cfg, newLsg())
+      sum += hlf.findLoops
+      #echo getOccupiedMem()
+  echo "\nFound ", loops, " loops (including artificial root node) (", sum, ")"
+
+  when false:
+    echo("Total memory available: " & formatSize(getTotalMem()) & " bytes")
+    echo("Free memory: " & formatSize(getFreeMem()) & " bytes")
+
+proc main =
+  var l = newLoopTesterApp()
+  l.run
+
+let mem = getOccupiedMem()
+main()
+when defined(gcOrc):
+  GC_fullCollect()
+  doAssert getOccupiedMem() == mem
diff --git a/tests/gc/tlists.nim b/tests/gc/tlists.nim
new file mode 100644
index 000000000..959cc5f7c
--- /dev/null
+++ b/tests/gc/tlists.nim
@@ -0,0 +1,35 @@
+discard """
+    output: '''Success'''
+"""
+
+# bug #3793
+
+import os
+import math
+import lists
+import strutils
+
+proc mkleak() =
+    # allocate 1 MB via linked lists
+    let numberOfLists = 100
+    for i in countUp(1, numberOfLists):
+        var leakList = initDoublyLinkedList[string]()
+        let numberOfLeaks = 5000
+        for j in countUp(1, numberOfLeaks):
+            leakList.append(newString(200))
+
+proc mkManyLeaks() =
+    for i in 0..0:
+        when false: echo getOccupiedMem()
+        mkleak()
+        when false: echo getOccupiedMem()
+        # Force a full collection. This should free all of the
+        # lists and bring the memory usage down to a few MB's.
+        GC_fullCollect()
+        when false: echo getOccupiedMem()
+        if getOccupiedMem() > 8 * 200 * 5000 * 2:
+          echo GC_getStatistics()
+          quit "leaking"
+    echo "Success"
+
+mkManyLeaks()
diff --git a/tests/gc/trace_globals.nim b/tests/gc/trace_globals.nim
new file mode 100644
index 000000000..f62a15692
--- /dev/null
+++ b/tests/gc/trace_globals.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''
+10000000
+10000000
+10000000'''
+"""
+
+# bug #17085
+
+#[
+refs https://github.com/nim-lang/Nim/issues/17085#issuecomment-786466595
+with --gc:boehm, this warning sometimes gets generated:
+Warning: Repeated allocation of very large block (appr. size 14880768):
+May lead to memory leak and poor performance.
+nim CI now runs this test with `testWithoutBoehm` to avoid running it with --gc:boehm.
+]#
+
+proc init(): string =
+  for a in 0..<10000000:
+    result.add 'c'
+
+proc f() =
+  var a {.global.} = init()
+  var b {.global.} = init()
+  var c {.global.} = init()
+
+  echo a.len
+    # `echo` intentional according to
+    # https://github.com/nim-lang/Nim/pull/17469/files/0c9e94cb6b9ebca9da7cb19a063fba7aa409748e#r600016573
+  echo b.len
+  echo c.len
+
+f()
diff --git a/tests/gc/tregionleak.nim b/tests/gc/tregionleak.nim
new file mode 100644
index 000000000..277cfc987
--- /dev/null
+++ b/tests/gc/tregionleak.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: '''nim c --gc:regions $file'''
+  output: '''
+finalized
+finalized
+'''
+"""
+
+proc finish(o: RootRef) =
+  echo "finalized"
+
+withScratchRegion:
+  var test: RootRef
+  new(test, finish)
+
+var
+  mr: MemRegion
+  test: RootRef
+
+withRegion(mr):
+  new(test, finish)
+
+deallocAll(mr)
diff --git a/tests/gc/tstandalone.nim b/tests/gc/tstandalone.nim
new file mode 100644
index 000000000..41dad9ba4
--- /dev/null
+++ b/tests/gc/tstandalone.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "--os:standalone --gc:none"
+  exitcode: 1
+  output: "value out of range"
+"""
+
+type
+  rangeType = range[0..1]
+
+var
+  r: rangeType = 0
+  i = 2
+
+r = rangeType(i)
diff --git a/tests/gc/weakrefs.nim b/tests/gc/weakrefs.nim
new file mode 100644
index 000000000..81c048d74
--- /dev/null
+++ b/tests/gc/weakrefs.nim
@@ -0,0 +1,57 @@
+discard """
+  output: "true"
+"""
+
+import intsets
+
+type
+  TMyObject = object
+    id: int
+  StrongObject = ref TMyObject
+  WeakObject = object
+    id: int
+    data: ptr TMyObject
+
+var
+  gid: int # for id generation
+  valid = initIntSet()
+
+proc finalizer(x: StrongObject) =
+  valid.excl(x.id)
+
+when defined(gcDestructors):
+  proc `=destroy`(x: var TMyObject) =
+    valid.excl(x.id)
+
+proc create: StrongObject =
+  when defined(gcDestructors):
+    new(result)
+  else:
+    new(result, finalizer)
+  result.id = gid
+  valid.incl(gid)
+  inc gid
+
+proc register(s: StrongObject): WeakObject =
+  result.data = cast[ptr TMyObject](s)
+  result.id = s.id
+
+proc access(w: WeakObject): StrongObject =
+  ## returns nil if the object doesn't exist anymore
+  if valid.contains(w.id):
+    result = cast[StrongObject](w.data)
+
+proc main =
+  var s: seq[WeakObject]
+  newSeq(s, 10_000)
+  for i in 0 .. s.high:
+    s[i] = register(create())
+  # test that we have at least 80% unreachable weak objects by now:
+  when defined(gcMarkAndSweep):
+    GC_fullcollect()
+  var unreachable = 0
+  for i in 0 .. s.high:
+    if access(s[i]) == nil: inc unreachable
+  echo unreachable > 8_000
+
+main()
diff --git a/tests/gcbench.nim b/tests/gcbench.nim
deleted file mode 100755
index 72daad210..000000000
--- a/tests/gcbench.nim
+++ /dev/null
@@ -1,171 +0,0 @@
-# This is adapted from a benchmark written by John Ellis and Pete Kovac

-#   of Post Communications.

-#   It was modified by Hans Boehm of Silicon Graphics.

-#

-# 	This is no substitute for real applications. No actual application

-#	is likely to behave in exactly this way. However, this benchmark was

-#	designed to be more representative of real applications than other

-#	Java GC benchmarks of which we are aware.

-#	It attempts to model those properties of allocation requests that

-#	are important to current GC techniques.

-#	It is designed to be used either to obtain a single overall performance

-#	number, or to give a more detailed estimate of how collector

-#	performance varies with object lifetimes. It prints the time

-#	required to allocate and collect balanced binary trees of various

-#	sizes. Smaller trees result in shorter object lifetimes. Each cycle

-#	allocates roughly the same amount of memory.

-#	Two data structures are kept around during the entire process, so

-#	that the measured performance is representative of applications

-#	that maintain some live in-memory data. One of these is a tree

-#	containing many pointers. The other is a large array containing

-#	double precision floating point numbers. Both should be of comparable

-#	size.

-#

-#	The results are only really meaningful together with a specification

-#	of how much memory was used. It is possible to trade memory for

-#	better time performance. This benchmark should be run in a 32 MB

-#	heap, though we don't currently know how to enforce that uniformly.

-#

-#	Unlike the original Ellis and Kovac benchmark, we do not attempt

-# measure pause times. This facility should eventually be added back

-#	in. There are several reasons for omitting it for now.  The original

-#	implementation depended on assumptions about the thread scheduler

-#	that don't hold uniformly. The results really measure both the

-#	scheduler and GC. Pause time measurements tend to not fit well with

-#	current benchmark suites. As far as we know, none of the current

-#	commercial Java implementations seriously attempt to minimize GC pause

-#	times.

-#

-#	Known deficiencies:

-#		- No way to check on memory use

-#		- No cyclic data structures

-#		- No attempt to measure variation with object size

-#		- Results are sensitive to locking cost, but we dont

-#		  check for proper locking

-#

-

-import

-  strutils, times

-

-type

-  PNode = ref TNode

-  TNode {.final.} = object

-    left, right: PNode

-    i, j: int

-

-proc newNode(l, r: PNode): PNode =

-  new(result)

-  result.left = l

-  result.right = r

-

-const

-  kStretchTreeDepth = 18 # about 16Mb

-  kLongLivedTreeDepth = 16  # about 4Mb

-  kArraySize  = 500000  # about 4Mb

-  kMinTreeDepth = 4

-  kMaxTreeDepth = 16

-

-# Nodes used by a tree of a given size

-proc TreeSize(i: int): int = return ((1 shl (i + 1)) - 1)

-

-# Number of iterations to use for a given tree depth

-proc NumIters(i: int): int =

-  return 2 * TreeSize(kStretchTreeDepth) div TreeSize(i)

-

-# Build tree top down, assigning to older objects.

-proc Populate(iDepth: int, thisNode: PNode) =

-  if iDepth <= 0:

-    return

-  else:

-    new(thisNode.left)

-    new(thisNode.right)

-    Populate(iDepth-1, thisNode.left)

-    Populate(iDepth-1, thisNode.right)

-

-# Build tree bottom-up

-proc MakeTree(iDepth: int): PNode =

-  if iDepth <= 0:

-    new(result)

-  else:

-    return newNode(MakeTree(iDepth-1),

-                   MakeTree(iDepth-1))

-

-proc PrintDiagnostics() =

-  var

-    FreeMemory = getFreeMem()

-    TotalMemory = getTotalMem()

-

-  echo("Total memory available: " & $TotalMemory & " bytes")

-  echo("Free memory: " & $FreeMemory & " bytes")

-

-proc TimeConstruction(depth: int) =

-  var

-    root, tempTree: PNode

-    t: int

-    iNumIters: int

-

-  iNumIters = NumIters(depth)

-

-  echo("Creating " & $iNumIters & " trees of depth " & $depth)

-  t = getStartMilsecs()

-  for i in 0..iNumIters-1:

-    new(tempTree)

-    Populate(depth, tempTree)

-    tempTree = nil

-  echo("\tTop down construction took " &

-                     $(getStartMilsecs() - t) & "msecs")

-  t = getStartMilsecs()

-  for i in 0..iNumIters-1:

-    tempTree = MakeTree(depth)

-    tempTree = nil

-  echo("\tBottom up construction took " &

-                     $(getStartMilsecs() - t) & "msecs")

-

-type

-  tMyArray = seq[float]

-

-proc main() =

-  var

-    root, longLivedTree, tempTree: PNode

-    t: int

-    myarray: tMyArray

-

-  echo("Garbage Collector Test")

-  echo(" Stretching memory with a binary tree of depth " &

-       $kStretchTreeDepth)

-  PrintDiagnostics()

-  t = getStartMilsecs()

-

-  # Stretch the memory space quickly

-  tempTree = MakeTree(kStretchTreeDepth)

-  tempTree = nil

-

-  # Create a long lived object

-  echo(" Creating a long-lived binary tree of depth " &

-        $kLongLivedTreeDepth)

-  new(longLivedTree)

-  Populate(kLongLivedTreeDepth, longLivedTree)

-

-  # Create long-lived array, filling half of it

-  echo(" Creating a long-lived array of " & $kArraySize & " doubles")

-  newSeq(myarray, kArraySize)

-  for i in 0..kArraySize div 2 -1:

-    myarray[i] = 1.0 / toFloat(i)

-

-  PrintDiagnostics()

-

-  var d = kMinTreeDepth

-  while d <= kMaxTreeDepth:

-    TimeConstruction(d)

-    inc(d, 2)

-

-  if longLivedTree == nil or myarray[1000] != 1.0/1000.0:

-    echo("Failed")

-    # fake reference to LongLivedTree

-    # and array to keep them from being optimized away

-

-  var elapsed = getStartMilsecs() - t

-  PrintDiagnostics()

-  echo("Completed in " & $elapsed & "ms.")

-

-main()

diff --git a/tests/generics/m14509.nim b/tests/generics/m14509.nim
new file mode 100644
index 000000000..cabc4f308
--- /dev/null
+++ b/tests/generics/m14509.nim
@@ -0,0 +1,16 @@
+import macros
+
+type float32x4 = array[4, float32]
+type float32x8 = array[8, float32]
+
+{.experimental: "dynamicBindSym".}
+macro dispatch(N: static int, T: type SomeNumber): untyped =
+  let BaseT = getTypeInst(T)[1]
+  result = bindSym($BaseT & "x" & $N)
+
+type
+  VecIntrin*[N: static int, T: SomeNumber] = dispatch(N, T)
+
+func `$`*[N, T](vec: VecIntrin[N, T]): string =
+  ## Display a vector
+  $cast[array[N, T]](vec)
diff --git a/tests/generics/m22373a.nim b/tests/generics/m22373a.nim
new file mode 100644
index 000000000..28e087ca6
--- /dev/null
+++ b/tests/generics/m22373a.nim
@@ -0,0 +1,7 @@
+# module a for t22373
+
+# original:
+type LightClientHeader* = object
+
+# simplified:
+type TypeOrTemplate* = object
diff --git a/tests/generics/m22373b.nim b/tests/generics/m22373b.nim
new file mode 100644
index 000000000..67ee4211b
--- /dev/null
+++ b/tests/generics/m22373b.nim
@@ -0,0 +1,18 @@
+# module b for t22373
+
+import m22373a
+
+# original:
+type
+  LightClientDataFork* {.pure.} = enum
+    None = 0,
+    Altair = 1
+template LightClientHeader*(kind: static LightClientDataFork): auto =
+  when kind == LightClientDataFork.Altair:
+    typedesc[m22373a.LightClientHeader]
+  else:
+    static: raiseAssert "Unreachable"
+
+# simplified:
+template TypeOrTemplate*(num: int): untyped =
+  typedesc[m22373a.TypeOrTemplate]
diff --git a/tests/generics/m3770.nim b/tests/generics/m3770.nim
new file mode 100644
index 000000000..7f5714a2b
--- /dev/null
+++ b/tests/generics/m3770.nim
@@ -0,0 +1,11 @@
+type
+  Noice* = object
+    hidden: int
+
+template jjj*: Noice =
+  Noice(hidden: 15)
+
+type Opt* = object
+  o: int
+
+template none*(O: type Opt): Opt = Opt(o: 0)
diff --git a/tests/generics/mbind_bracket.nim b/tests/generics/mbind_bracket.nim
new file mode 100644
index 000000000..4bf18b471
--- /dev/null
+++ b/tests/generics/mbind_bracket.nim
@@ -0,0 +1,17 @@
+
+import tables
+
+type
+  UUIDObject* = ref object
+    uuid: string
+
+  Registry*[T] = ref object
+    objects: Table[string, T]
+
+proc newRegistry*[T](): Registry[T] =
+  result = Registry[T]()
+  result.objects = initTable[string, T](128)
+
+proc register*[T](self: Registry[T], obj: T) =
+  self.objects[obj.uuid] = obj
+
diff --git a/tests/generics/mclosed_sym.nim b/tests/generics/mclosed_sym.nim
new file mode 100644
index 000000000..bcccd9a85
--- /dev/null
+++ b/tests/generics/mclosed_sym.nim
@@ -0,0 +1,10 @@
+
+type R* = object
+
+type Data*[T] = object
+  d*: T
+
+proc same(r:R, d:int) = echo "TEST2"
+
+proc doIt*(d:Data, r:R) =
+  r.same(1)      # Expecting this to invoke the local `same()` method
diff --git a/tests/generics/mdotlookup.nim b/tests/generics/mdotlookup.nim
new file mode 100644
index 000000000..090b97771
--- /dev/null
+++ b/tests/generics/mdotlookup.nim
@@ -0,0 +1,28 @@
+proc baz(o: auto): int = 5 # if bar is exported, it works
+
+type MyObj = object
+  x: int
+
+proc foo*(b: auto) =
+  var o: MyObj
+  echo b.baz, " ", o.x.baz, " ", b.baz()
+
+import sets
+
+var intset = initHashSet[int]()
+
+proc fn*[T](a: T) =
+  if a in intset: echo("true")
+  else: echo("false")
+
+import strutils
+
+proc doStrip*[T](a: T): string =
+  result = ($a).strip()
+
+type Foo = int32
+proc baz2*[T](y: int): auto =
+  result = y.Foo
+
+proc set*(x: var int, a, b: string) =
+  x = a.len + b.len
diff --git a/tests/generics/mfriends.nim b/tests/generics/mfriends.nim
new file mode 100644
index 000000000..19672289e
--- /dev/null
+++ b/tests/generics/mfriends.nim
@@ -0,0 +1,11 @@
+
+type
+  TMyObj = object
+    x: int
+
+proc gen*[T](): T =
+  var d: TMyObj
+  # access private field here
+  d.x = 3
+  result = d.x
+
diff --git a/tests/generics/mmodule_same_as_proc.nim b/tests/generics/mmodule_same_as_proc.nim
new file mode 100644
index 000000000..048b98336
--- /dev/null
+++ b/tests/generics/mmodule_same_as_proc.nim
@@ -0,0 +1,2 @@
+
+proc mmodule_same_as_proc*(x: string) = discard
diff --git a/tests/generics/module_with_generics.nim b/tests/generics/module_with_generics.nim
new file mode 100644
index 000000000..960a694d7
--- /dev/null
+++ b/tests/generics/module_with_generics.nim
@@ -0,0 +1,14 @@
+type
+  Base[T] {.inheritable.} = ref object
+    value*: T
+
+  Derived[T] = ref object of Base[T]
+    derivedValue*: T
+
+proc makeDerived*[T](v: T): Derived[T] =
+  new result
+  result.value = v
+
+proc setBaseValue*[T](a: Base[T], value: T) =
+  a.value = value
+
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/moverloading_typedesc.nim b/tests/generics/moverloading_typedesc.nim
new file mode 100644
index 000000000..92805fb7b
--- /dev/null
+++ b/tests/generics/moverloading_typedesc.nim
@@ -0,0 +1,11 @@
+import tables
+
+type
+  FFoo* = object
+  FBar* = object
+
+proc new*(_: typedesc[FFoo]): int = 2
+proc new*[T](_: typedesc[T]): int = 3
+proc new*(_: typedesc): int = 4
+proc new*(_: typedesc[seq[Table[int, seq[Table[int, string]]]]]): int = 5
+proc new*(_: typedesc[seq[Table[int, seq[Table[int, typedesc]]]]]): int = 6
diff --git a/tests/generics/mtypenodes.nim b/tests/generics/mtypenodes.nim
new file mode 100644
index 000000000..e1132241b
--- /dev/null
+++ b/tests/generics/mtypenodes.nim
@@ -0,0 +1,6 @@
+# issue #22699
+
+type Private = distinct int
+
+proc chop*[T](x: int): int =
+  cast[int](cast[tuple[field: Private]](x))
diff --git a/tests/generics/muninstantiatedgenericcalls.nim b/tests/generics/muninstantiatedgenericcalls.nim
new file mode 100644
index 000000000..caed07c98
--- /dev/null
+++ b/tests/generics/muninstantiatedgenericcalls.nim
@@ -0,0 +1,26 @@
+import std/bitops
+
+const
+  lengths = block:
+    var v: array[64, int8]
+    for i in 0..<64:
+      v[i] = int8((i + 7) div 7)
+    v
+
+type
+  Leb128* = object
+
+{.push checks: off.}
+func len(T: type Leb128, x: SomeUnsignedInt): int8 =
+  if x == 0: 1
+  else: lengths[fastLog2(x)]
+{.pop.}
+
+# note private to test scoping issue:
+func maxLen(T: type Leb128, I: type): int8 =
+  Leb128.len(I.high)
+
+type
+  Leb128Buf*[T: SomeUnsignedInt] = object
+    data*: array[maxLen(Leb128, T), byte] 
+    len*: int8
diff --git a/tests/generics/t12938.nim b/tests/generics/t12938.nim
new file mode 100644
index 000000000..e09d65c7a
--- /dev/null
+++ b/tests/generics/t12938.nim
@@ -0,0 +1,9 @@
+type
+  ExampleArray[Size, T] = array[Size, T]
+
+var integerArray: ExampleArray[32, int]  # Compiler crash!
+doAssert integerArray.len == 32
+
+const Size = 2
+var integerArray2: ExampleArray[Size, int]
+doAssert integerArray2.len == 2
diff --git a/tests/generics/t13525.nim b/tests/generics/t13525.nim
new file mode 100644
index 000000000..1fd84852b
--- /dev/null
+++ b/tests/generics/t13525.nim
@@ -0,0 +1,6 @@
+# https://github.com/nim-lang/Nim/issues/13524
+template fun(field): untyped = astToStr(field)
+proc test1(): string = fun(nonexistent1)
+proc test2[T](): string = fun(nonexistent2) # used to cause: Error: undeclared identifier: 'nonexistent2'
+doAssert test1() == "nonexistent1"
+doAssert test2[int]() == "nonexistent2"
diff --git a/tests/generics/t14193.nim b/tests/generics/t14193.nim
new file mode 100644
index 000000000..213b1a8e6
--- /dev/null
+++ b/tests/generics/t14193.nim
@@ -0,0 +1,6 @@
+type
+  Task*[N: int] = object
+    env*: array[N, byte]
+
+var task14193: Task[20]
+doAssert task14193.env.len == 20
diff --git a/tests/generics/t14509.nim b/tests/generics/t14509.nim
new file mode 100644
index 000000000..ef3143ee4
--- /dev/null
+++ b/tests/generics/t14509.nim
@@ -0,0 +1,4 @@
+import m14509
+
+var v: VecIntrin[4, float32]
+doAssert $v == "[0.0, 0.0, 0.0, 0.0]"
diff --git a/tests/generics/t1500.nim b/tests/generics/t1500.nim
new file mode 100644
index 000000000..6dd457d33
--- /dev/null
+++ b/tests/generics/t1500.nim
@@ -0,0 +1,8 @@
+#issue 1500
+
+type
+  TFtpBase*[SockType] = object
+    job: TFTPJob[SockType]
+  PFtpBase*[SockType] = ref TFtpBase[SockType]
+  TFtpClient* = TFtpBase[string]
+  TFTPJob[T] = object
\ No newline at end of file
diff --git a/tests/generics/t17509.nim b/tests/generics/t17509.nim
new file mode 100644
index 000000000..89f507577
--- /dev/null
+++ b/tests/generics/t17509.nim
@@ -0,0 +1,25 @@
+type List[O] = object
+  next: ptr List[O]
+
+proc initList[O](l: ptr List[O]) =
+  l[].next = l
+
+type
+  PolytopeVertex[R] = object
+    list: List[PolytopeVertex[R]]
+
+  PolytopeEdge[R] = object
+    list: List[PolytopeEdge[R]]
+
+  Polytope[R] = object
+    vertices: List[PolytopeVertex[R]]
+    edges: List[PolytopeEdge[R]]
+
+var pt: Polytope[float]
+
+static:
+  doAssert pt.vertices.next is (ptr List[PolytopeVertex[float]])
+  doAssert pt.edges.next is (ptr List[PolytopeEdge[float]])
+
+initList(addr pt.vertices)
+initList(addr pt.edges)
\ No newline at end of file
diff --git a/tests/generics/t18823.nim b/tests/generics/t18823.nim
new file mode 100644
index 000000000..94c79aebe
--- /dev/null
+++ b/tests/generics/t18823.nim
@@ -0,0 +1,6 @@
+type BitsRange[T] = range[0..sizeof(T)*8-1]
+
+proc bar[T](a: T; b: BitsRange[T]) =
+  discard
+
+bar(1, 2.Natural)
diff --git a/tests/generics/t18859.nim b/tests/generics/t18859.nim
new file mode 100644
index 000000000..ca6c3d10b
--- /dev/null
+++ b/tests/generics/t18859.nim
@@ -0,0 +1,17 @@
+import macros
+
+macro symFromDesc(T: typedesc): untyped =
+  let typ = getType(T)
+  typ[1]
+
+template produceType(T: typedesc): untyped =
+  type
+    XT = object
+      x: symFromDesc(T)
+
+  XT
+
+type
+  X[T] = produceType(T)
+
+var x: X[int]
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/t20996.nim b/tests/generics/t20996.nim
new file mode 100644
index 000000000..8aa83c4e2
--- /dev/null
+++ b/tests/generics/t20996.nim
@@ -0,0 +1,15 @@
+discard """
+  action: compile
+"""
+
+import std/macros
+
+macro matchMe(x: typed): untyped =
+  discard x.getTypeImpl
+
+type
+  ElementRT = object
+  Element[Z] = ElementRT # this version is needed, even though we don't use it
+
+let ar = ElementRT()
+matchMe(ar)
diff --git a/tests/generics/t21742.nim b/tests/generics/t21742.nim
new file mode 100644
index 000000000..c49c8ee97
--- /dev/null
+++ b/tests/generics/t21742.nim
@@ -0,0 +1,10 @@
+type
+  Foo[T] = object
+    x:T
+  Bar[T,R] = Foo[T]
+  Baz = Bar[int,float]
+
+proc qux[T,R](x: Bar[T,R]) = discard
+
+var b:Baz
+b.qux()
\ No newline at end of file
diff --git a/tests/generics/t21760.nim b/tests/generics/t21760.nim
new file mode 100644
index 000000000..5343279bb
--- /dev/null
+++ b/tests/generics/t21760.nim
@@ -0,0 +1,8 @@
+import std/tables
+
+type Url = object
+
+proc myInit(_: type[Url], params = default(Table[string, string])): Url =
+  discard
+
+discard myInit(Url)
\ No newline at end of file
diff --git a/tests/generics/t21958.nim b/tests/generics/t21958.nim
new file mode 100644
index 000000000..f566b57cb
--- /dev/null
+++ b/tests/generics/t21958.nim
@@ -0,0 +1,11 @@
+discard """
+  action: compile
+"""
+
+type
+  Ct*[T: SomeUnsignedInt] = distinct T
+
+template `shr`*[T: Ct](x: T, y: SomeInteger): T = T(T.T(x) shr y)
+
+var x: Ct[uint64]
+let y {.used.} = x shr 2
\ No newline at end of file
diff --git a/tests/generics/t22373.nim b/tests/generics/t22373.nim
new file mode 100644
index 000000000..ecfaf0f1b
--- /dev/null
+++ b/tests/generics/t22373.nim
@@ -0,0 +1,16 @@
+# issue #22373
+
+import m22373a
+import m22373b
+
+# original:
+template lazy_header(name: untyped): untyped {.dirty.} =
+  var `name _ ptr`: ptr[data_fork.LightClientHeader]  # this data_fork.Foo part seems required to reproduce
+proc createLightClientUpdates(data_fork: static LightClientDataFork) =
+  lazy_header(attested_header)
+createLightClientUpdates(LightClientDataFork.Altair)
+
+# simplified:
+proc generic[T](abc: T) =
+  var x: abc.TypeOrTemplate
+generic(123)
diff --git a/tests/generics/t22826.nim b/tests/generics/t22826.nim
new file mode 100644
index 000000000..914d4243a
--- /dev/null
+++ b/tests/generics/t22826.nim
@@ -0,0 +1,8 @@
+import std/tables
+
+var a: Table[string, float]
+
+type Value*[T] = object
+  table: Table[string, Value[T]]
+
+discard toTable({"a": Value[float]()})
\ No newline at end of file
diff --git a/tests/generics/t23186.nim b/tests/generics/t23186.nim
new file mode 100644
index 000000000..76f38da6b
--- /dev/null
+++ b/tests/generics/t23186.nim
@@ -0,0 +1,155 @@
+# issue #23186
+
+block: # simplified
+  template typedTempl(x: int, body): untyped =
+    body
+  proc generic1[T]() =
+    discard
+  proc generic2[T]() =
+    typedTempl(1):
+      let x = generic1[T]
+  generic2[int]()
+
+import std/macros
+
+when not compiles(len((1, 2))):
+  import std/typetraits
+
+  func len(x: tuple): int =
+    arity(type(x))
+
+block: # full issue example
+  type FieldDescription = object
+    name: NimNode
+  func isTuple(t: NimNode): bool =
+    t.kind == nnkBracketExpr and t[0].kind == nnkSym and eqIdent(t[0], "tuple")
+  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 nnkIdentDefs:
+      for i in 0 ..< n.len - 2:
+        var field: FieldDescription
+        field.name = n[i]
+        if field.name.kind == nnkPragmaExpr:
+          field.name = field.name[0]
+        if field.name.kind == nnkPostfix:
+          field.name = field.name[1]
+        result.add field
+    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
+    if objectType.kind == nnkRefTy:
+      objectType = objectType[0]
+    let recList = objectType[2]
+    collectFieldsFromRecList result, recList
+  proc recordFields(typeImpl: NimNode): seq[FieldDescription] =
+    let objectType = case typeImpl.kind
+      of nnkObjectTy: typeImpl
+      of nnkTypeDef: typeImpl[2]
+      else:
+        macros.error("object type expected", typeImpl)
+        return
+    collectFieldsInHierarchy(result, objectType)
+  proc skipPragma(n: NimNode): NimNode =
+    if n.kind == nnkPragmaExpr: n[0]
+    else: n
+  func declval(T: type): T =
+    doAssert false,
+      "declval should be used only in `typeof` expressions and concepts"
+    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`
+            # we can't access .Fieldn, so our helper knows
+            # to parseInt this
+      let field =
+        if isSymbol:
+          quote do: declval(`T`).`fieldIdent`
+        else:
+          quote do: declval(`T`)[`fieldIndex`]
+      result.add quote do:
+        block:
+          `fieldNameDefs`
+          type FieldType {.inject, used.} = type(`field`)
+          `body`
+      i += 1
+  template enumAllSerializedFields(T: type, body): untyped =
+    when T is ref|ptr:
+      type TT = type(default(T)[])
+      enumAllSerializedFieldsImpl(TT, body)
+    else:
+      enumAllSerializedFieldsImpl(T, body)
+  type
+    MemRange = object
+      startAddr: ptr byte
+      length: int
+    SszNavigator[T] = object
+      m: MemRange
+  func sszMount(data: openArray[byte], T: type): SszNavigator[T] =
+    let startAddr = unsafeAddr data[0]
+    SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len))
+  func sszMount(data: openArray[char], T: type): SszNavigator[T] =
+    let startAddr = cast[ptr byte](unsafeAddr data[0])
+    SszNavigator[T](m: MemRange(startAddr: startAddr, length: data.len))
+  template sszMount(data: MemRange, T: type): SszNavigator[T] =
+    SszNavigator[T](m: data)
+  func navigateToField[T](
+      n: SszNavigator[T],
+      FieldType: type): SszNavigator[FieldType] =
+    default(SszNavigator[FieldType])
+  type
+    FieldInfo = ref object
+      navigator: proc (m: MemRange): MemRange {.
+        gcsafe, noSideEffect, raises: [IOError] .}
+  func fieldNavigatorImpl[RecordType; FieldType; fieldName: static string](
+      m: MemRange): MemRange =
+    var typedNavigator = sszMount(m, RecordType)
+    discard navigateToField(typedNavigator, FieldType)
+    default(MemRange)
+  func genTypeInfo(T: type) =
+    when T is object:
+      enumAllSerializedFields(T):
+        discard FieldInfo(navigator: fieldNavigatorImpl[T, FieldType, fieldName])
+  type
+    Foo = object
+      bar: Bar
+    BarList = seq[uint64]
+    Bar = object
+      b: BarList
+      baz: Baz
+    Baz = object
+      i: uint64
+  genTypeInfo(Foo)
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/t2tables.nim b/tests/generics/t2tables.nim
new file mode 100644
index 000000000..e4b1fb967
--- /dev/null
+++ b/tests/generics/t2tables.nim
@@ -0,0 +1,15 @@
+discard """
+action: compile
+"""
+
+# bug #3669
+
+import tables
+
+type
+  G[T] = object
+    inodes: Table[int, T]
+    rnodes: Table[T, int]
+
+var g: G[string]
+echo g.rnodes["foo"]
diff --git a/tests/generics/t3770.nim b/tests/generics/t3770.nim
new file mode 100644
index 000000000..ffccbeeb5
--- /dev/null
+++ b/tests/generics/t3770.nim
@@ -0,0 +1,13 @@
+# bug #3770
+import m3770
+
+doAssert $jjj() == "(hidden: 15)"  # works
+
+proc someGeneric(_: type) =
+  doAssert $jjj() == "(hidden: 15)" # fails: "Error: the field 'hidden' is not accessible."
+
+someGeneric(int)
+
+# bug #20900
+proc c(y: int | int, w: Opt = Opt.none) = discard
+c(0)
diff --git a/tests/generics/t4668.nim b/tests/generics/t4668.nim
new file mode 100644
index 000000000..bd44cc975
--- /dev/null
+++ b/tests/generics/t4668.nim
@@ -0,0 +1,166 @@
+discard """
+  output: '''
+foo1
+foo2
+'''
+"""
+
+block:
+  type
+    FooObj[T] = object
+      v: T
+    Foo1[T] = FooObj[T]
+    Foo2 = FooObj
+
+  proc foo1(x: Foo1) = echo "foo1"
+  proc foo2(x: Foo2) = echo "foo2"
+
+  var x: FooObj[float]
+  foo1(x)  # works
+  foo2(x)  # works
+
+block:
+  type
+    FooObj[T] = T
+    Foo1[T] = FooObj[T]
+    Foo2 = FooObj
+    Foo3 = Foo1
+    Foo4x = FooObj[SomeInteger]
+    Foo4 = FooObj[SomeFloat]
+    Foo5x = Foo1[SomeInteger]
+    Foo5 = Foo1[SomeFloat]
+
+  proc foo0(x: FooObj): int = 0
+  proc foo1(x: Foo1): int = 1
+  proc foo2(x: Foo2): int = 2
+  proc foo3(x: Foo3): int = 3
+  proc foo4(x: Foo4x): int = 40
+  proc foo4(x: Foo4): int = 4
+  proc foo5(x: Foo5x): int = 50
+  proc foo5(x: Foo5): int = 5
+
+  block:
+    var x: FooObj[float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+  block:
+    var x: Foo1[float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+  block:
+    var x: Foo2[float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+block:
+  type
+    FooObj[T,U] = object
+      x: T
+      y: U
+    Foo1[U,T] = FooObj[T,U]
+    Foo2 = FooObj
+    Foo3 = Foo1
+    Foo4x = FooObj[SomeInteger,SomeInteger]
+    Foo4y = FooObj[SomeInteger,SomeFloat]
+    Foo4z = FooObj[SomeFloat,SomeFloat]
+    Foo4 = FooObj[SomeFloat,SomeInteger]
+    Foo5x = Foo1[SomeInteger,SomeInteger]
+    Foo5y = Foo1[SomeFloat,SomeInteger]
+    Foo5z = Foo1[SomeFloat,SomeFloat]
+    Foo5 = Foo1[SomeInteger,SomeFloat]
+
+  proc foo0(x: FooObj): int = 0
+  proc foo1(x: Foo1): int = 1
+  proc foo2(x: Foo2): int = 2
+  proc foo3(x: Foo3): int = 3
+  proc foo4(x: Foo4x): int = 40
+  proc foo4(x: Foo4y): int = 41
+  proc foo4(x: Foo4z): int = 42
+  proc foo4(x: Foo4): int = 4
+  proc foo5(x: Foo5x): int = 50
+  proc foo5(x: Foo5y): int = 51
+  proc foo5(x: Foo5z): int = 52
+  proc foo5(x: Foo5): int = 5
+
+  block:
+    var x: FooObj[float,int]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+  block:
+    var x: Foo1[int,float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+block:
+  type
+    FooObj[T] = object of RootObj
+      v: T
+    FooObj2[T] = object of FooObj[T]
+    Foo1[T] = FooObj[T]
+    Foo2 = FooObj
+    Foo3 = Foo1
+    Foo4x = FooObj[SomeInteger]
+    Foo4 = FooObj[SomeFloat]
+    Foo5x = Foo1[SomeInteger]
+    Foo5 = Foo1[SomeFloat]
+
+  proc foo0(x: FooObj): int = 0
+  proc foo1(x: Foo1): int = 1
+  proc foo2(x: Foo2): int = 2
+  proc foo3(x: Foo3): int = 3
+  proc foo4(x: Foo4x): int = 40
+  proc foo4(x: Foo4): int = 4
+  proc foo5(x: Foo5x): int = 50
+  proc foo5(x: Foo5): int = 5
+
+  block:
+    var x: FooObj[float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+  block:
+    var x: Foo1[float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+
+  #[ XXX These still fail
+  block:
+    var x: FooObj2[float]
+    doAssert(foo0(x) == 0)
+    doAssert(foo1(x) == 1)
+    doAssert(foo2(x) == 2)
+    doAssert(foo3(x) == 3)
+    doAssert(foo4(x) == 4)
+    doAssert(foo5(x) == 5)
+  ]#
diff --git a/tests/generics/t500.nim b/tests/generics/t500.nim
new file mode 100644
index 000000000..2486359aa
--- /dev/null
+++ b/tests/generics/t500.nim
@@ -0,0 +1,8 @@
+discard """
+action: compile
+"""
+
+type
+  TTest = tuple[x: range[0..80], y: range[0..25]]
+
+let x: TTest = (2, 23)
diff --git a/tests/generics/t5602_inheritence.nim b/tests/generics/t5602_inheritence.nim
new file mode 100644
index 000000000..ee5ba89d5
--- /dev/null
+++ b/tests/generics/t5602_inheritence.nim
@@ -0,0 +1,24 @@
+discard """
+  output: "seq[float]\n0"
+  targets: "c cpp"
+"""
+
+# https://github.com/nim-lang/Nim/issues/5602
+
+import typetraits, module_with_generics
+
+type
+  Foo[T] = object of RootObj
+  Bar[T] = object of Foo[seq[T]]
+
+proc p[T](f: Foo[T]): T =
+  echo T.name
+
+var s: Bar[float]
+echo p(s).len # the bug was: p(s) should return seq[float], but returns float instead
+
+# Test overloading and code generation when
+# downcasting is required for generic types:
+var d = makeDerived(10)
+setBaseValue(d, 20)
+
diff --git a/tests/generics/t5926.nim b/tests/generics/t5926.nim
new file mode 100644
index 000000000..bb14c3af5
--- /dev/null
+++ b/tests/generics/t5926.nim
@@ -0,0 +1,22 @@
+discard """
+action: compile
+"""
+
+type
+  SomeObj[T] = object
+
+template useSomeObj[T]() =
+  var retObj: SomeObj[T]
+
+useSomeObj[void]()
+useSomeObj[int]()
+
+
+type
+  Data*[T] = object
+    x: T
+
+template test*[T](xxx: T) =
+  let data = Data[T](x: xxx)
+
+test(1)
diff --git a/tests/generics/t6060.nim b/tests/generics/t6060.nim
new file mode 100644
index 000000000..6b1856f1c
--- /dev/null
+++ b/tests/generics/t6060.nim
@@ -0,0 +1,11 @@
+import tables
+
+type MyTab[A,B] = distinct TableRef[A,B]
+
+proc `$`[A,B](t: MyTab[A,B]): string =
+  "My special table " & $TableRef[A,B](t)
+
+proc create[A,B](): MyTab[A,B] = MyTab(newTable[A,B]())
+
+var a = create[int,int]()
+doAssert $a == "My special table {:}"
diff --git a/tests/generics/t6137.nim b/tests/generics/t6137.nim
new file mode 100644
index 000000000..fb7db22f8
--- /dev/null
+++ b/tests/generics/t6137.nim
@@ -0,0 +1,28 @@
+discard """
+  errormsg: "cannot instantiate: 'T'"
+  line: 19
+"""
+
+type
+  # simple vector of declared fixed length
+  vector[N : static[int]] = array[0..N-1, float]
+
+proc `*`[T](x: float, a: vector[T]): vector[T] =
+  # multiplication by scalar
+  for ii in 0..high(a):
+    result[ii] = a[ii]*x
+
+let
+  # define a vector of length 3
+  x: vector[3] = [1.0, 3.0, 5.0]
+
+proc vectFunc[T](x: vector[T]): vector[T] =
+  # Define a vector function
+  result = 2.0*x
+
+proc passVectFunction[T](g: proc(x: vector[T]): vector[T], x: vector[T]): vector[T] =
+  # pass a vector function as input in another procedure
+  result = g(x)
+
+let
+  xNew = passVectFunction(vectFunc,x)
diff --git a/tests/generics/t6637.nim b/tests/generics/t6637.nim
new file mode 100644
index 000000000..dd4f339a2
--- /dev/null
+++ b/tests/generics/t6637.nim
@@ -0,0 +1,9 @@
+
+type
+  Grid2D*[I: SomeInteger, w, h: static[I], T] = object
+    grid: array[w, array[h, T]]
+  Grid2DIns = Grid2D[int, 2, 3, uint8]
+
+let a = Grid2DIns()
+doAssert a.grid.len == 2
+doAssert a.grid[0].len == 3
diff --git a/tests/generics/t7141.nim b/tests/generics/t7141.nim
new file mode 100644
index 000000000..b1e9cbf43
--- /dev/null
+++ b/tests/generics/t7141.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot instantiate: \'T\'"
+  line: 6
+"""
+
+proc foo[T](x: T) =
+  discard
+
+var fun = if true: foo else: foo
diff --git a/tests/generics/t7446.nim b/tests/generics/t7446.nim
new file mode 100644
index 000000000..71aa8f0e8
--- /dev/null
+++ b/tests/generics/t7446.nim
@@ -0,0 +1,10 @@
+proc foo(x: Natural or SomeUnsignedInt):int = 
+  when x is int:
+    result = 1
+  else:
+    result = 2
+let a = 10
+doAssert foo(a) == 1
+
+let b = 10'u8
+doAssert foo(b) == 2
\ No newline at end of file
diff --git a/tests/generics/t7839.nim b/tests/generics/t7839.nim
new file mode 100644
index 000000000..4d17b438b
--- /dev/null
+++ b/tests/generics/t7839.nim
@@ -0,0 +1,9 @@
+type A[I: SomeOrdinal, E] = tuple # same for object
+  length: int
+
+doAssert A.sizeof == sizeof(int) # works without the following proc
+
+proc newA*[I: SomeOrdinal, E](): A[I, E] = # works without `SomeOrdinal`
+  discard
+
+discard newA[uint8, int]()
diff --git a/tests/generics/t8270.nim b/tests/generics/t8270.nim
new file mode 100644
index 000000000..1e731d1d4
--- /dev/null
+++ b/tests/generics/t8270.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "cannot instantiate: \'T\'"
+  line: 6
+"""
+
+proc m[T](x: T): int = discard
+echo [m]
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/tarc_misc.nim b/tests/generics/tarc_misc.nim
new file mode 100644
index 000000000..3e7762556
--- /dev/null
+++ b/tests/generics/tarc_misc.nim
@@ -0,0 +1,21 @@
+discard """
+  output: ''''''
+  cmd: "nim c --gc:arc $file"
+"""
+
+# bug #13519
+
+var unrelated: seq[proc() {.closure, gcsafe.}]
+
+unrelated.add proc () =
+  echo "gcsafe"
+
+import tables, sequtils
+let t = newTable[int, proc()]()
+
+type
+  MyProc = proc() {.closure.}
+
+var result: seq[MyProc] = @[]
+for x in t.values:
+  result.add(x)
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/tbaddeprecated.nim b/tests/generics/tbaddeprecated.nim
new file mode 100644
index 000000000..335234a25
--- /dev/null
+++ b/tests/generics/tbaddeprecated.nim
@@ -0,0 +1,55 @@
+discard """
+  output: '''
+not deprecated
+not deprecated
+not error
+not error
+'''
+"""
+
+# issue #21724
+
+block: # deprecated
+  {.push warningAsError[Deprecated]: on.}
+  type
+    SomeObj = object
+      hey: bool
+  proc hey() {.deprecated: "Shouldn't use this".} = echo "hey"
+  proc gen(o: auto) =
+    doAssert not compiles(o.hey())
+    if o.hey:
+      echo "not deprecated"
+  gen(SomeObj(hey: true))
+  doAssert not (compiles do:
+    proc hey(o: SomeObj) {.deprecated: "Shouldn't use this".} = echo "hey"
+    proc gen2(o: auto) =
+      if o.hey():
+        echo "not deprecated"
+    gen2(SomeObj(hey: true)))
+  proc hey(o: SomeObj) {.deprecated: "Shouldn't use this".} = echo "hey"
+  proc gen3(o: auto) =
+    if o.hey:
+      echo "not deprecated"
+  gen3(SomeObj(hey: true))
+  {.pop.}
+block: # error
+  type
+    SomeObj = object
+      hey: bool
+  proc hey() {.error: "Shouldn't use this".} = echo "hey"
+  proc gen(o: auto) =
+    doAssert not compiles(o.hey())
+    if o.hey:
+      echo "not error"
+  gen(SomeObj(hey: true))
+  doAssert not (compiles do:
+    proc hey(o: SomeObj) {.error: "Shouldn't use this".} = echo "hey"
+    proc gen2(o: auto) =
+      if o.hey():
+        echo "not error"
+    gen2(SomeObj(hey: true)))
+  proc hey(o: SomeObj) {.error: "Shouldn't use this".} = echo "hey"
+  proc gen3(o: auto) =
+    if o.hey:
+      echo "not error"
+  gen3(SomeObj(hey: true))
diff --git a/tests/generics/tbadgenericlambda.nim b/tests/generics/tbadgenericlambda.nim
new file mode 100644
index 000000000..9fac150c1
--- /dev/null
+++ b/tests/generics/tbadgenericlambda.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "nested proc can have generic parameters only when"
+  line: 6
+"""
+
+let x = proc (x, y: auto): auto = x + y
+
diff --git a/tests/generics/tbindoncevsbindmany.nim b/tests/generics/tbindoncevsbindmany.nim
new file mode 100644
index 000000000..01e801f0e
--- /dev/null
+++ b/tests/generics/tbindoncevsbindmany.nim
@@ -0,0 +1,68 @@
+template accept(x) =
+  static: assert(compiles(x))
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+type
+  ObjectWithNumber = concept obj
+    obj.number is int
+
+  Foo[T] = object
+    x: T
+
+type A = object
+  anumber: int
+
+type B = object
+  bnumber: int
+
+proc number(a: A): int = a.anumber
+proc number(b: B): int = b.bnumber
+
+proc notDistincConcept1(a: ObjectWithNumber, b: ObjectWithNumber) = discard
+proc notDistincConcept2(a, b: ObjectWithNumber) = discard
+proc distinctConcept1(a, b: distinct ObjectWithNumber) = discard
+proc distinctConcept2(a: ObjectWithNumber, b: distinct ObjectWithNumber) = discard
+proc distinctConcept3(a: distinct ObjectWithNumber, b: ObjectWithNumber) = discard
+proc distinctConcept4(a: distinct ObjectWithNumber, b: distinct ObjectWithNumber) = discard
+
+var a = A(anumber: 5)
+var b = B(bnumber: 6)
+
+accept notDistincConcept1(a, a)
+accept notDistincConcept1(b, b)
+reject notDistincConcept2(a, b)
+
+accept notDistincConcept2(a, a)
+accept notDistincConcept2(b, b)
+reject notDistincConcept2(a, b)
+
+accept distinctConcept1(a, b)
+accept distinctConcept2(a, b)
+accept distinctConcept3(a, b)
+accept distinctConcept4(a, b)
+
+proc nonDistincGeneric1(a: Foo, b: Foo) = discard
+proc nonDistincGeneric2(a, b: Foo) = discard
+proc distinctGeneric1(a, b: distinct Foo) = discard
+proc distinctGeneric2(a: distinct Foo, b: Foo) = discard
+proc distinctGeneric3(a: Foo, b: distinct Foo) = discard
+proc distinctGeneric4(a: distinct Foo, b: distinct Foo) = discard
+
+var f1 = Foo[int](x: 10)
+var f2 = Foo[string](x: "x")
+
+accept nonDistincGeneric1(f1, f1)
+accept nonDistincGeneric1(f2, f2)
+reject nonDistincGeneric1(f1, f2)
+
+accept nonDistincGeneric2(f1, f1)
+accept nonDistincGeneric2(f2, f2)
+reject nonDistincGeneric2(f1, f2)
+
+accept distinctGeneric1(f1, f1)
+accept distinctGeneric2(f1, f1)
+accept distinctGeneric3(f1, f1)
+accept distinctGeneric4(f1, f1)
+
diff --git a/tests/tbintree.nim b/tests/generics/tbintree.nim
index 89126eaa5..83f14406b 100755..100644
--- a/tests/tbintree.nim
+++ b/tests/generics/tbintree.nim
@@ -1,3 +1,10 @@
+discard """
+  output: '''hello
+world
+99
+110
+223'''
+"""
 type
   TBinaryTree[T] = object      # TBinaryTree is a generic type with
                                # with generic param ``T``
@@ -35,12 +42,12 @@ proc add*[Ty](root: var PBinaryTree[Ty], data: Ty) =
   # convenience proc:
   add(root, newNode(data))
 
-proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool = 
+proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool =
   # for testing this needs to be recursive, so that the
   # instantiated type is checked for proper tyGenericInst envelopes
-  if b == nil: 
+  if b == nil:
     result = false
-  else: 
+  else:
     var c = cmp(data, b.data)
     if c < 0: result = find(b.le, data)
     elif c > 0: result = find(b.ri, data)
@@ -48,8 +55,8 @@ proc find*[Ty2](b: PBinaryTree[Ty2], data: Ty2): bool =
 
 iterator preorder*[T](root: PBinaryTree[T]): T =
   # Preorder traversal of a binary tree.
-  # Since recursive iterators are not yet implemented,
-  # this uses an explicit stack:
+  # This uses an explicit stack (which is more efficient than
+  # a recursive iterator factory).
   var stack: seq[PBinaryTree[T]] = @[root]
   while stack.len > 0:
     var n = stack.pop()
@@ -66,7 +73,7 @@ iterator items*[T](root: PBinaryTree[T]): T =
     while n != nil:
       add(stack, n)
       n = n.le
-    if stack.len > 0: 
+    if stack.len > 0:
       n = stack.pop()
       yield n.data
       n = n.ri
@@ -78,24 +85,22 @@ proc debug[T](a: PBinaryTree[T]) =
     echo a.data
     debug(a.ri)
 
-when isMainModule:
+when true:
   var
     root: PBinaryTree[string]
-    x = newNode("hallo")
+    x = newNode("hello")
   add(root, x)
   add(root, "world")
   if find(root, "world"):
     for str in items(root):
-      stdout.write(str)
+      echo(str)
   else:
-    stdout.writeln("BUG")
-  
+    echo("BUG")
+
   var
     r2: PBinaryTree[int]
   add(r2, newNode(110))
   add(r2, 223)
   add(r2, 99)
   for y in items(r2):
-    stdout.write(y)
-
-#OUT halloworld99110223
+    echo(y)
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/tcan.nim b/tests/generics/tcan.nim
new file mode 100644
index 000000000..bbefa7233
--- /dev/null
+++ b/tests/generics/tcan.nim
@@ -0,0 +1,46 @@
+discard """
+  output: '''
+'''
+"""
+
+# Created by Eric Doughty-Papassideris on 2011-02-16.
+
+block talias_generic:
+  type
+    TGen[T] = object
+    TGen2[T] = TGen[T]
+
+
+block talias_specialised:
+  type
+    TGen[T] = object
+    TSpef = TGen[string]
+  var s: TSpef
+
+
+block tinherit:
+  type
+    TGen[T] = object of RootObj
+      x, y: T
+    TSpef[T] = object of TGen[T]
+
+  var s: TSpef[float]
+  s.x = 0.4
+  s.y = 0.6
+
+
+block tspecialise:
+  type
+    TGen[T] {.inheritable.} = object
+    TSpef = object of TGen[string]
+
+
+block tspecialised_equivalent:
+  type
+    TGen[T] = tuple[a: T]
+    TSpef = tuple[a: string]
+
+  var
+    a: TGen[string]
+    b: TSpef
+  a = b
diff --git a/tests/generics/tcannot_pass_empty_seq_to_generic.nim b/tests/generics/tcannot_pass_empty_seq_to_generic.nim
new file mode 100644
index 000000000..e33dbc10b
--- /dev/null
+++ b/tests/generics/tcannot_pass_empty_seq_to_generic.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "type mismatch: got <seq[empty]>"
+  line: 16
+"""
+
+# bug #836
+
+type
+  TOption*[T] = object
+    case FIsSome: bool
+    of false: nil
+    of true: FData: T
+
+proc some*[T](value: T): TOption[T] = TOption[T](FIsSome: true, FData: value)
+
+echo some(@[]).FIsSome
+
diff --git a/tests/generics/tconstraints.nim b/tests/generics/tconstraints.nim
new file mode 100644
index 000000000..3ca01cfd5
--- /dev/null
+++ b/tests/generics/tconstraints.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "type mismatch: got <int literal(232)>"
+  line: 16
+"""
+
+proc myGenericProc[T: object|tuple|ptr|ref|distinct](x: T): string =
+  result = $x
+
+type
+  TMyObj = tuple[x, y: int]
+
+var
+  x: TMyObj
+
+assert myGenericProc(x) == "(x: 0, y: 0)"
+assert myGenericProc(232) == "232"
diff --git a/tests/generics/tcritical.nim b/tests/generics/tcritical.nim
new file mode 100644
index 000000000..e84c03618
--- /dev/null
+++ b/tests/generics/tcritical.nim
@@ -0,0 +1,19 @@
+discard """
+  errormsg: "type mismatch"
+  line: 18
+"""
+
+# bug #3998
+
+type Vec3[T] = array[3, T]
+
+var vg: Vec3[float32] = Vec3([1.0f, 2.0f, 3.0f])
+
+echo "vg[0]: " & $vg[0]  # prints 1.0    OK
+echo "vg[1]: " & $vg[1]  # prints 2.0    OK
+echo "vg[2]: " & $vg[2]  # prints 3.0    OK
+echo ""
+
+var ve: Vec3[float64]
+ve = vg     # compiles, this MUST NOT be allowed!
+
diff --git a/tests/generics/texplicitgeneric1.nim b/tests/generics/texplicitgeneric1.nim
new file mode 100644
index 000000000..16f4f7330
--- /dev/null
+++ b/tests/generics/texplicitgeneric1.nim
@@ -0,0 +1,36 @@
+discard """
+  output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13"
+"""
+# test explicit type instantiation
+
+type
+  TDict*[TKey, TValue] = object
+    data: seq[tuple[k: TKey, v: TValue]]
+  PDict*[TKey, #with `==`(a, b: TKey): bool
+               #     hash(a: TKey): int,
+         TValue] = ref TDict[TKey, TValue]
+
+proc newDict*[TKey, TValue](): PDict[TKey, TValue] =
+  new(result)
+  result.data = @[]
+
+proc add*[TKey, TValue](d: PDict[TKey, TValue], k: TKey, v: TValue) =
+  d.data.add((k, v))
+
+iterator items*[Tkey, TValue](d: PDict[TKey, TValue]): tuple[k: TKey,
+               v: TValue] =
+  for k, v in items(d.data): yield (k, v)
+
+var d = newDict[int, string]()
+d.add(12, "12")
+d.add(13, "13")
+for k, v in items(d):
+  stdout.write("Key: ", $k, " value: ", v)
+
+var c = newDict[char, string]()
+c.add('A', "12")
+c.add('B', "13")
+for k, v in items(c):
+  stdout.write(" Key: ", $k, " value: ", v)
+
+stdout.write "\n"
diff --git a/tests/generics/texplicitgeneric2.nim b/tests/generics/texplicitgeneric2.nim
new file mode 100644
index 000000000..37b133130
--- /dev/null
+++ b/tests/generics/texplicitgeneric2.nim
@@ -0,0 +1,35 @@
+discard """
+  output: "Key: 12 value: 12Key: 13 value: 13 Key: A value: 12 Key: B value: 13"
+"""
+
+# test explicit type instantiation
+
+type
+  TDict*[TKey, TValue] = object
+    data: seq[tuple[k: TKey, v: TValue]]
+  PDict*[TKey, TValue] = ref TDict[TKey, TValue]
+
+proc newDict*[TKey, TValue](): PDict[TKey, TValue] =
+  new(result)
+  result.data = @[]
+
+proc add*(d: PDict, k: d.TKey, v: d.TValue) =
+  d.data.add((k, v))
+
+
+iterator items*(d: PDict): tuple[k: d.TKey, v: d.TValue] =
+  for k, v in items(d.data): yield (k, v)
+
+var d = newDict[int, string]()
+d.add(12, "12")
+d.add(13, "13")
+for k, v in items(d):
+  stdout.write("Key: ", $k, " value: ", v)
+
+var c = newDict[char, string]()
+c.add('A', "12")
+c.add('B', "13")
+for k, v in items(c):
+  stdout.write(" Key: ", $k, " value: ", v)
+
+stdout.write "\n"
diff --git a/tests/generics/tfakecovariance.nim b/tests/generics/tfakecovariance.nim
new file mode 100644
index 000000000..0920cb504
--- /dev/null
+++ b/tests/generics/tfakecovariance.nim
@@ -0,0 +1,78 @@
+template accept(x) =
+  static: assert(compiles(x))
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+type
+  BaseObj = object of RootObj
+  DerivedObj = object of BaseObj
+  NonDerivedObj = object
+
+  Container[T] = object
+
+var base: BaseObj
+var derived: DerivedObj
+var nonDerived: NonDerivedObj
+
+var baseContainer: Container[BaseObj]
+var derivedContainer: Container[DerivedObj]
+var nonDerivedContainer: Container[NonDerivedObj]
+
+# We can fake covariance by listing some specific derived types that
+# will be allowed with our overload. This is not a real covariance,
+# because there will be multiple instantiations of the proc, but for
+# many purposes, it will suffice:
+
+proc wantsSpecificContainers(c: Container[BaseObj or DerivedObj]) = discard
+
+accept wantsSpecificContainers(baseContainer)
+accept wantsSpecificContainers(derivedContainer)
+
+reject wantsSpecificContainers(nonDerivedContainer)
+reject wantsSpecificContainers(derived)
+
+# Now, let's make a more general solution able to catch all derived types:
+
+type
+  DerivedFrom[T] = concept type D
+    var derived: ref D
+    var base: ref T = derived
+
+proc wantsDerived(x: DerivedFrom[BaseObj]) = discard
+
+accept wantsDerived(base)
+accept wantsDerived(derived)
+
+reject wantsDerived(nonDerived)
+reject wantsDerived(baseContainer)
+
+proc wantsDerivedContainer(c: Container[DerivedFrom[BaseObj]]) = discard
+
+accept wantsDerivedContainer(baseContainer)
+accept wantsDerivedContainer(derivedContainer)
+
+reject wantsDerivedContainer(nonDerivedContainer)
+
+# The previous solutions were solving the problem for a single overload.
+# Let's solve it for multiple overloads by introducing a converter:
+
+type
+  OtherContainer[T] = object
+
+proc wantsBaseContainer1(c: OtherContainer[BaseObj]) = discard
+proc wantsBaseContainer2(c: OtherContainer[BaseObj]) = discard
+
+converter derivedToBase(c: OtherContainer[DerivedFrom[BaseObj]]): OtherContainer[BaseObj] = discard
+
+block:
+  var baseContainer: OtherContainer[BaseObj]
+  var derivedContainer: OtherContainer[DerivedObj]
+  var nonDerivedContainer: OtherContainer[NonDerivedObj]
+
+  accept wantsBaseContainer1(derivedContainer)
+  reject wantsBaseContainer1(nonDerivedContainer)
+
+  accept wantsBaseContainer2(derivedContainer)
+  reject wantsBaseContainer2(nonDerivedContainer)
+
diff --git a/tests/generics/tforwardgeneric.nim b/tests/generics/tforwardgeneric.nim
new file mode 100644
index 000000000..9f68bf332
--- /dev/null
+++ b/tests/generics/tforwardgeneric.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "1.1 11\n42\n0"
+  ccodecheck: "!@'ClEnv'"
+"""
+
+proc p[T](a, b: T): T
+
+echo p(0.9, 0.1), " ", p(9, 1)
+
+proc p[T](a, b: T): T =
+  let c = b
+  result = a + b + c
+
+# https://github.com/nim-lang/Nim/issues/4908
+proc foo(t: typedesc[int]): int
+proc bar(): int = foo(int)
+proc foo(t: typedesc[int]): int =
+  return 0
+
+# https://github.com/nim-lang/Nim/issues/4104
+proc print[T](t: T) # Error: implementation of 'print.print(t: int)' expected
+print 42 # moving this line after the implementation fixes the error,
+         # but such behaviour makes forward declaration pointless
+proc print[T](t: T) =
+  echo t
+
+echo bar()
+
diff --git a/tests/generics/tforwardgenericconstrained.nim b/tests/generics/tforwardgenericconstrained.nim
new file mode 100644
index 000000000..6163ea1a8
--- /dev/null
+++ b/tests/generics/tforwardgenericconstrained.nim
@@ -0,0 +1,73 @@
+discard """
+output: '''
+hello some integer
+hello range
+hello tuple
+hello seq
+hello object
+hello distinct
+hello enum
+'''
+"""
+
+
+
+# SomeInteger
+
+proc foo[T : SomeInteger](arg: T)
+proc foo[T : SomeInteger](arg: T) =
+  echo "hello some integer"
+foo(123)
+
+# range
+
+proc foo2[T : range[0..100]](arg: T)
+proc foo2[T : range[0..100]](arg: T) =
+  echo "hello range"
+foo2(7)
+
+# tuple
+
+proc foo3[T : tuple](arg: T)
+proc foo3[T : tuple](arg: T) =
+  echo "hello tuple"
+
+foo3((a:123,b:321))
+
+# seq
+
+proc foo4[T: seq](arg: T)
+proc foo4[T: seq](arg: T) =
+  echo "hello seq"
+
+foo4(@[1,2,3])
+
+# object
+
+proc foo5[T : object](arg: T)
+proc foo5[T : object](arg: T) =
+  echo "hello object"
+
+type MyType = object
+var mt: MyType
+foo5(mt)
+
+# distinct
+
+proc foo6[T : distinct](arg: T)
+proc foo6[T : distinct](arg: T) =
+  echo "hello distinct"
+
+type MyDistinct = distinct string
+var md: MyDistinct
+foo6(md)
+
+# enum
+
+proc foo7[T : enum](arg: T)
+proc foo7[T : enum](arg: T) =
+  echo "hello enum"
+
+type MyEnum = enum
+  ValueA
+foo7(ValueA)
diff --git a/tests/generics/tfriends.nim b/tests/generics/tfriends.nim
new file mode 100644
index 000000000..1e70d50a5
--- /dev/null
+++ b/tests/generics/tfriends.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "3"
+"""
+
+# Tests that a generic instantiation from a different module may access
+# private object fields:
+
+import mfriends
+
+echo gen[int]()
+
diff --git a/tests/generics/tgeneric0.nim b/tests/generics/tgeneric0.nim
new file mode 100644
index 000000000..16a148f7b
--- /dev/null
+++ b/tests/generics/tgeneric0.nim
@@ -0,0 +1,196 @@
+discard """
+  output: '''
+100
+0
+float32
+float32
+(name: "Resource 1", readers: ..., writers: ...)
+'''
+"""
+
+
+import std/tables
+
+
+block tgeneric0:
+  type
+    TX = Table[string, int]
+
+  proc foo(models: seq[Table[string, float]]): seq[float] =
+    result = @[]
+    for model in models.items:
+      result.add model["foobar"]
+
+  # bug #686
+  type TType[T; A] = array[A, T]
+
+  proc foo[T](p: TType[T, range[0..1]]) =
+    echo "foo"
+  proc foo[T](p: TType[T, range[0..2]]) =
+    echo "bar"
+
+  #bug #1366
+
+  proc reversed(x: auto) =
+    for i in countdown(x.low, x.high):
+      echo i
+
+  reversed(@[-19, 7, -4, 6])
+
+
+
+block tgeneric1:
+  type
+    TNode[T] = tuple[priority: int, data: T]
+    TBinHeap[T] = object
+      heap: seq[TNode[T]]
+      last: int
+    PBinHeap[T] = ref TBinHeap[T]
+
+  proc newBinHeap[T](heap: var PBinHeap[T], size: int) =
+    new(heap)
+    heap.last = 0
+    newSeq(heap.heap, size)
+    #newSeq(heap.seq, size)
+
+  proc parent(elem: int): int {.inline.} =
+    return (elem-1) div 2
+
+  proc siftUp[T](heap: PBinHeap[T], elem: int) =
+    var idx = elem
+    while idx != 0:
+      var p = parent(idx)
+      if heap.heap[idx].priority < heap.heap[p].priority:
+        swap(heap.heap[idx], heap.heap[p])
+        idx = p
+      else:
+        break
+
+  proc add[T](heap: PBinHeap[T], priority: int, data: T) =
+    var node: TNode[T]
+    node.priority = priority
+    node.data = data
+    heap.heap[heap.last] = node
+    siftUp(heap, heap.last)
+    inc(heap.last)
+
+  proc print[T](heap: PBinHeap[T]) =
+    for i in countup(0, heap.last):
+      stdout.write($heap.heap[i].data, "\n")
+
+  var heap: PBinHeap[int]
+
+  newBinHeap(heap, 256)
+  add(heap, 1, 100)
+  print(heap)
+
+
+
+block tgeneric2:
+  type
+    TX = Table[string, int]
+
+  proc foo(models: seq[TX]): seq[int] =
+    result = @[]
+    for model in models.items:
+      result.add model["foobar"]
+
+  type
+    Obj = object
+      field: Table[string, string]
+  var t: Obj
+  discard initTable[type(t.field), string]()
+
+
+
+block tgeneric4:
+  type
+    TIDGen[A: Ordinal] = object
+      next: A
+      free: seq[A]
+
+  proc newIDGen[A]: TIDGen[A] =
+      newSeq result.free, 0
+
+  var x = newIDGen[int]()
+
+block tgeneric5:
+  # bug #12528
+  proc foo[T](a: T; b: T) =
+    echo T
+
+  foo(0.0'f32, 0.0)
+
+  proc bar[T](a: T; b: T = 0.0) =
+    echo T
+
+  bar(0.0'f32)
+
+# bug #13378
+
+type
+  Resource = ref object of RootObj
+    name: string
+    readers, writers: seq[RenderTask]
+
+  RenderTask = ref object
+    name: string
+
+var res = Resource(name: "Resource 1")
+
+(proc (r: typeof(res)) =
+   echo r[])(res)
+
+# bug #4061
+
+type List[T] = object
+  e: T
+  n: ptr List[T]
+
+proc zip*[T,U](xs: List[T], ys: List[U]): List[(T,U)] = discard
+
+proc unzip*[T,U](xs: List[tuple[t: T, u: U]]): (List[T], List[U]) = discard
+
+proc unzip2*[T,U](xs: List[(T,U)]): (List[T], List[U]) = discard
+
+type
+  AtomicType = pointer|ptr|int
+
+  Atomic[T: AtomicType] = distinct T
+
+  Block[T: AtomicType] = object
+
+  AtomicContainer[T: AtomicType] = object
+    b: Atomic[ptr Block[T]]
+
+# bug #8295
+var x = AtomicContainer[int]()
+doAssert (ptr Block[int])(x.b) == nil
+
+
+# bug #23233
+type
+  JsonObjectType*[T: string or uint64] = Table[string, JsonValueRef[T]]
+
+  JsonValueRef*[T: string or uint64] = object
+    objVal*: JsonObjectType[T]
+
+proc scanValue[K](val: var K) =
+  var map: JsonObjectType[K.T]
+  var newVal: K
+  map["one"] = newVal
+
+block:
+  var a: JsonValueRef[uint64]
+  scanValue(a)
+
+  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/tgeneric3.nim b/tests/generics/tgeneric3.nim
new file mode 100644
index 000000000..29a73afc6
--- /dev/null
+++ b/tests/generics/tgeneric3.nim
@@ -0,0 +1,487 @@
+discard """
+output: '''
+312
+1000
+1000
+500
+0
+'''
+"""
+
+import strutils
+
+type
+  PNode[T,D] = ref TNode[T,D]
+  TItem[T,D] {.acyclic, pure, final, shallow.} = object
+        key: T
+        value: D
+        node: PNode[T,D]
+        when not (D is string):
+          val_set: bool
+
+  TItems[T,D] = seq[ref TItem[T,D]]
+  TNode[T,D] {.acyclic, pure, final, shallow.} = object
+        slots: TItems[T,D]
+        left: PNode[T,D]
+        count: int32
+
+
+  RPath[T,D] = tuple[
+    Xi: int,
+    Nd: PNode[T,D] ]
+
+const
+  cLen1 = 2
+  cLen2 = 16
+  cLen3 = 32
+  cLenCenter = 80
+  clen4 = 96
+  cLenMax = 128
+  cCenter = cLenMax div 2
+
+proc len[T,D] (n:PNode[T,D]): int {.inline.} =
+  return n.count
+
+proc clean[T: SomeOrdinal|SomeNumber](o: var T) {.inline.} = discard
+
+proc clean[T: string|seq](o: var T) {.inline.} =
+  o = nil
+
+proc clean[T,D] (o: ref TItem[T,D]) {.inline.} =
+  when (D is string) :
+    o.value = nil
+  else :
+    o.val_set = false
+
+proc isClean[T,D] (it: ref TItem[T,D]): bool {.inline.} =
+  when (D is string) :
+    return it.value == nil
+  else :
+    return not it.val_set
+
+proc isClean[T,D](n: PNode[T,D], x: int): bool {.inline.} =
+  when (D is string):
+    return n.slots[x].value == nil
+  else:
+    return not n.slots[x].val_set
+
+proc setItem[T,D](Akey: T, Avalue: D, ANode: PNode[T,D]): ref TItem[T,D] {.inline.} =
+  new(result)
+  result.key = Akey
+  result.value = Avalue
+  result.node = ANode
+  when not (D is string) :
+    result.val_set = true
+
+proc cmp[T:int8|int16|int32|int64|int] (a,b: T): T {.inline.} =
+  return a-b
+
+template binSearchImpl *(docmp: untyped) =
+  var bFound = false
+  result = 0
+  var H = haystack.len - 1
+  while result <= H :
+    var I {.inject.} = (result + H) shr 1
+    var SW = docmp
+    if SW < 0: result = I + 1
+    else:
+      H = I - 1
+      if SW == 0 : bFound = true
+  if bFound: inc(result)
+  else: result = - result
+
+proc bSearch[T,D] (haystack: PNode[T,D], needle:T): int {.inline.} =
+  binSearchImpl(haystack.slots[I].key.cmp(needle))
+
+proc DeleteItem[T,D] (n: PNode[T,D], x: int): PNode[T,D] {.inline.} =
+  var w = n.slots[x]
+  if w.node != nil :
+    clean(w)
+    return n
+  dec(n.count)
+  if n.count > 0 :
+    for i in countup(x, n.count - 1) : n.slots[i] = n.slots[i + 1]
+    n.slots[n.count] = nil
+    case n.count
+    of cLen1 : setLen(n.slots, cLen1)
+    of cLen2 : setLen(n.slots, cLen2)
+    of cLen3 : setLen(n.slots, cLen3)
+    of cLenCenter : setLen(n.slots, cLenCenter)
+    of cLen4 : setLen(n.slots, cLen4)
+    else: discard
+    result = n
+
+  else :
+    result = n.left
+    n.slots = @[]
+    n.left = nil
+
+proc internalDelete[T,D] (ANode: PNode[T,D], key: T, Avalue: var D): PNode[T,D] =
+  var Path: array[0..20, RPath[T,D]]
+  var n = ANode
+  result = n
+  clean(Avalue)
+  var h = 0
+  while n != nil:
+    var x = bSearch(n, key)
+    if x <= 0 :
+      Path[h].Nd = n
+      Path[h].Xi = - x
+      inc(h)
+      if x == 0 :
+        n = n.left
+      else :
+        x = (-x) - 1
+        if x < n.count :
+          n = n.slots[x].node
+        else :
+          n = nil
+    else :
+      dec(x)
+      if isClean(n, x) : return
+      Avalue = n.slots[x].value
+      var n2 = DeleteItem(n, x)
+      dec(h)
+      while (n2 != n) and (h >= 0) :
+        n = n2
+        var w = addr Path[h]
+        x  = w.Xi - 1
+        if x >= 0 :
+          if (n == nil) and isClean(w.Nd, x) :
+            n = w.Nd
+            n.slots[x].node = nil
+            n2 = DeleteItem(n, x)
+          else :
+            w.Nd.slots[x].node = n
+            return
+        else :
+          w.Nd.left = n
+          return
+        dec(h)
+      if h < 0:
+        result = n2
+      return
+
+proc internalFind[T,D] (n: PNode[T,D], key: T): ref TItem[T,D] {.inline.} =
+  var wn = n
+  while wn != nil :
+    var x = bSearch(wn, key)
+    if x <= 0 :
+      if x == 0 :
+        wn = wn.left
+      else :
+        x = (-x) - 1
+        if x < wn.count :
+          wn = wn.slots[x].node
+        else :
+          return nil
+
+    else :
+      return wn.slots[x - 1]
+  return nil
+
+proc traceTree[T,D](root: PNode[T,D]) =
+  proc traceX(x: int) =
+    write stdout, "("
+    write stdout, x
+    write stdout, ") "
+
+  proc traceEl(el: ref TItem[T,D]) =
+    write stdout, " key: "
+    write stdout, el.key
+    write stdout, " value: "
+    write stdout, el.value
+
+
+  proc traceln(space: string) =
+    writeLine stdout, ""
+    write stdout, space
+
+  proc doTrace(n: PNode[T,D], level: int) =
+    var space = spaces(2 * level)
+    traceln(space)
+    write stdout, "node: "
+    if n == nil:
+      writeLine stdout, "is empty"
+      return
+    write stdout, n.count
+    write stdout, " elements: "
+    if n.left != nil:
+      traceln(space)
+      write stdout, "left: "
+      doTrace(n.left, level+1)
+    for i, el in n.slots:
+      if el != nil and not isClean(el):
+        traceln(space)
+        traceX(i)
+        if i >= n.count:
+          write stdout, "error "
+        else:
+          traceEl(el)
+          if el.node != nil: doTrace(el.node, level+1)
+          else : write stdout, " empty "
+      elif i < n.count :
+        traceln(space)
+        traceX(i)
+        write stdout, "clean: "
+        when T is string :
+          if el.key != nil: write stdout, el.key
+        else : write stdout, el.key
+        if el.node != nil: doTrace(el.node, level+1)
+        else : write stdout, " empty "
+    writeLine stdout,""
+
+  doTrace(root, 0)
+
+proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], Akey: T, Avalue: D) =
+  var x = - APath.Xi
+  inc(APath.Nd.count)
+  case APath.Nd.count
+  of cLen1: setLen(APath.Nd.slots, cLen2)
+  of cLen2: setLen(APath.Nd.slots, cLen3)
+  of cLen3: setLen(APath.Nd.slots, cLenCenter)
+  of cLenCenter: setLen(APath.Nd.slots, cLen4)
+  of cLen4: setLen(APath.Nd.slots, cLenMax)
+  else: discard
+  for i in countdown(APath.Nd.count.int - 1, x + 1): APath.Nd.slots[i] = move APath.Nd.slots[i - 1]
+  APath.Nd.slots[x] = setItem(Akey, Avalue, ANode)
+
+
+proc SplitPage[T,D](n, left: PNode[T,D], xi: int, Akey:var T, Avalue:var D): PNode[T,D] =
+  var x = -xi
+  var it1: TItems[T,D]
+  it1.newSeq(cLenCenter)
+  new(result)
+  result.slots.newSeq(cLenCenter)
+  result.count = cCenter
+  if x == cCenter:
+    for i in 0..cCenter-1: 
+      it1[i] = move left.slots[i]
+    for i in 0..cCenter-1:
+      result.slots[i] = move left.slots[cCenter + i]
+    result.left = n
+  else :
+    if x < cCenter :
+      for i in 0..x-1:
+        it1[i] = move left.slots[i]
+      it1[x] = setItem(Akey, Avalue, n)
+      for i in x+1 .. cCenter-1:
+        it1[i] = move left.slots[i-1]
+      var w = left.slots[cCenter-1]
+      Akey = w.key
+      Avalue = w.value
+      result.left = w.node
+      for i in 0..cCenter-1:
+        result.slots[i] = move left.slots[cCenter + i]
+    else :
+      for i in 0..cCenter-1:
+        it1[i] = move left.slots[i]
+      x = x - (cCenter + 1)
+      for i in 0..x-1:
+        result.slots[i] = move left.slots[cCenter + i + 1]
+      result.slots[x] = setItem(Akey, Avalue, n)
+      for i in x+1 .. cCenter-1:
+        result.slots[i] = move left.slots[cCenter + i]
+      var w = left.slots[cCenter]
+      Akey = w.key
+      Avalue = w.value
+      result.left = w.node
+  left.count = cCenter
+  left.slots = move it1
+
+
+proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, Oldvalue: var D): ref TNode[T,D] =
+  var h: int
+  var Path: array[0..30, RPath[T,D]]
+  var left: PNode[T,D]
+  var n = ANode
+
+
+  result = ANode
+  h = 0
+  while n != nil:
+    var x = bSearch[T,D](n, Akey)
+    if x <= 0 :
+      Path[h].Nd = n
+      Path[h].Xi = x
+      inc(h)
+      if x == 0 :
+        n = n.left
+      else :
+        x = (-x)-1
+        if x < n.count :
+          n = n.slots[x].node
+        else :
+          n = nil
+    else :
+      var w = n.slots[x - 1]
+      Oldvalue = w.value
+      w.value = Avalue
+      return
+
+  dec(h)
+  left = nil
+  var lkey = Akey
+  var lvalue = Avalue
+  while h >= 0 :
+    if Path[h].Nd.count < cLenMax :
+      InsertItem(Path[h], n, lkey, lvalue)
+      return
+    else :
+      left = Path[h].Nd
+      n = SplitPage(n, left, Path[h].Xi, lkey, lvalue)
+    dec(h)
+
+  new(result)
+  result.slots.newSeq(cLen1)
+  result.count = 1
+  result.left = left
+  result.slots[0] = setItem(lkey, lvalue, n)
+
+
+proc CleanTree[T,D](n: PNode[T,D]): PNode[T,D] =
+  if n.left != nil :
+    n.left = CleanTree(n.left)
+  for i in 0 .. n.count - 1 :
+    var w = n.slots[i]
+    if w.node != nil :
+        w.node = CleanTree(w.node)
+    clean(w.value)
+    clean(w.key)
+  n.slots = nil
+  return nil
+
+
+proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]): PNode[T,D] {.closure.} ): PNode[T,D] =
+  if n != nil :
+    if n.left != nil :
+      n.left = VisitAllNodes(n.left, visit)
+    for i in 0 .. n.count - 1 :
+      var w = n.slots[i]
+      if w.node != nil :
+        w.node = VisitAllNodes(w.node, visit)
+    return visit(n)
+  return nil
+
+proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]) {.closure.} ) =
+  if n != nil:
+    if n.left != nil :
+      VisitAllNodes(n.left, visit)
+    for i in 0 .. n.count - 1 :
+      var w = n.slots[i]
+      if w.node != nil :
+        VisitAllNodes(w.node, visit)
+    visit(n)
+
+proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: D) {.closure.} ) =
+  if n != nil:
+    if n.left != nil :
+      VisitAll(n.left, visit)
+    for i in 0 .. n.count - 1 :
+      var w = n.slots[i]
+      if not w.isClean :
+        visit(w.key, w.value)
+      if w.node != nil :
+        VisitAll(w.node, visit)
+
+proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: var D):bool {.closure.} ): PNode[T,D] =
+  if n != nil:
+    var n1 = n.left
+    if n1 != nil :
+      var n2 = VisitAll(n1, visit)
+      if n1 != n2 :
+        n.left = n2
+    var i = 0
+    while i < n.count :
+      var w = n.slots[i]
+      if not w.isClean :
+        if visit(w.key, w.value) :
+          result = DeleteItem(n, i)
+          if result == nil : return
+          dec(i)
+      n1 = w.node
+      if n1 != nil :
+        var n2 = VisitAll(n1, visit)
+        if n1 != n2 :
+          w.node = n2
+      inc(i)
+  return n
+
+iterator keys* [T,D] (n: PNode[T,D]): T =
+  if n != nil :
+    var Path: array[0..20, RPath[T,D]]
+    var level = 0
+    var nd = n
+    var i = -1
+    while true :
+      if i < nd.count :
+        Path[level].Nd = nd
+        Path[level].Xi = i
+        if i < 0 :
+          if nd.left != nil :
+            nd = nd.left
+            inc(level)
+          else : inc(i)
+        else :
+          var w = nd.slots[i]
+          if not w.isClean() :
+            yield w.key
+          if w.node != nil :
+            nd = w.node
+            i = -1
+            inc(level)
+          else : inc(i)
+      else :
+        dec(level)
+        if level < 0 : break
+        nd = Path[level].Nd
+        i = Path[level].Xi
+        inc(i)
+
+proc test() =
+  var oldvalue: int
+  var root = internalPut[int, int](nil, 312, 312, oldvalue)
+  var someOtherRoot = internalPut[string, int](nil, "312", 312, oldvalue)
+  var it1 = internalFind(root, 312)
+  echo it1.value
+
+  for i in 1..1_000:
+    root = internalPut(root, i, i, oldvalue)
+
+  var cnt = 0
+  oldvalue = -1
+  when true : # code compiles, when this or the other when is switched to false
+    for k in root.keys :
+      if k <= oldvalue :
+        echo k
+      oldvalue = k
+      inc(cnt)
+    echo cnt
+  when true :
+    cnt = 0
+    VisitAll(root, proc(key, val: int) = inc(cnt))
+    echo cnt
+    when true :
+      root = VisitAll(root, proc(key: int, value: var int): bool =
+        return key mod 2 == 0 )
+    cnt = 0
+    oldvalue = -1
+    VisitAll(root, proc(key: int, value: int) {.closure.} =
+      if key <= oldvalue :
+        echo key
+      oldvalue = key
+      inc(cnt) )
+    echo cnt
+    root = VisitAll(root, proc(key: int, value: var int): bool =
+      return key mod 2 != 0 )
+    cnt = 0
+    oldvalue = -1
+    VisitAll(root, proc(key: int, value: int) {.closure.} =
+      if key <= oldvalue :
+        echo "error ", key
+      oldvalue = key
+      inc(cnt) )
+    echo cnt
+    #traceTree(root)
+
+test()
diff --git a/tests/generics/tgeneric_recursionlimit.nim b/tests/generics/tgeneric_recursionlimit.nim
new file mode 100644
index 000000000..5fe9b43c6
--- /dev/null
+++ b/tests/generics/tgeneric_recursionlimit.nim
@@ -0,0 +1,123 @@
+discard """
+  action: "compile"
+"""
+
+# https://github.com/nim-lang/Nim/issues/20348
+
+type
+  Payload[T] = object
+    payload: T
+  Carrier[T] = object
+    val: T
+
+type
+  Payload0*[T] = object
+    payload: Payload[T]
+  Payload1*[T] = object
+    payload: Payload[T]
+  Payload2*[T] = object
+    payload: Payload[T]
+  Payload3*[T] = object
+    payload: Payload[T]
+  Payload4*[T] = object
+    payload: Payload[T]
+  Payload5*[T] = object
+    payload: Payload[T]
+  Payload6*[T] = object
+    payload: Payload[T]
+  Payload7*[T] = object
+    payload: Payload[T]
+  Payload8*[T] = object
+    payload: Payload[T]
+  Payload9*[T] = object
+    payload: Payload[T]
+  Payload10*[T] = object
+    payload: Payload[T]
+  Payload11*[T] = object
+    payload: Payload[T]
+  Payload12*[T] = object
+    payload: Payload[T]
+  Payload13*[T] = object
+    payload: Payload[T]
+  Payload14*[T] = object
+    payload: Payload[T]
+  Payload15*[T] = object
+    payload: Payload[T]
+  Payload16*[T] = object
+    payload: Payload[T]
+  Payload17*[T] = object
+    payload: Payload[T]
+  Payload18*[T] = object
+    payload: Payload[T]
+  Payload19*[T] = object
+    payload: Payload[T]
+  Payload20*[T] = object
+    payload: Payload[T]
+  Payload21*[T] = object
+    payload: Payload[T]
+  Payload22*[T] = object
+    payload: Payload[T]
+  Payload23*[T] = object
+    payload: Payload[T]
+  Payload24*[T] = object
+    payload: Payload[T]
+  Payload25*[T] = object
+    payload: Payload[T]
+  Payload26*[T] = object
+    payload: Payload[T]
+  Payload27*[T] = object
+    payload: Payload[T]
+  Payload28*[T] = object
+    payload: Payload[T]
+  Payload29*[T] = object
+    payload: Payload[T]
+  Payload30*[T] = object
+    payload: Payload[T]
+  Payload31*[T] = object
+    payload: Payload[T]
+  Payload32*[T] = object
+    payload: Payload[T]
+  Payload33*[T] = object
+    payload: Payload[T]
+
+type
+  Carriers*[T] = object
+    c0*: Carrier[Payload0[T]]
+    c1*: Carrier[Payload1[T]]
+    c2*: Carrier[Payload2[T]]
+    c3*: Carrier[Payload3[T]]
+    c4*: Carrier[Payload4[T]]
+    c5*: Carrier[Payload5[T]]
+    c6*: Carrier[Payload6[T]]
+    c7*: Carrier[Payload7[T]]
+    c8*: Carrier[Payload8[T]]
+    c9*: Carrier[Payload9[T]]
+    c10*: Carrier[Payload10[T]]
+    c11*: Carrier[Payload11[T]]
+    c12*: Carrier[Payload12[T]]
+    c13*: Carrier[Payload13[T]]
+    c14*: Carrier[Payload14[T]]
+    c15*: Carrier[Payload15[T]]
+    c16*: Carrier[Payload16[T]]
+    c17*: Carrier[Payload17[T]]
+    c18*: Carrier[Payload18[T]]
+    c19*: Carrier[Payload19[T]]
+    c20*: Carrier[Payload20[T]]
+    c21*: Carrier[Payload21[T]]
+    c22*: Carrier[Payload22[T]]
+    c23*: Carrier[Payload23[T]]
+    c24*: Carrier[Payload24[T]]
+    c25*: Carrier[Payload25[T]]
+    c26*: Carrier[Payload26[T]]
+    c27*: Carrier[Payload27[T]]
+    c28*: Carrier[Payload28[T]]
+    c29*: Carrier[Payload29[T]]
+    c30*: Carrier[Payload30[T]]
+    c31*: Carrier[Payload31[T]]
+    c32*: Carrier[Payload32[T]]
+    c33*: Carrier[Payload33[T]]
+
+var carriers : Carriers[int]
+
+static:
+  assert $(typeof(carriers.c33.val)) == "Payload33[system.int]"
diff --git a/tests/generics/tgenericdotrettype.nim b/tests/generics/tgenericdotrettype.nim
new file mode 100644
index 000000000..3e4614752
--- /dev/null
+++ b/tests/generics/tgenericdotrettype.nim
@@ -0,0 +1,29 @@
+discard """
+output: '''string
+int
+(int, string)
+'''
+"""
+
+import typetraits
+
+type
+  Foo[T, U] = object
+    x: T
+    y: U
+
+proc bar[T](a: T): T.U =
+  echo result.type.name
+
+proc bas(x: auto): x.T =
+  echo result.type.name
+
+proc baz(x: Foo): (Foo.T, x.U) =
+  echo result.type.name
+
+var
+  f: Foo[int, string]
+  x = bar f
+  z = bas f
+  y = baz f
+
diff --git a/tests/generics/tgenericlambda.nim b/tests/generics/tgenericlambda.nim
new file mode 100644
index 000000000..41ee74557
--- /dev/null
+++ b/tests/generics/tgenericlambda.nim
@@ -0,0 +1,23 @@
+discard """
+  output: "10\n10\n1\n2\n3\n15"
+"""
+
+proc test(x: proc (a, b: int): int) =
+  echo x(5, 5)
+
+test(proc (a, b: auto): auto = a + b)
+
+test do (a, b: auto) -> auto: a + b
+
+proc foreach[T](s: seq[T], body: proc(x: T)) =
+  for e in s:
+    body(e)
+
+foreach(@[1,2,3]) do (x: auto):
+  echo x
+
+proc foo =
+  let x = proc (a, b: int): auto = a + b
+  echo x(5, 10)
+
+foo()
diff --git a/tests/generics/tgenericmatcher.nim b/tests/generics/tgenericmatcher.nim
new file mode 100644
index 000000000..ca4dc2a4d
--- /dev/null
+++ b/tests/generics/tgenericmatcher.nim
@@ -0,0 +1,40 @@
+discard """
+  output: '''
+'''
+"""
+
+
+block tmatcher1:
+  type
+    TMatcherKind = enum
+      mkTerminal, mkSequence, mkAlternation, mkRepeat
+    TMatcher[T] = object
+      case kind: TMatcherKind
+      of mkTerminal:
+        value: T
+      of mkSequence, mkAlternation:
+        matchers: seq[TMatcher[T]]
+      of mkRepeat:
+        matcher: PMatcher[T]
+        min, max: int
+    PMatcher[T] = ref TMatcher[T]
+
+  var m: PMatcher[int]
+
+
+block tmatcher2:
+  type
+    TMatcherKind = enum
+      mkTerminal, mkSequence, mkAlternation, mkRepeat
+    TMatcher[T] = object
+      case kind: TMatcherKind
+      of mkTerminal:
+        value: T
+      of mkSequence, mkAlternation:
+        matchers: seq[TMatcher[T]]
+      of mkRepeat:
+        matcher: ref TMatcher[T]
+        min, max: int
+  
+  var m: ref TMatcher[int]
+
diff --git a/tests/generics/tgenericprocvar.nim b/tests/generics/tgenericprocvar.nim
new file mode 100644
index 000000000..7935d90c2
--- /dev/null
+++ b/tests/generics/tgenericprocvar.nim
@@ -0,0 +1,37 @@
+discard """
+  output: "0false12"
+"""
+
+# Test multiple generic instantiation of generic proc vars:
+
+proc threadProcWrapper[TMsg]() =
+  var x: TMsg
+  stdout.write($x)
+
+#var x = threadProcWrapper[int]
+#x()
+
+#var y = threadProcWrapper[bool]
+#y()
+
+threadProcWrapper[int]()
+threadProcWrapper[bool]()
+
+type
+  TFilterProc[T,D] = proc (item: T, env:D): bool {.nimcall.}
+
+proc filter[T,D](data: seq[T], env:D, pred: TFilterProc[T,D]): seq[T] =
+  result = @[]
+  for e in data:
+    if pred(e, env): result.add(e)
+
+proc predTest(item: int, value: int): bool =
+  return item <= value
+
+proc test(data: seq[int], value: int): seq[int] =
+  return filter(data, value, predTest)
+
+for x in items(test(@[1,2,3], 2)):
+  stdout.write(x)
+
+stdout.write "\n"
diff --git a/tests/generics/tgenerics_issues.nim b/tests/generics/tgenerics_issues.nim
new file mode 100644
index 000000000..3068a22f2
--- /dev/null
+++ b/tests/generics/tgenerics_issues.nim
@@ -0,0 +1,894 @@
+discard """
+  output: '''
+4
+3
+(weight: 17.0, color: 100)
+perm: 22 det: 22
+TMatrix[3, 3, system.int]
+3
+@[0.9, 0.1]
+U[3]
+U[(f: 3)]
+U[[3]]
+b()
+@[1, 2]
+@[3, 4]
+1
+concrete 88
+123
+1
+2
+3
+!!Hi!!
+G:0,1:0.1
+G:0,1:0.1
+H:1:0.1
+0
+(foo: none(seq[Foo]), s: "")
+(foo: some(@[(a: "world", bar: none(Bar))]), s: "hello,")
+@[(a: "hey", bar: none(Bar))]
+'''
+joinable: false
+"""
+
+import macros, sequtils, sets, sugar, tables, typetraits
+
+block t88:
+  type
+    BaseClass[V] = object of RootObj
+      b: V
+
+  proc new[V](t: typedesc[BaseClass], v: V): BaseClass[V] =
+    BaseClass[V](b: v)
+
+  proc baseMethod[V](v: BaseClass[V]): V = v.b
+  proc overriddenMethod[V](v: BaseClass[V]): V = v.baseMethod
+
+  type
+    ChildClass[V] = object of BaseClass[V]
+      c: V
+
+  proc new[V](t: typedesc[ChildClass], v1, v2: V): ChildClass[V] =
+    ChildClass[V](b: v1, c: v2)
+
+  proc overriddenMethod[V](v: ChildClass[V]): V = v.c
+
+  let c = ChildClass[string].new("Base", "Child")
+
+  doAssert c.baseMethod == "Base"
+  doAssert c.overriddenMethod == "Child"
+
+
+
+block t4528:
+  type GenericBase[T] = ref object of RootObj
+  type GenericSubclass[T] = ref object of GenericBase[T]
+  proc foo[T](g: GenericBase[T]) = discard
+  var bar: GenericSubclass[int]
+  foo(bar)
+
+
+
+block t1050_5597:
+  type ArrayType[T] = distinct T
+
+  proc arrayItem(a: ArrayType): auto =
+    static: echo(name(type(a).T))
+    result = (type(a).T)(4)
+
+  var arr: ArrayType[int]
+  echo arrayItem(arr)
+
+  # bug #5597
+
+  template fail() = "what"
+
+  proc g[T](x: var T) =
+    x.fail = 3
+
+  type
+    Obj = object
+      fail: int
+
+  var y: Obj
+  g y
+
+
+
+block t1789:
+  type
+    Foo[N: static[int]] = object
+
+  proc bindStaticN[N](foo: Foo[N]) =
+    var ar0: array[3, int]
+    var ar1: array[N, int]
+    var ar2: array[1..N, int]
+    var ar3: array[0..(N+10), float]
+    echo N
+
+  var f: Foo[3]
+  f.bindStaticN
+
+  # case 2
+
+  type
+    ObjectWithStatic[X, Y: static[int], T] = object
+      bar: array[X * Y, T]   # this one works
+
+    AliasWithStatic[X, Y: static[int], T] = array[X * Y, T]
+
+  var
+    x: ObjectWithStatic[1, 2, int]
+    y: AliasWithStatic[2, 3, int]
+
+  # case 3
+
+  type
+    Bar[N: static[int], T] = object
+      bar: array[N, T]
+
+  proc `[]`[N, T](f: Bar[N, T], n: range[0..(N - 1)]): T =
+    doAssert high(n) == N-1
+    result = f.bar[n]
+
+  var b: Bar[3, int]
+  doAssert b[2] == 0
+
+
+
+block t3977:
+  type Foo[N: static[int]] = object
+
+  proc foo[N](x: Foo[N]) =
+    let n = N
+    doAssert N == n
+
+  var f1: Foo[42]
+  f1.foo
+
+
+
+block t5570:
+  type
+    BaseFruit[T] = object of RootObj
+      color: T
+
+    Banana[T] = object of BaseFruit[uint32]
+      weight: T
+
+  macro printTypeName(typ: typed): untyped =
+    echo "type ", getType(typ).repr
+
+  proc setColor[K](self: var BaseFruit[K], c: int) =
+    printTypeName(self.color)
+    self.color = uint32(c)
+
+  var x: Banana[float64]
+  x.weight = 17
+  printTypeName(x.color)
+  x.setColor(100)
+  echo x
+
+
+
+block t5643:
+  type
+    Matrix[M, N: static[int], T: SomeFloat] = object
+      data: ref array[N * M, T]
+    Matrix64[M, N: static[int]] = Matrix[M, N, float64]
+
+  proc zeros64(M,N: static[int]): Matrix64[M,N] =
+    new result.data
+    for i in 0 ..< (M * N):
+      result.data[i] = 0'f64
+
+  proc bar[M,N: static[int], T](a: Matrix[M,N,T], b: Matrix[M,N,T]) =
+    discard
+
+  let a = zeros64(2,2)
+  bar(a,a)
+    # https://github.com/nim-lang/Nim/issues/5643
+    #
+    # The test case was failing here, because the compiler failed to
+    # detect the two matrix instantiations as the same type.
+    #
+    # The root cause was that the `T` type variable is a different
+    # type after the first Matrix type has been matched.
+    #
+    # Sigmatch was failing to match the second version of `T`, but
+    # due to some complex interplay between tyOr, tyTypeDesc and
+    # tyGenericParam this was allowed to went through. The generic
+    # instantiation of the second matrix was incomplete and the
+    # generic cache lookup failed, producing two separate types.
+
+
+
+block t5683:
+  type Matrix[M,N: static[int]] = array[M, array[N, float]]
+
+  proc det[M,N](a: Matrix[M,N]): int = N*10 + M
+  proc perm[M,N](a: Matrix[M,N]): int = M*10 + N
+
+  const
+    a = [ [1.0, 2.0]
+        , [3.0, 4.0]
+        ]
+
+  echo "perm: ", a.perm, " det: ", a.det
+
+  # This tests multiple instantiations of a generic
+  # proc involving static params:
+  type
+    Vector64[N: static[int]] = ref array[N, float64]
+    Array64[N: static[int]] = array[N, float64]
+
+  proc vector[N: static[int]](xs: Array64[N]): Vector64[N] =
+    new result
+    for i in 0 ..< N:
+      result[i] = xs[i]
+
+  let v1 = vector([1.0, 2.0, 3.0, 4.0, 5.0])
+  let v2 = vector([1.0, 2.0, 3.0, 4.0, 5.0])
+  let v3 = vector([1.0, 2.0, 3.0, 4.0])
+
+
+
+block t7794:
+  type
+    Data[T:SomeNumber, U:SomeFloat] = ref object
+      x: T
+      value*: U
+
+  var d = Data[int, float64](x:10.int, value:2'f64)
+  doAssert d.x == 10
+  doAssert d.value == 2.0
+
+
+
+block t8403:
+  proc sum[T](s: seq[T], R: typedesc): R =
+    var sum: R = 0
+    for x in s:
+      sum += R(x)
+    return sum
+
+  doAssert @[1, 2, 3].sum(float) == 6.0
+
+
+
+block t8439:
+  type
+    Cardinal = enum
+      north, east, south, west
+
+  proc foo[cardinal: static[Cardinal]](): int = 1
+  doAssert foo[north]() == 1
+
+
+
+block t8694:
+  when true:
+    # Error: undeclared identifier: '|'
+    proc bar[T](t:T): bool =
+      runnableExamples:
+        type Foo = int | float
+      true
+    doAssert bar(0)
+
+  when true:
+    # ok
+    proc bar(t:int): bool =
+      runnableExamples:
+        type Foo = int | float
+      true
+    doAssert bar(0)
+
+  when true:
+    # Error: undeclared identifier: '|'
+    proc bar(t:typedesc): bool =
+      runnableExamples:
+        type Foo = int | float
+      true
+    doAssert bar(int)
+
+
+
+block t9130:
+  when true:
+    # stack overflow
+    template baz1(iter: untyped): untyped =
+      runnableExamples:
+        import sugar
+        proc fun(a: proc(x:int): int) = discard
+        baz1(fun(x:int => x))
+      discard
+
+    proc foo1[A](ts: A) =
+      baz1(ts)
+
+  when true:
+    # ok
+    template baz2(iter: untyped): untyped =
+      runnableExamples:
+        import sugar
+        proc fun(a: proc(x:int): int) = discard
+        baz2(fun(x:int => x))
+      discard
+
+    proc foo2(ts: int) =
+      baz2(ts)
+
+  when true:
+    # stack overflow
+    template baz3(iter: untyped): untyped =
+      runnableExamples:
+        baz3(fun(x:int => x))
+      discard
+
+    proc foo3[A](ts: A) =
+      baz3(ts)
+
+
+
+block t1056:
+  type
+    TMatrix[N,M: static[int], T] = object
+      data: array[0..N*M-1, T]
+
+    TMat2[T] = TMatrix[2,2,T]
+
+  proc echoMatrix(a: TMatrix) =
+    echo a.type.name
+    echo TMatrix.N
+
+  proc echoMat2(a: TMat2) =
+    echo TMat2.M
+
+  var m = TMatrix[3,3,int](data: [1,2,3,4,5,6,7,8,9])
+
+  echoMatrix m
+
+
+
+block t4884:
+  type
+    Vec[N: static[int], T] = object
+      arr*: array[N, T]
+
+    Mat[N,M: static[int], T] = object
+      arr: array[N, Vec[M,T]]
+
+  var m : Mat[3,3,float]
+  var strMat : Mat[m.N, m.M, string]
+  var lenMat : Mat[m.N, m.M, int]
+
+
+
+block t2221:
+  var tblo: TableRef[string, int]
+  doAssert tblo == nil
+
+
+
+block t2304:
+  type TV2[T:SomeNumber] = array[0..1, T]
+  proc newV2T[T](x, y: T=0): TV2[T] = [x, y]
+
+  let x = newV2T[float](0.9, 0.1)
+  echo(@x)
+
+
+
+block t2752:
+  proc myFilter[T](it: (iterator(): T), f: (proc(anything: T):bool)): (iterator(): T) =
+    iterator aNameWhichWillConflict(): T {.closure.}=
+      for x in it():
+        if f(x):
+          yield x
+    result = aNameWhichWillConflict
+
+  iterator testIt():int {.closure.}=
+    yield -1
+    yield 2
+
+  #let unusedVariable = myFilter(testIt, (x: int) => x > 0)
+
+  proc onlyPos(it: (iterator(): int)): (iterator(): int)=
+    iterator aNameWhichWillConflict(): int {.closure.}=
+      var filtered = onlyPos(myFilter(it, (x:int) => x > 0))
+      for x in filtered():
+        yield x
+    result = aNameWhichWillConflict
+
+  let x = onlyPos(testIt)
+
+
+
+block t5106:
+  block:
+    type T = distinct int
+
+    proc `+`(a, b: T): T =
+      T(int(a) + int(b))
+
+    type U[F: static[T]] = distinct int
+
+    proc `+`[P1, P2: static[T]](a: U[P1], b: U[P2]): U[P1 + P2] =
+      U[P1 + P2](int(a) + int(b))
+
+    var a = U[T(1)](1)
+    var b = U[T(2)](2)
+    var c = a + b
+    echo c.type.name
+
+  block:
+    type T = object
+      f: int
+
+    proc `+`(a, b: T): T =
+      T(f: a.f + b.f)
+
+    type U[F: static[T]] = distinct int
+
+    proc `+`[P1, P2: static[T]](a: U[P1], b: U[P2]): U[P1 + P2] =
+      U[P1 + P2](int(a) + int(b))
+
+    var a = U[T(f: 1)](1)
+    var b = U[T(f: 2)](2)
+    var c = a + b
+    echo c.type.name
+
+  block:
+    type T = distinct array[0..0, int]
+
+    proc `+`(a, b: T): T =
+      T([array[0..0, int](a)[0] + array[0..0, int](b)[0]])
+
+    type U[F: static[T]] = distinct int
+
+    proc `+`[P1, P2: static[T]](a: U[P1], b: U[P2]): U[P1 + P2] =
+      U[P1 + P2](int(a) + int(b))
+
+    var a = U[T([1])](1)
+    var b = U[T([2])](2)
+    var c = a + b
+    echo c.type.name
+
+
+
+block t3055:
+  proc b(t: int | string)
+  proc a(t: int) = b(t)
+  proc b(t: int | string) = echo "b()"
+  a(1)
+
+  # test recursive generics still work:
+  proc fac[T](x: T): T =
+    if x == 0: return 1
+    else: return fac(x-1)*x
+
+  doAssert fac(6) == 720
+  doAssert fac(5.0) == 120.0
+
+
+  # test recursive generic with forwarding:
+  proc fac2[T](x: T): T
+
+  doAssert fac2(6) == 720
+  doAssert fac2(5.0) == 120.0
+
+  proc fac2[T](x: T): T =
+    if x == 0: return 1
+    else: return fac2(x-1)*x
+
+
+
+block t1187:
+  type
+    TEventArgs = object
+      skip: bool
+    TEventHandler[T] = proc (e: var TEventArgs, data: T) {.closure.}
+    TEvent[T] = object
+      #handlers: seq[TEventHandler[T]] # Does not work
+      handlers: seq[proc (e: var TEventArgs, d: T) {.closure.}] # works
+
+    TData = object
+      x: int
+
+    TSomething = object
+      s: TEvent[TData]
+
+  proc init[T](e: var TEvent[T]) =
+    e.handlers.newSeq(0)
+
+  #proc add*[T](e: var TEvent[T], h: proc (e: var TEventArgs, data: T) {.closure.}) =
+  # this line works
+  proc add[T](e: var TEvent[T], h: TEventHandler[T]) =
+    # this line does not work
+    e.handlers.add(h)
+
+  proc main () =
+    var something: TSomething
+    something.s.init()
+    var fromOutside = 4711
+
+    something.s.add() do (e: var TEventArgs, data: TData):
+      var x = data.x
+      x = fromOutside
+
+  main()
+
+
+
+block t1919:
+  type
+    Base[M] = object of RootObj
+      a : M
+    Sub1[M] = object of Base[M]
+      b : int
+    Sub2[M] = object of Sub1[M]
+      c : int
+
+  var x: Sub2[float]
+  doAssert x.a == 0.0
+
+
+
+block t5756:
+  type
+    Vec[N : static[int]] = object
+      x: int
+      arr: array[N, int32]
+
+    Mat[M,N: static[int]] = object
+      x: int
+      arr: array[M, Vec[N]]
+
+  proc vec2(x,y:int32) : Vec[2] =
+    result.arr = [x,y]
+    result.x = 10
+
+  proc mat2(a,b: Vec[2]): Mat[2,2] =
+    result.arr = [a,b]
+    result.x = 20
+
+  const M = mat2(vec2(1, 2), vec2(3, 4))
+
+  let m1 = M
+  echo @(m1.arr[0].arr)
+  echo @(m1.arr[1].arr)
+
+  proc foo =
+    let m2 = M
+    echo m1.arr[0].arr[0]
+
+  foo()
+
+
+
+block t7854:
+  type
+    Stream = ref StreamObj
+    StreamObj = object of RootObj
+
+    InhStream = ref InhStreamObj
+    InhStreamObj = object of Stream
+      f: string
+
+  proc newInhStream(f: string): InhStream =
+    new(result)
+    result.f = f
+
+  var val: int
+  let str = newInhStream("input_file.json")
+
+  block:
+    # works:
+    proc load[T](data: var T, s: Stream) =
+      discard
+    load(val, str)
+
+  block:
+    # works
+    proc load[T](s: Stream, data: T) =
+      discard
+    load(str, val)
+
+  block:
+    # broken
+    proc load[T](s: Stream, data: var T) =
+      discard
+    load(str, val)
+
+
+
+block t5864:
+  proc defaultStatic(s: openArray, N: static[int] = 1): int = N
+  proc defaultGeneric[T](a: T = 2): int = a
+
+  let a = [1, 2, 3, 4].defaultStatic()
+  let b = defaultGeneric()
+
+  doAssert a == 1
+  doAssert b == 2
+
+
+
+block t3498:
+  template defaultOf[T](t: T): untyped = (var d: T; d)
+
+  doAssert defaultOf(1) == 0
+
+  # assignment using template
+
+  template tassign[T](x: var seq[T]) =
+    x = @[1, 2, 3]
+
+  var y: seq[int]
+  tassign(y) #<- x is expected = @[1, 2, 3]
+  tassign(y)
+
+  doAssert y[0] == 1
+  doAssert y[1] == 2
+  doAssert y[2] == 3
+
+
+
+block t3499:
+  proc foo[T](x: proc(): T) =
+    echo "generic ", x()
+
+  proc foo(x: proc(): int) =
+    echo "concrete ", x()
+
+  # note the following 'proc' is not .closure!
+  foo(proc (): auto {.nimcall.} = 88)
+
+  # bug #3499 last snippet fixed
+  # bug 705  last snippet fixed
+
+
+
+
+block t797:
+  proc foo[T](s:T):string = $s
+
+  type IntStringProc = proc(x: int): string
+
+  var f1 = IntStringProc(foo)
+  var f2: proc(x: int): string = foo
+  var f3: IntStringProc = foo
+
+  echo f1(1), f2(2), f3(3)
+
+  for x in map([1,2,3], foo): echo x
+
+
+
+block t4658:
+  var x = 123
+  proc twice[T](f: T -> T): T -> T = (x: T) => f(f(x))
+  proc quote(s: string): string = "!" & s & "!"
+  echo twice(quote)("Hi")
+
+
+
+block t4589:
+  type SimpleTable[TKey, TVal] = TableRef[TKey, TVal]
+  template newSimpleTable(TKey, TVal: typedesc): SimpleTable[TKey, TVal] = newTable[TKey, TVal]()
+  var fontCache : SimpleTable[string, SimpleTable[int32, int]]
+  fontCache = newSimpleTable(string, SimpleTable[int32, int])
+
+
+
+block t4600:
+  template foo(x: untyped): untyped = echo 1
+  template foo(x,y: untyped): untyped = echo 2
+
+  proc bar1[T](x: T) = foo(x)
+  proc bar2(x: float) = foo(x,x)
+  proc bar3[T](x: T) = foo(x,x)
+
+
+
+block t4672:
+  type
+    EnumContainer[T: enum] = object
+      v: T
+    SomeEnum {.pure.} = enum
+      A,B,C
+
+  proc value[T: enum](this: EnumContainer[T]): T =
+    this.v
+
+  var enumContainer: EnumContainer[SomeEnum]
+  discard enumContainer.value()
+
+
+
+block t4863:
+  type
+    G[i,j: static[int]] = object
+      v:float
+    H[j: static[int]] = G[0,j]
+  proc p[i,j: static[int]](x:G[i,j]) = echo "G:", i, ",", j, ":", x.v
+  proc q[j: static[int]](x:H[j]) = echo "H:", j, ":", x.v
+
+  var
+    g0 = G[0,1](v: 0.1)
+    h0:H[1] = g0
+  p(g0)
+  p(h0)
+  q(h0)
+
+
+
+block t1684:
+  type
+    BaseType {.inheritable pure.} = object
+      idx: int
+
+    DerivedType {.final pure.} = object of BaseType
+
+  proc index[Toohoo: BaseType](h: Toohoo): int {.inline.} = h.idx
+  proc newDerived(idx: int): DerivedType {.inline.} = DerivedType(idx: idx)
+
+  let d = newDerived(2)
+  doAssert(d.index == 2)
+
+
+
+block t5632:
+  type Option[T] = object
+
+  proc point[A](v: A, t: typedesc[Option[A]]): Option[A] =
+    discard
+
+  discard point(1, Option)
+
+
+
+block t7247:
+  type n8 = range[0'i8..127'i8]
+  var tab = initHashSet[n8]()
+  doAssert tab.contains(8) == false
+
+
+
+block t3717:
+  type
+    Foo[T] = object
+      a: T
+    Foo1[T] = Foo[T] | int
+
+  proc foo[T](s: Foo1[Foo[T]]): T =
+    5
+
+  var f: Foo[Foo[int]]
+  discard foo(f)
+
+
+
+block: # issue #9458
+  type
+    Option[T] = object
+      val: T
+      has: bool
+
+    Bar = object
+
+  proc none(T: typedesc): Option[T] =
+    discard
+
+  proc foo[T](self: T; x: Option[Bar] = Bar.none) =
+    discard
+
+  foo(1)
+
+
+# bug #8426
+type
+  MyBool[T: uint] = range[T(0)..T(1)] # Works
+
+var x: MyBool[uint]
+echo x
+
+# x = 2 # correctly prevented
+
+type
+  MyBool2 = range[uint(0)..uint(1)] # Error ordinal or float type expected
+
+
+# bug #10396
+import options, strutils
+
+type
+  Foo {.acyclic.} = object
+    a: string
+    bar: Option[Bar]
+
+  Bar {.acyclic.} = object
+    foo: Option[seq[Foo]]   # if this was just Option[Foo], everything works fine
+    s: string
+
+proc getBar(x: string): Bar
+
+proc intoFoos(ss: seq[string]): seq[Foo] =
+  result = @[]
+  for s in ss:
+    let spl = s.split(',')
+    if spl.len > 1:
+      result.add Foo(a: spl[0],
+                     bar: some(getBar(spl[1])))
+    else:
+      result.add Foo(a: s,
+                     bar: none[Bar]())
+
+proc getBar(x: string): Bar =
+  let spl = x.split(' ')
+  result =
+    if spl.len > 1:
+      Bar(foo: some(spl[1..high(spl)].intoFoos),
+          s: spl[0])
+    else:
+      Bar(foo: none[seq[Foo]](),
+          s: "")
+
+proc fakeReadLine(): string = "hey"
+
+echo getBar(fakeReadLine()) # causes error
+
+echo getBar("hello, world") # causes error
+
+discard $getBar(fakeReadLine()) # causes error
+
+discard $getBar("hello, world") # causes error
+
+discard getBar(fakeReadLine()) # no error
+
+discard getBar("hello, world") # no error
+
+echo intoFoos(fakeReadLine().split(' ')) # no error, works as expected
+
+
+# bug #14990
+type
+  Tile3 = Tile2
+  Tile2 = Tile
+  Tile[n] = object
+    a: n
+
+var a: Tile3[int]
+
+block: # Ensure no segfault from constraint
+  type
+    Regex[A: SomeOrdinal] = ref object
+      val: Regex[A]
+    MyConstraint = (seq or enum or set)
+    MyOtherType[A: MyConstraint] = ref object
+      val: MyOtherType[A]
+
+  var
+    a = Regex[int]()
+    b = Regex[bool]()
+    c = MyOtherType[seq[int]]()
+
+block: # https://github.com/nim-lang/Nim/issues/20416
+  type
+    Item[T] = object
+      link:ptr Item[T]
+      data:T
+
+    KVSeq[A,B] = seq[(A,B)]
+
+    MyTable[A,B] = object
+      data: KVSeq[A,B]
+
+    Container[T] = object
+      a: MyTable[int,ref Item[T]]
+
+  proc p1(sg:Container) = discard # Make sure that a non parameterized 'Container' argument still compiles
+
+  proc p2[T](sg:Container[T]) = discard
+  var v : Container[int]
+  p2(v)
diff --git a/tests/generics/tgenerics_various.nim b/tests/generics/tgenerics_various.nim
new file mode 100644
index 000000000..53661236e
--- /dev/null
+++ b/tests/generics/tgenerics_various.nim
@@ -0,0 +1,254 @@
+discard """
+  output: '''
+we
+direct
+generic
+generic
+'''
+joinable: false
+"""
+
+import algorithm, sugar, sequtils, typetraits, asyncdispatch
+
+block tconfusing_arrow:
+  type Deck = object
+    value: int
+
+  proc sort(h: var seq[Deck]) =
+    # works:
+    h.sort(proc (x, y: Deck): auto =
+      cmp(x.value, y.value))
+    # fails:
+    h.sort((x, y: Deck) => cmp(ord(x.value), ord(y.value)))
+
+  var player: seq[Deck] = @[]
+  player.sort()
+
+
+
+block tdictdestruct:
+  type
+    TDict[TK, TV] = object
+      k: TK
+      v: TV
+    PDict[TK, TV] = ref TDict[TK, TV]
+
+  proc fakeNew[T](x: var ref T, destroy: proc (a: ref T) {.nimcall.}) =
+    discard
+
+  proc destroyDict[TK, TV](a: PDict[TK, TV]) =
+      return
+  proc newDict[TK, TV](a: TK, b: TV): PDict[TK, TV] =
+      fakeNew(result, destroyDict[TK, TV])
+
+  # Problem: destroyDict is not instantiated when newDict is instantiated!
+  discard newDict("a", "b")
+
+
+
+block tgenericdefaults:
+  type
+    TFoo[T, U, R = int] = object
+      x: T
+      y: U
+      z: R
+
+    TBar[T] = TFoo[T, array[4, T], T]
+
+  var x1: TFoo[int, float]
+
+  static:
+    doAssert type(x1.x) is int
+    doAssert type(x1.y) is float
+    doAssert type(x1.z) is int
+
+  var x2: TFoo[string, R = float, U = seq[int]]
+
+  static:
+    doAssert type(x2.x) is string
+    doAssert type(x2.y) is seq[int]
+    doAssert type(x2.z) is float
+
+  var x3: TBar[float]
+
+  static:
+    doAssert type(x3.x) is float
+    doAssert type(x3.y) is array[4, float]
+    doAssert type(x3.z) is float
+
+
+
+block tprop:
+  type
+    TProperty[T] = object of RootObj
+      getProc: proc(property: TProperty[T]): T {.nimcall.}
+      setProc: proc(property: TProperty[T], value: T) {.nimcall.}
+      value: T
+
+  proc newProperty[T](value: RootObj): TProperty[T] =
+    result.getProc = proc (property: TProperty[T]) =
+      return property.value
+
+
+
+block trefs:
+  type
+    PA[T] = ref TA[T]
+    TA[T] = object
+      field: T
+  var a: PA[string]
+  new(a)
+  a.field = "some string"
+
+  proc someOther[T](len: string): seq[T] = discard
+  proc someOther[T](len: int): seq[T] = echo "we"
+
+  proc foo[T](x: T) =
+    var s = someOther[T](34)
+    #newSeq[T](34)
+
+  foo 23
+
+  when false:
+    # Compiles unless you use var a: PA[string]
+    type
+      PA = ref TA
+      TA[T] = object
+
+    # Cannot instantiate:
+    type
+      TA[T] = object
+        a: PA[T]
+      PA[T] = ref TA[T]
+
+    type
+      PA[T] = ref TA[T]
+      TA[T] = object
+
+
+
+block tmap_auto:
+  let x = map(@[1, 2, 3], x => x+10)
+  doAssert x == @[11, 12, 13]
+
+  let y = map(@[(1,"a"), (2,"b"), (3,"c")], x => $x[0] & x[1])
+  doAssert y == @["1a", "2b", "3c"]
+
+  proc eatsTwoArgProc[T,S,U](a: T, b: S, f: proc(t: T, s: S): U): U =
+    f(a,b)
+
+  let z = eatsTwoArgProc(1, "a", (t,s) => $t & s)
+  doAssert z == "1a"
+
+
+
+block tproctypecache_falsepositive:
+  type
+    Callback = proc() {.closure, gcsafe.}
+    GameState = ref object
+      playerChangeHandlers: seq[Callback]
+
+  proc newGameState(): GameState =
+    result = GameState(
+      playerChangeHandlers: newSeq[Callback]() # this fails
+    )
+
+
+
+block tptrinheritance:
+  type NSPasteboardItem = ptr object
+  type NSPasteboard = ptr object
+  type NSArrayAbstract {.inheritable.} = ptr object
+  type NSMutableArrayAbstract = ptr object of NSArrayAbstract
+  type NSArray[T] = ptr object of NSArrayAbstract
+  type NSMutableArray[T] = ptr object of NSArray[T]
+
+  proc newMutableArrayAbstract(): NSMutableArrayAbstract = discard
+
+  template newMutableArray(T: typedesc): NSMutableArray[T] =
+    cast[NSMutableArray[T]](newMutableArrayAbstract())
+
+  proc writeObjects(p: NSPasteboard, o: NSArray[NSPasteboardItem]) = discard
+
+  let a = newMutableArray NSPasteboardItem
+  var x: NSMutableArray[NSPasteboardItem]
+  var y: NSArray[NSPasteboardItem] = x
+
+  writeObjects(nil, a)
+
+
+
+block tsigtypeop:
+  type Vec3[T] = array[3, T]
+
+  proc foo(x: Vec3, y: Vec3.T, z: x.T): x.type.T =
+    return 10
+
+  var y: Vec3[int] = [1, 2, 3]
+  var z: int = foo(y, 3, 4)
+
+
+
+block tvarargs_vs_generics:
+  proc withDirectType(args: string) =
+    echo "direct"
+  proc withDirectType[T](arg: T) =
+    echo "generic"
+  proc withOpenArray(args: openArray[string]) =
+    echo "openArray"
+  proc withOpenArray[T](arg: T) =
+    echo "generic"
+  proc withVarargs(args: varargs[string]) =
+    echo "varargs"
+  proc withVarargs[T](arg: T) =
+    echo "generic"
+
+  withDirectType "string"
+  withOpenArray "string"
+  withVarargs "string"
+
+block:
+  type
+    Que[T] {.gcsafe.} = object
+      x: T
+
+  proc `=`[T](q: var Que[T]; x: Que[T]) =
+    discard
+
+  var x: Que[int]
+  doAssert(x.x == 0)
+
+
+# bug #4466
+proc identity[T](t: T): T = t
+
+proc doSomething[A, B](t: tuple[a: A, b: B]) = discard
+
+discard identity((c: 1, d: 2))
+doSomething(identity((1, 2)))
+
+# bug #6231
+proc myProc[T, U](x: T or U) = discard
+
+myProc[int, string](x = 2)
+
+block: # issue #8390
+  proc x[T:SomeFloat](q: openarray[T], y: T = 1): string =
+    doAssert $q.type == $openarray[y.type]
+    $y.type
+
+  doAssert x(@[1.0]) == $1.0.type
+
+
+block: # issue #9381
+  var evalCount {.compileTime.} = 0
+
+  macro test(t: typed): untyped =
+    inc evalCount
+    t
+
+  type GenericObj[T] = object
+    f: test(T)
+
+  var x: GenericObj[int]
+  static: doAssert evalCount == 1
diff --git a/tests/generics/tgenerictmpl2.nim b/tests/generics/tgenerictmpl2.nim
new file mode 100644
index 000000000..2efb000b3
--- /dev/null
+++ b/tests/generics/tgenerictmpl2.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''1
+1
+1
+1
+999
+999
+999
+2'''
+"""
+
+# test if we can pass explicit generic arguments to generic templates
+# based on bug report #3496
+
+proc     tproc[T](t: T = 999) = echo t
+template ttmpl[T](t: T = 999) = echo t
+
+tproc(1)
+tproc[int](1)
+ttmpl(1)
+ttmpl[int](1) #<- crash case #1
+
+tproc[int]()
+let _ = tproc[int]
+ttmpl[int]()  #<- crash case #2
+ttmpl[int]    #<- crash case #3
+
+# but still allow normal use of [] on non-generic templates
+
+template tarr: untyped = [1, 2, 3, 4]
+echo tarr[1]
diff --git a/tests/generics/tgenericvariant.nim b/tests/generics/tgenericvariant.nim
new file mode 100644
index 000000000..5ba3a2e7c
--- /dev/null
+++ b/tests/generics/tgenericvariant.nim
@@ -0,0 +1,36 @@
+discard """
+output: '''
+Test
+abcxyz123
+'''
+"""
+
+proc fakeReadLine(): string =
+  "abcxyz123"
+
+type
+  TMaybe[T] = object
+    case empty: bool
+    of false: value: T
+    else: nil
+
+proc Just*[T](val: T): TMaybe[T] =
+  result.empty = false
+  result.value = val
+
+proc Nothing[T](): TMaybe[T] =
+  result.empty = true
+
+proc safeReadLine(): TMaybe[string] =
+  var r = fakeReadLine()
+  if r == "": return Nothing[string]()
+  else: return Just(r)
+
+proc main() =
+  var Test = Just("Test")
+  echo(Test.value)
+  var mSomething = safeReadLine()
+  echo(mSomething.value)
+  mSomething = safeReadLine()
+
+main()
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/timpl_ast.nim b/tests/generics/timpl_ast.nim
new file mode 100644
index 000000000..97fe128cd
--- /dev/null
+++ b/tests/generics/timpl_ast.nim
@@ -0,0 +1,80 @@
+import std/macros
+import std/assertions
+
+block: # issue #16639
+  type Foo[T] = object
+    when true:
+      x: float
+
+  type Bar = object
+    when true:
+      x: float
+
+  macro test() =
+    let a = getImpl(bindSym"Foo")[^1]
+    let b = getImpl(bindSym"Bar")[^1]
+    doAssert treeRepr(a) == treeRepr(b)
+
+  test()
+
+import strutils
+
+block: # issues #9899, ##14708
+  macro implRepr(a: typed): string =
+    result = newLit(repr(a.getImpl))
+
+  type
+    Option[T] = object
+      when false: discard # issue #14708
+      when false: x: int
+      when T is (ref | ptr):
+        val: T
+      else:
+        val: T
+        has: bool
+
+  static: # check information is retained
+    let r = implRepr(Option)
+    doAssert "when T is" in r
+    doAssert r.count("val: T") == 2
+    doAssert "has: bool" in r
+
+  block: # try to compile the output
+    macro parse(s: static string) =
+      result = parseStmt(s)
+    parse("type " & implRepr(Option))
+
+block: # issue #22639
+  type
+    Spectrum[N: static int] = object
+      data: array[N, float]
+    AngleInterpolator = object
+      data: seq[Spectrum[60]]
+  proc initInterpolator(num: int): AngleInterpolator =
+    result = AngleInterpolator()
+    for i in 0 ..< num:
+      result.data.add Spectrum[60]()
+  macro genCompatibleTuple(t: typed): untyped =
+    let typ = t.getType[1].getTypeImpl[2]
+    result = nnkTupleTy.newTree()
+    for i, ch in typ: # is `nnkObjectTy`
+      result.add nnkIdentDefs.newTree(ident(ch[0].strVal), # ch is `nnkIdentDefs`
+                                      ch[1],
+                                      newEmptyNode())
+  proc fullSize[T: object | tuple](x: T): int =
+    var tmp: genCompatibleTuple(T)
+    result = 0
+    for field, val in fieldPairs(x):
+      result += sizeof(val)
+    doAssert result == sizeof(tmp)
+
+  let reflectivity = initInterpolator(1)
+  for el in reflectivity.data:
+    doAssert fullSize(el) == sizeof(el)
+  doAssert fullSize(reflectivity.data[0]) == sizeof(reflectivity.data[0])
+  doAssert genCompatibleTuple(Spectrum[60]) is tuple[data: array[60, float]]
+  doAssert genCompatibleTuple(Spectrum[120]) is tuple[data: array[120, float]]
+  type Foo[T] = object
+    data: T
+  doAssert genCompatibleTuple(Foo[int]) is tuple[data: int]
+  doAssert genCompatibleTuple(Foo[float]) is tuple[data: float]
diff --git a/tests/generics/timplicit_and_explicit.nim b/tests/generics/timplicit_and_explicit.nim
new file mode 100644
index 000000000..7220b7429
--- /dev/null
+++ b/tests/generics/timplicit_and_explicit.nim
@@ -0,0 +1,65 @@
+
+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, 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)
+
+  assert t[string]("Hallo", 2.0) == @["Hallo" & $2.0]
+
+  proc t2[T](z: int | float): seq[T] = result.add($z)
+
+  assert t2[string](2.0) == @[$2.0]
+
+block: # template test
+  template someThing[T;Y](a: SomeFloat, b: SomeOrdinal): (T, Y) = (a, b)
+  assert typeof(someThing[float64, int](1.0, 100)) is (float64, int)
+
+block: # static test
+  proc t[T](s: static bool) = discard
+  proc t2[T](s: static string) = discard
+  t[string](true)
+  t2[int]("hello")
+  t2[string]("world")
+  t2[float]("test222222")
+
+block: #11152
+  proc f[T](X: typedesc) = discard
+  f[int](string)
+
+block: #15622
+  proc test1[T](a: T, b: static[string] = "") = discard
+  test1[int64](123)
+  proc test2[T](a: T, b: static[string] = "") = discard
+  doAssert not (compiles do:
+    test2[int64, static[string]](123))
+
+block: #4688
+  proc convertTo[T](v: int or float): T = (T)(v)
+  discard convertTo[float](1)
+
+block: #4164
+  proc printStr[T](s: static[string]): T = discard
+  discard printStr[int]("hello static")
+
+import macros
+
+block: # issue #9040, statics with template, macro, symchoice explicit generics
+  block: # macro
+    macro fun[N: static int](): untyped =
+      newLit 1
+    const a = fun[2]()
+    doAssert a == 1
+  block: # template
+    template fun[N: static int](): untyped =
+      1
+    const a = fun[2]()
+    doAssert a == 1
+  block: # symchoice
+    proc newSeq[x: static int](): int = 1
+    template foo: int =
+      newSeq[2]()
+    doAssert foo() == 1
diff --git a/tests/generics/timports.nim b/tests/generics/timports.nim
new file mode 100644
index 000000000..e252ad194
--- /dev/null
+++ b/tests/generics/timports.nim
@@ -0,0 +1,63 @@
+discard """
+  output: '''
+317
+TEST2
+5 5 5
+false
+'''
+"""
+
+import mbind_bracket, mclosed_sym, mdotlookup, mmodule_same_as_proc, mtypenodes
+
+
+block tbind_bracket:
+  # bug #2599
+  # also test that `[]` can be passed now as a first class construct:
+
+  template takeBracket(x, a, i: untyped) =
+    echo x(a, i)
+
+  var a: array[10, int]
+  a[8] = 317
+
+  takeBracket(`[]`, a, 8)
+
+  let reg = newRegistry[UUIDObject]()
+  reg.register(UUIDObject())
+
+
+block tclosed_sym:
+  # bug #2664
+  proc same(r:R, d:int) = echo "TEST1"
+  doIt(Data[int](d:123), R())
+
+import strutils, unicode # ambiguous `strip`
+
+block tdotlookup:
+  foo(7)
+  # bug #1444
+  fn(4)
+  doAssert doStrip(123) == "123"
+  # bug #14254
+  doAssert baz2[float](1'i8) == 1
+  # bug #21883
+  proc abc[T: not not int](x: T): T =
+    var x = x
+    x.set("hello", "world")
+    result = x
+  doAssert abc(5) == 10
+  block: # ensure normal call is consistent with dot call 
+    proc T(x: int): float = x.float
+    proc foo[T](x: int) =
+      doAssert typeof(T(x)) is typeof(x.T)
+    foo[uint](123)
+
+block tmodule_same_as_proc:
+  # bug #1965
+  proc test[T](t: T) =
+    mmodule_same_as_proc"a"
+  test(0)
+
+block ttypenodes:
+  # issue #22699
+  doAssert chop[bool](42) == 42
diff --git a/tests/generics/tinheritable_importcpp.nim b/tests/generics/tinheritable_importcpp.nim
new file mode 100644
index 000000000..8ee18b70b
--- /dev/null
+++ b/tests/generics/tinheritable_importcpp.nim
@@ -0,0 +1,10 @@
+discard """
+  targets: "cpp"
+  action: compile
+"""
+
+# #4651
+type
+  Vector[T] {.importcpp: "std::vector<'0 >", header: "vector", inheritable.} = object
+  VectorDerived {.importcpp: "SomeVectorDerived", nodecl.} = object of Vector[int]
+  # Error: inheritance only works with non-final objects
diff --git a/tests/generics/tlateboundgenericparams.nim b/tests/generics/tlateboundgenericparams.nim
new file mode 100644
index 000000000..9f0580fd2
--- /dev/null
+++ b/tests/generics/tlateboundgenericparams.nim
@@ -0,0 +1,145 @@
+discard """
+  output: "1\n10\n1\n10"
+  nimout: '''
+bar instantiated with 1
+bar instantiated with 10
+'''
+"""
+
+import typetraits
+
+type
+  Foo = object
+
+proc defaultFoo: Foo = discard
+proc defaultInt: int = 1
+proc defaultTInt(T: type): int = 2
+proc defaultTFoo[T](x: typedesc[T]): Foo = discard
+proc defaultTOldSchool[T](x: typedesc[T]): T = discard
+proc defaultTModern(T: type): T = discard
+
+proc specializedDefault(T: type int): int = 10
+proc specializedDefault(T: type string): string = "default"
+
+converter intFromFoo(x: Foo): int = 3
+
+proc consumeInt(x: int) =
+  discard
+
+const activeTests = {1..100}
+
+when true:
+  template test(n, body) =
+    when n in activeTests:
+      block:
+        body
+
+  template reject(x) =
+    static: assert(not compiles(x))
+
+  test 1:
+    proc t[T](val: T = defaultInt()) =
+      consumeInt val
+
+    t[int]()
+    reject t[string]()
+
+  test 2:
+    proc t1[T](val: T = defaultFoo()) =
+      static:
+        assert type(val).name == "int"
+        assert T.name == "int"
+
+      consumeInt val
+
+    # here, the converter should kick in, but notice
+    # how `val` is still typed `int` inside the proc.
+    t1[int]()
+
+    proc t2[T](val: T = defaultFoo()) =
+      discard
+
+    reject t2[string]()
+
+  test 3:
+    proc tInt[T](val = defaultInt()): string =
+      return type(val).name
+
+    doAssert tInt[int]() == "int"
+    doAssert tInt[string]() == "int"
+
+    proc tInt2[T](val = defaultTInt(T)): string =
+      return type(val).name
+
+    doAssert tInt2[int]() == "int"
+    doAssert tInt2[string]() == "int"
+
+    proc tDefTModern[T](val = defaultTModern(T)): string =
+      return type(val).name
+
+    doAssert tDefTModern[int]() == "int"
+    doAssert tDefTModern[string]() == "string"
+    doAssert tDefTModern[Foo]() == "Foo"
+
+    proc tDefTOld[T](val = defaultTOldSchool(T)): string =
+      return type(val).name
+
+    doAssert tDefTOld[int]() == "int"
+    doAssert tDefTOld[string]() == "string"
+    doAssert tDefTOld[Foo]() == "Foo"
+
+  test 4:
+    proc t[T](val: T = defaultTFoo(T)): string =
+      return type(val).name
+
+    doAssert t[int]() == "int"
+    doAssert t[Foo]() == "Foo"
+    reject t[string]()
+
+  test 5:
+    proc t1[T](a: T = specializedDefault(T)): T =
+      return a
+
+    doAssert t1[int]() == 10
+    doAssert t1[string]() == "default"
+
+    proc t2[T](a: T, b = specializedDefault(T)): auto =
+      return $a & $b
+
+    doAssert t2(5) == "510"
+    doAssert t2("string ") == "string default"
+
+    proc t3[T](a: T, b = specializedDefault(type(a))): auto =
+      return $a & $b
+
+    doAssert t3(100) == "10010"
+    doAssert t3("another ") == "another default"
+
+  test 6:
+    # https://github.com/nim-lang/Nim/issues/5595
+    type
+      Point[T] = object
+        x, y: T
+
+    proc getOrigin[T](): Point[T] = Point[T](x: 0, y: 0)
+
+    proc rotate[T](point: Point[T], radians: float,
+                   origin = getOrigin[T]()): Point[T] =
+      discard
+
+    var p = getOrigin[float]()
+    var rotated = p.rotate(2.1)
+
+  test 7:
+    proc bar(x: static[int]) =
+      static: echo "bar instantiated with ", x
+      echo x
+
+    proc foo(x: static[int] = 1) =
+      bar(x)
+
+    foo()
+    foo(10)
+    foo(1)
+    foo(10)
+
diff --git a/tests/generics/tlateboundstatic.nim b/tests/generics/tlateboundstatic.nim
new file mode 100644
index 000000000..90b44aa8e
--- /dev/null
+++ b/tests/generics/tlateboundstatic.nim
@@ -0,0 +1,16 @@
+discard """
+  nimout: "array[0..3, int]"
+"""
+
+type
+  KK[I: static[int]] = object
+   x: array[I, int]
+
+proc foo(a: static[string]): KK[a.len] =
+  result.x[0] = 12
+
+var x = foo "test"
+
+import typetraits
+static: echo x.x.type.name
+
diff --git a/tests/generics/tmacroinjectedsym.nim b/tests/generics/tmacroinjectedsym.nim
new file mode 100644
index 000000000..985e415f2
--- /dev/null
+++ b/tests/generics/tmacroinjectedsym.nim
@@ -0,0 +1,186 @@
+{.experimental: "openSym".}
+
+block: # issue #22605, 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
+
+  proc g(T: type): string =
+    let x = valueOr 123:
+      return $error
+
+    "ok"
+
+  doAssert g(int) == "good"
+
+  proc g2(T: type): string =
+    bind error # use the bad version on purpose
+    let x = valueOr 123:
+      return $error
+
+    "ok"
+
+  doAssert g2(int) == "bad"
+
+block: # issue #22605, 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
+
+  proc g(T: type): string =
+    let x = 123.valueOr:
+      return $error
+
+    "ok"
+
+  doAssert g(int) == "good"
+
+  proc g2(T: type): string =
+    bind error # use the bad version on purpose
+    let x = 123.valueOr:
+      return $error
+
+    "ok"
+
+  doAssert g2(int) == "bad"
+
+block: # issue #22605, 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")
+
+  proc g(T: type): string =
+    let x = f().valueOr:
+      return $error
+
+    "ok"
+
+  doAssert g(int) == "f"
+
+  proc g2(T: type): string =
+    bind error # use the bad version on purpose
+    let x = f().valueOr:
+      return $error
+
+    "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
new file mode 100644
index 000000000..77119004b
--- /dev/null
+++ b/tests/generics/tmacroinjectedsymwarning.nim
@@ -0,0 +1,59 @@
+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")
+
+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 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"
+
+discard g(int)
diff --git a/tests/generics/tmapping_generic_alias.nim b/tests/generics/tmapping_generic_alias.nim
new file mode 100644
index 000000000..efdf32ead
--- /dev/null
+++ b/tests/generics/tmapping_generic_alias.nim
@@ -0,0 +1,28 @@
+discard """
+output: '''type(c) = GenAlias[system.int]
+T = int
+seq[int]
+'''
+"""
+
+import typetraits
+
+type
+  Gen[T] = object
+    x: T
+
+  GenAlias[T] = Gen[seq[T]]
+
+proc f1[T](x: Gen[T]) =
+  echo T.name
+
+proc f2[T](x: GenAlias[T]) =
+  echo "type(c) = ", type(x).name
+  echo "T = ", T.name
+  f1 x
+
+let
+  y = Gen[seq[int]](x: @[10])
+
+f2 y
+
diff --git a/tests/generics/tmetafield.nim b/tests/generics/tmetafield.nim
new file mode 100644
index 000000000..cf30a936d
--- /dev/null
+++ b/tests/generics/tmetafield.nim
@@ -0,0 +1,30 @@
+discard """
+  cmd: "nim check $options $file"
+  action: "reject"
+  nimout: '''
+tmetafield.nim(26, 5) Error: 'proc' is not a concrete type; for a callback without parameters use 'proc()'
+tmetafield.nim(27, 5) Error: 'Foo' is not a concrete type
+tmetafield.nim(29, 5) Error: invalid type: 'proc' in this context: 'TBaseMed' for var
+'''
+"""
+
+# bug #188
+
+
+
+
+
+
+
+
+# line 20
+type
+  Foo[T] = object
+    x: T
+
+  TBaseMed =  object
+    doSmth: proc
+    data: seq[Foo]
+
+var a: TBaseMed
+
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/tnullary_generics.nim b/tests/generics/tnullary_generics.nim
new file mode 100644
index 000000000..c79558ee3
--- /dev/null
+++ b/tests/generics/tnullary_generics.nim
@@ -0,0 +1,26 @@
+discard """
+  nimout: '''
+hah
+hey
+hey
+hah
+'''
+"""
+
+# non-generic
+proc foo(s: string) =
+  static: echo "hah"
+  echo s
+
+static: echo "hey"
+
+foo("hoo")
+
+# nullary generic
+proc bar[](s: string) =
+  static: echo "hah"
+  echo s
+
+static: echo "hey"
+
+bar("hoo")
diff --git a/tests/generics/tobjecttyperel.nim b/tests/generics/tobjecttyperel.nim
new file mode 100644
index 000000000..6f223c154
--- /dev/null
+++ b/tests/generics/tobjecttyperel.nim
@@ -0,0 +1,89 @@
+discard """
+  matrix: "-d:nimInternalNonVtablesTesting"
+  output: '''(peel: 0, color: 15)
+(color: 15)
+17
+(width: 0.0, taste: "", color: 13)
+(width: 0.0, taste: "", color: 15)
+cool
+test'''
+"""
+
+# bug #5241
+type
+  BaseFruit[T] = object of RootObj
+    color: T
+
+  MidLevel[T] = object of BaseFruit[T]
+
+  Mango = object of MidLevel[int]
+    peel: int
+
+  Peach[X, T, Y] = object of T
+    width: X
+    taste: Y
+
+proc setColor[T](self: var BaseFruit[T]) =
+  self.color = 15
+
+proc setColor[T](self: var BaseFruit[T], c: int) =
+  self.color = c
+
+var c: Mango
+setColor(c)
+echo c
+
+var d: MidLevel[int]
+setColor(d)
+echo d
+
+type
+  FooBase[T] = ref object of RootRef
+    v: T
+  BarClient = ref object of FooBase[int]
+
+proc getColor[T](f: FooBase[T]): T = 17
+var b: BarClient
+echo getColor(b)
+
+var z: Peach[float64, BaseFruit[int], string]
+z.setColor(13)
+echo z
+
+z.setColor()
+echo z
+
+# bug #5411
+type
+  Foo[T] = ref object of RootRef
+    v: T
+  Bar = ref object of Foo[int]
+
+method m(o: RootRef) {.base.} = assert(false, "Abstract method called")
+method m[T](o: Foo[T]) = echo "cool"
+
+var v: Bar
+v.new()
+v.m() # Abstract method not called anymore
+
+
+# bug #88
+
+type
+  TGen[T] = object of RootObj
+    field: T
+
+  TDerived[T] = object of TGen[T]
+    nextField: T
+
+proc doSomething[T](x: ref TGen[T]) =
+  type
+    Ty = ref TDerived[T]
+  echo Ty(x).nextField
+
+var
+  x: ref TDerived[string]
+new(x)
+x.nextField = "test"
+
+doSomething(x)
diff --git a/tests/generics/tobjecttyperel2.nim b/tests/generics/tobjecttyperel2.nim
new file mode 100644
index 000000000..d8c0751b7
--- /dev/null
+++ b/tests/generics/tobjecttyperel2.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''1
+a
+13'''
+"""
+
+# bug #5621 #5615
+type
+  Obj5[T] = ref object of RootObj
+    x_impl: T
+
+proc x[T](v476205: Obj5[T]): T {.used.} =
+  v476205.x_impl
+
+type
+  Obj6[T, U] = ref object of Obj5[T]
+    y_impl: U
+
+proc newObj6[T, U](x: T; y: U): Obj6[T, U] =
+  new(result)
+  result.x_impl = x
+  result.y_impl = y
+
+proc x[T, U](v477606: Obj6[T, U]): T {.used.} =
+  v477606.x_impl
+
+proc y[T, U](v477608: Obj6[T, U]): U {.used.} =
+  v477608.y_impl
+
+let e = newObj6(1, "a")
+echo e.x
+echo e.y
+
+type
+  Fruit[T] = ref object of RootObj
+  Apple[T] = ref object of Fruit[T]
+
+proc getColor[T](v: Fruit[T]): T = 13
+
+var w: Apple[int]
+let r = getColor(w)
+echo r
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/toverloading_typedesc.nim b/tests/generics/toverloading_typedesc.nim
new file mode 100644
index 000000000..4d748bfee
--- /dev/null
+++ b/tests/generics/toverloading_typedesc.nim
@@ -0,0 +1,19 @@
+import moverloading_typedesc
+import tables
+
+type
+  LFoo = object
+  LBar = object
+
+when true:
+  doAssert FBar.new() == 3
+
+  proc new(_: typedesc[LFoo]): int = 0
+  proc new[T](_: typedesc[T]): int = 1
+  proc new*(_: typedesc[seq[Table[int, seq[Table[int, typedesc]]]]]): int = 7
+
+  doAssert LFoo.new() == 0     # Tests selecting more precise type
+  doAssert LBar.new() == 1     # Tests preferring function from local scope
+  doAssert FBar.new() == 1
+  doAssert FFoo.new() == 2     # Tests selecting more precise type from other module
+  doAssert seq[Table[int, seq[Table[int, string]]]].new() == 5     # Truly complex type test
diff --git a/tests/generics/tparam_binding.nim b/tests/generics/tparam_binding.nim
new file mode 100644
index 000000000..fa7558613
--- /dev/null
+++ b/tests/generics/tparam_binding.nim
@@ -0,0 +1,29 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  errormsg: "got <ref Matrix[2, 2, system.float], ref Matrix[2, 1, system.float]>"
+  line: 28
+"""
+
+type
+  Matrix[M,N: static[int]; T: SomeFloat] = distinct array[0..(M*N - 1), T]
+
+let a = new Matrix[2,2,float]
+let b = new Matrix[2,1,float]
+
+proc foo[M,N: static[int],T](a: ref Matrix[M, N, T], b: ref Matrix[M, N, T])=
+  discard
+
+foo(a, a)
+
+proc bar[M,N: static[int],T](a: ref Matrix[M, M, T], b: ref Matrix[M, N, T])=
+  discard
+
+bar(a, b)
+bar(a, a)
+
+proc baz[M,N: static[int],T](a: ref Matrix[N, N, T], b: ref Matrix[M, N, T])=
+  discard
+
+baz(a, a)
+baz(a, b)
+
diff --git a/tests/generics/tparser_generator.nim b/tests/generics/tparser_generator.nim
new file mode 100644
index 000000000..ac921c0e5
--- /dev/null
+++ b/tests/generics/tparser_generator.nim
@@ -0,0 +1,415 @@
+discard """
+  output: '''Match failed: spam
+Match failed: ham'''
+joinable: false
+"""
+
+# bug #6220
+
+import nre
+import options
+import strutils except isAlpha, isLower, isUpper, isSpace
+from unicode import isAlpha, isLower, isUpper, isTitle, isWhiteSpace
+import os
+
+const debugLex = false
+
+template debug(enable: bool, text: string): typed =
+  when enable:
+    echo(text)
+
+type
+  Parser[N, T] = proc(text: T, start: int, nodes: var seq[Node[N]]): int {.closure.}
+
+  RuleObj[N, T] = object
+    parser: Parser[N, T]
+    kind: N
+
+  Rule[N, T] = ref RuleObj[N, T]
+
+  NodeKind = enum
+    terminal,
+    nonterminal
+
+  Node*[N] = object of RootObj
+    # Uncomment the following lines and the compiler crashes
+    # case nodeKind: NodeKind
+    #   of nonterminal:
+    #     kids: Node[N]
+    #   of terminal:
+    #     discard
+    start*: int
+    length*: int
+    kind*: N
+
+
+  NonTerminal[N] = object of Node
+    children: seq[Node[N]]
+
+proc newRule[N, T](parser: Parser, kind: N): Rule[N, T] =
+  new(result)
+  result.parser = parser
+  result.kind = kind
+
+proc newRule[N, T](kind: N): Rule[N, T] =
+  new(result)
+  result.kind = kind
+
+proc initNode[N](start: int, length: int, kind: N): Node[N] =
+  result.start = start
+  result.length = length
+  result.kind = kind
+
+proc initNode[N](start: int, length: int, children: seq[Node[N]], kind: N): NonTerminal[N] =
+  result.start = start
+  result.length = length
+  result.kind = kind
+  result.children = children
+
+proc substr[T](text: T, first, last: int): T =
+  text[first .. last]
+
+proc continuesWith[N](text: seq[Node[N]], subtext: seq[N], start: Natural): bool =
+  let length = len(text)
+  var pos = 0
+  while pos < len(subtext):
+    let textpos = start + pos
+    if textpos == len(text):
+      return false
+    if text[textpos].kind != subtext[pos].kind:
+      return false
+    pos+=1
+  return true
+
+
+proc render*[N, T](text: T, nodes: seq[Node[N]]): string =
+  ## Uses a sequence of Nodes to render a given text string
+  result = ""
+  for node in nodes:
+    result.add("<" & node.value(text) & ">")
+
+proc render*[N, T](rule: Rule[N, T], text: string): string =
+  ## Uses a rule to render a given text string
+  render(text, rule.parse(text))
+
+proc render*[N, T](text: T, nodes: seq[Node[N]], source: string): string =
+  result = ""
+  for node in nodes:
+    result.add("[" & node.value(text, source) & "]")
+
+proc render*[N, T, X](rule: Rule[N, T], text: seq[Node[X]], source: string): string =
+  ## Uses a rule to render a given series of nodes, providing the source string
+  text.render(rule.parse(text, source = source), source)
+
+proc annotate*[N, T](node: Node[N], text: T): string =
+  result = "<" & node.value(text) & ":" & $node.kind & ">"
+
+proc annotate*[N, T](nodes: seq[Node[N]], text: T): string =
+  result = ""
+  for node in nodes:
+    result.add(node.annotate(text))
+
+proc annotate*[N, T](rule: Rule[N, T], text: T): string =
+  annotate(rule.parse(text), text)
+
+proc value*[N, T](node: Node[N], text: T): string =
+  result = $text.substr(node.start, node.start + node.length - 1)
+
+proc value*[N, X](node: Node[N], text: seq[Node[X]], source: string): string =
+  result = ""
+  for n in node.start ..< node.start + node.length:
+    result &= text[n].annotate(source)
+
+proc parse*[N, T](rule: Rule[N, T], text: T, start = 0, source: string = ""): seq[Node[N]] =
+  result = newSeq[Node[N]]()
+  debug(debugLex, "Parsing: " & $text)
+  let length = rule.parser(text, start, result)
+
+  when T is string:
+    if length == -1:
+      echo("Match failed: " & $text)
+      result = @[]
+    elif length == len(text):
+      debug(debugLex, "Matched: " & $text & " => " & $len(result) & " tokens: " & text.render(result))
+    else:
+      echo("Matched first " & $length & " symbols: " & $text & " => " & $len(result) & " tokens: " & text.render(result))
+  else:
+    if length == -1:
+      echo("Match failed: " & $text)
+      result = @[]
+    elif length == len(text):
+      debug(debugLex, "Matched: " & $text & " => " & $len(result) & " tokens: " & text.render(result, source))
+    else:
+      echo("Matched first " & $length & " symbols: " & $text & " => " & $len(result) & " tokens: " & text.render(result, source))
+
+
+proc literal*[N, T, P](pattern: P, kind: N): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    if start == len(text):
+      return -1
+    doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)])
+    when P is string or P is seq[N]:
+      debug(debugLex, "Literal[" & $kind & "]: testing " & $pattern & " at " & $start & ": " & $text[start..start+len(pattern)-1])
+      if text.continuesWith(pattern, start):
+        let node = initNode(start, len(pattern), kind)
+        nodes.add(node)
+        debug(debugLex, "Literal: matched <" & $text[start ..< start+node.length] & ":" & $node.length & ">" )
+        return node.length
+    elif P is char:
+      debug(debugLex, "Literal[" & $kind & "]: testing " & $pattern & " at " & $start & ": " & $text[start])
+      if text[start] == pattern:
+        let node = initNode(start, 1, kind)
+        nodes.add(node)
+        return 1
+    else:
+      debug(debugLex, "Literal[" & $kind & "]: testing " & $pattern & " at " & $start & ": " & $text[start])
+      if text[start].kind == pattern:
+        let node = initNode(start, 1, kind)
+        nodes.add(node)
+        return 1
+    return -1
+  result = newRule[N, T](parser, kind)
+
+proc token[N, T](pattern: T, kind: N): Rule[N, T] =
+  when T is not string:
+     {.fatal: "Token is only supported for strings".}
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    debug(debugLex, "Token[" & $kind & "]: testing " & pattern & " at " & $start)
+    if start == len(text):
+      return -1
+    doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)])
+    let m = text.match(re(pattern), start)
+    if m.isSome:
+      let node = initNode(start, len(m.get.match), kind)
+      nodes.add(node)
+      result = node.length
+      debug(debugLex, "Token: matched <" & text[start ..< start+node.length] & ":" & $node.length & ">" )
+    else:
+      result = -1
+  result = newRule[N, T](parser, kind)
+
+proc chartest[N, T, S](testfunc: proc(s: S): bool, kind: N): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    if start == len(text):
+      return -1
+    doAssert(len(text)>start, "Attempting to match at $#, string length is $# " % [$start, $len(text)])
+    if testfunc(text[start]):
+      nodes.add(initNode(start, 1, kind))
+      result = 1
+    else:
+      result = -1
+  result = newRule[N, T](parser, kind)
+
+proc any*[N, T, S](symbols: T, kind: N): Rule[N, T] =
+  let test = proc(s: S): bool =
+    when S is string:
+      debug(debugLex, "Any[" & $kind & "]: testing for " & symbols.replace("\n", "\\n").replace("\r", "\\r"))
+    else:
+      debug(debugLex, "Any[" & $kind & "]: testing for " & $symbols)
+    result = s in symbols
+  result = chartest[N, T, S](test, kind)
+
+proc ignore*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    result = rule.parser(text, start, mynodes)
+  result = newRule[N, T](parser, rule.kind)
+
+proc combine*[N, T](rule: Rule[N, T], kind: N): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    result = rule.parser(text, start, mynodes)
+    nodes.add(initNode(start, result, kind))
+  result = newRule[N, T](parser, kind)
+
+proc build*[N, T](rule: Rule[N, T], kind: N): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    result = rule.parser(text, start, mynodes)
+    let nonTerminal = initNode(start, result, mynodes, kind)
+    nodes.add(nonTerminal)
+  result = newRule[N, T](parser, kind)
+
+proc fail*[N, T](message: string, kind: N): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    let lineno = countLines(text[0..start])
+    var startline = start
+    var endline = start
+    while startline>0:
+      if text[startline] in NewLines:
+        break
+      startline-=1
+    while endline < len(text):
+      if text[endline] in NewLines:
+        break
+      endline+=1
+    let charno = start-startline
+    echo text.substr(startline, endline)
+    echo ' '.repeat(max(charno,0)) & '^'
+    raise newException(ValueError, "Position: " & $start & " Line: " & $lineno & ", Symbol: " & $charno & ": " & message)
+  result = newRule[N, T](parser, kind)
+
+proc `+`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    doAssert(not isNil(left.parser), "Left hand side parser is nil")
+    let leftlength = left.parser(text, start, mynodes)
+    if leftlength == -1:
+      return leftlength
+    doAssert(not isNil(right.parser), "Right hand side parser is nil")
+    let rightlength = right.parser(text, start+leftlength, mynodes)
+    if rightlength == -1:
+      return rightlength
+    result = leftlength + rightlength
+    nodes.add(mynodes)
+  result = newRule[N, T](parser, left.kind)
+
+proc `/`*[N, T](left: Rule[N, T], right: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    doAssert(not isNil(left.parser), "Left hand side of / is not fully defined")
+    let leftlength = left.parser(text, start, mynodes)
+    if leftlength != -1:
+      nodes.add(mynodes)
+      return leftlength
+    mynodes = newSeq[Node[N]]()
+    doAssert(not isNil(right.parser), "Right hand side of / is not fully defined")
+    let rightlength = right.parser(text, start, mynodes)
+    if rightlength == -1:
+      return rightlength
+    nodes.add(mynodes)
+    return rightlength
+  result = newRule[N, T](parser, left.kind)
+
+proc `?`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    let success = rule.parser(text, start, nodes)
+    return if success != -1: success else: 0
+  result = newRule[N, T](parser, rule.kind)
+
+proc `+`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var success = rule.parser(text, start, nodes)
+    if success == -1:
+      return success
+    var total = 0
+    while success != -1 and start+total < len(text):
+      total += success
+      success = rule.parser(text, start+total, nodes)
+    return total
+  result = newRule[N, T](parser, rule.kind)
+
+proc `*`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    let success = (+rule).parser(text, start, nodes)
+    return if success != -1: success else: 0
+  result = newRule[N, T](parser, rule.kind)
+
+#Note: this consumes - for zero-width lookahead see !
+proc `^`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    let success = rule.parser(text, start, mynodes)
+    return if success == -1: 1 else: -1
+  result = newRule[N, T](parser, rule.kind)
+
+proc `*`*[N, T](repetitions: int, rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    var total = 0
+    for i in 0..<repetitions:
+      let success = rule.parser(text, start+total, mynodes)
+      if success == -1:
+        return success
+      else:
+        total += success
+    nodes.add(mynodes)
+    return total
+  result = newRule[N, T](parser, rule.kind)
+
+# Positive zero-width lookahead
+proc `&`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    let success = rule.parser(text, start, mynodes)
+    return if success != -1: 0 else: -1
+  result = newRule[N, T](parser, rule.kind)
+
+# Negative zero-width lookahead
+proc `!`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    let failure = rule.parser(text, start, mynodes)
+    return if failure == -1: 0 else: -1
+  result = newRule[N, T](parser, rule.kind)
+
+proc `/`*[N, T](rule: Rule[N, T]): Rule[N, T] =
+  let parser = proc (text: T, start: int, nodes: var seq[Node[N]]): int =
+    var mynodes = newSeq[Node[N]]()
+    var length = 0
+    var success = rule.parser(text, start+length, mynodes)
+    while success == -1 and start+length < len(text):
+      length += 1
+      success = rule.parser(text, start+length, mynodes)
+    if start+length >= len(text):
+      result = -1
+    else:
+      nodes.add(initNode(start, length, rule.kind))
+      nodes.add(mynodes)
+      result = length + success
+  result = newRule[N, T](parser, rule.kind)
+
+proc `->`*(rule: Rule, production: Rule) =
+  doAssert(not isnil(production.parser), "Right hand side of -> is nil - has the rule been defined yet?")
+  rule.parser = production.parser
+
+template grammar*[K](Kind, Text, Symbol: typedesc; default: K, code: untyped): typed {.hint[XDeclaredButNotUsed]: off.} =
+
+    proc newRule(): Rule[Kind, Text] {.inject.} = newRule[Kind, Text](default)
+    proc chartest(testfunc: proc(c: Symbol): bool): Rule[Kind, Text] {.inject.} = chartest[Kind, Text, Symbol](testfunc, default)
+    proc literal[P](pattern: P, kind: K): Rule[Kind, Text] {.inject.} = literal[Kind, Text, P](pattern, kind)
+    proc literal[P](pattern: P): Rule[Kind, Text] {.inject.} = literal[Kind, Text, P](pattern, default)
+
+    when Text is string:
+      proc token(pattern: string): Rule[Kind, Text] {.inject.} = token(pattern, default)
+      proc fail(message: string): Rule[Kind, Text] {.inject.} = fail[Kind, Text](message, default)
+      let alpha {.inject.} = chartest[Kind, Text, Symbol](isAlphaAscii, default)
+      let alphanumeric {.inject.}= chartest[Kind, Text, Symbol](isAlphaNumeric, default)
+      let digit {.inject.} = chartest[Kind, Text, Symbol](isDigit, default)
+      let lower {.inject.} = chartest[Kind, Text, Symbol](isLowerAscii, default)
+      let upper {.inject.} = chartest[Kind, Text, Symbol](isUpperAscii, default)
+      let isspace = proc (x: char): bool = x.isSpaceAscii and not (x in NewLines)
+      let space {.inject.} = chartest[Kind, Text, Symbol](isspace, default)
+      let isnewline = proc (x: char): bool = x in NewLines
+      let newline {.inject.} = chartest[Kind, Text, Symbol](isnewline, default)
+      let alphas {.inject.} = combine(+alpha, default)
+      let alphanumerics {.inject.} = combine(+alphanumeric, default)
+      let digits {.inject.} = combine(+digit, default)
+      let lowers {.inject.} = combine(+lower, default)
+      let uppers {.inject.} = combine(+upper, default)
+      let spaces {.inject.} = combine(+space, default)
+      let newlines {.inject.} = combine(+newline, default)
+
+    proc any(chars: Text): Rule[Kind, Text] {.inject.} = any[Kind, Text, Symbol](chars, default)
+    proc combine(rule: Rule[Kind, Text]): Rule[Kind, Text] {.inject.} = combine[Kind, Text](rule, default)
+
+    code
+
+template grammar*[K](Kind: typedesc; default: K, code: untyped): typed {.hint[XDeclaredButNotUsed]: off.} =
+  grammar(Kind, string, char, default, code)
+
+block:
+  type DummyKind = enum dkDefault
+  grammar(DummyKind, string, char, dkDefault):
+    let rule = token("h[a]+m") + ignore(token(r"\s+")) + (literal("eggs") / literal("beans"))
+    var text = "ham beans"
+    discard rule.parse(text)
+
+    var recursive = newRule()
+    recursive -> (literal("(") + recursive + literal(")")) / token(r"\d+")
+    for test in ["spam", "57", "(25)", "((25))"]:
+      discard recursive.parse(test)
+
+    let repeated = +literal("spam") + ?literal("ham") + *literal("salami")
+    for test in ["ham", "spam", "spamspamspam" , "spamham", "spamsalami", "spamsalamisalami"]:
+      discard  repeated.parse(test)
diff --git a/tests/generics/tpointerprocs.nim b/tests/generics/tpointerprocs.nim
new file mode 100644
index 000000000..2bcaf15b3
--- /dev/null
+++ b/tests/generics/tpointerprocs.nim
@@ -0,0 +1,28 @@
+discard """
+cmd: "nim check $options --hints:off $file"
+action: "reject"
+nimout:'''
+tpointerprocs.nim(15, 11) Error: 'foo' doesn't have a concrete type, due to unspecified generic parameters.
+tpointerprocs.nim(27, 11) Error: cannot instantiate: 'foo[int]'; got 1 typeof(s) but expected 2
+tpointerprocs.nim(27, 14) Error: expression 'foo[int]' has no type (or is ambiguous)
+tpointerprocs.nim(28, 11) Error: expression 'bar' has no type (or is ambiguous)
+'''
+"""
+
+block:
+  proc foo(x: int | float): float = result = 1.0
+  let
+    bar = foo
+    baz = bar
+
+block:
+  proc foo(x: int | float): float = result = 1.0
+  let
+    bar = foo[int]
+    baz = bar
+
+block:
+  proc foo(x: int | float, y: int or string): float = result = 1.0
+  let
+    bar = foo[int]
+    baz = bar
\ No newline at end of file
diff --git a/tests/generics/tprevent_double_bind.nim b/tests/generics/tprevent_double_bind.nim
new file mode 100644
index 000000000..d8fc6e5d3
--- /dev/null
+++ b/tests/generics/tprevent_double_bind.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "type mismatch: got <TT[seq[string]], proc (v: int){.gcsafe.}>"
+  line: 20
+"""
+
+# bug #6732
+import typetraits
+
+type
+  TT[T] = ref object of RootObj
+    val: T
+  CB[T] = proc (v: T)
+
+proc testGeneric[T](val: TT[T], cb: CB[T]) =
+  echo val.type.name
+  echo $val.val
+
+var tt = new(TT[seq[string]])
+echo tt.type.name
+tt.testGeneric( proc (v: int) =
+    echo $v )
diff --git a/tests/generics/trecursivegenerics.nim b/tests/generics/trecursivegenerics.nim
new file mode 100644
index 000000000..1b152b063
--- /dev/null
+++ b/tests/generics/trecursivegenerics.nim
@@ -0,0 +1,96 @@
+block: # Replicates #18728
+  type
+    FlipFlop[A, B] = ref object
+      val: A
+      next: FlipFlop[B, A]
+  
+    Trinary[A, B, C] = ref object
+      next: Trinary[B, C, A]
+  
+  assert typeof(FlipFlop[int, string]().next) is FlipFlop[string, int]
+  assert typeof(FlipFlop[string, int]().next) is FlipFlop[int, string]
+  assert typeof(Trinary[int, float, string]().next) is Trinary[float, string, int]
+  assert typeof(Trinary[int, float, string]().next.next) is Trinary[string, int, float]
+  var a = FlipFlop[int, string](val: 100, next: FlipFlop[string, int](val: "Hello"))
+  assert a.val == 100
+  assert a.next.val == "Hello"
+
+block: # 18838
+  type
+    DoublyLinkedNodeObj[T] = object
+      value: T
+
+    DoublyLinkedNode[T] = ref DoublyLinkedNodeObj[T]
+
+    Item[T] = ref object
+      link: DoublyLinkedNode[Item[T]]
+
+    Box = object
+
+  proc newDoublyLinkedNode[T](value: T): DoublyLinkedNode[T] =
+    new(result)
+    result.value = value 
+
+  let link = newDoublyLinkedNode(Item[Box]())
+
+import lists
+block:
+  type
+    Box = object
+    Item[T] = ref object
+      link:DoublyLinkedNode[ Item[T] ]
+
+    ItemSimple = ref object
+      link:DoublyLinkedNode[ ItemSimple ]
+
+  let link = newDoublyLinkedNode( Item[Box]() )
+
+block: #18897
+  type
+    SkipListObj[T] = object
+      over: SkipList[T]
+      down: SkipList[T]
+      value: T
+
+    SkipList[T] = ref SkipListObj[T]
+
+    GraphObj[N, E; F: static[int]] = object
+      nodes: SkipList[Node[N, E]]
+
+    Graph[N, E; F: static[int]] = ref GraphObj[N, E, F]
+
+    Node[N, E] = ref NodeObj[N, E]
+
+    NodeObj[N, E] = object
+      value: N
+      incoming: SkipList[Edge[N, E]]
+      outgoing: SkipList[Edge[N, E]]
+
+    Edge[N, E] = ref EdgeObj[N, E]
+
+    EdgeObj[N, E] = object
+      value: E
+      id: int
+      source: Node[N, E]
+      target: Node[N, E]
+
+    EdgeResult[N, E] = tuple
+      source: Node[N, E]
+      edge: Edge[N, E]
+      target: Node[N, E]
+
+  proc newSkipList[T](value: T): SkipList[T] =
+    static: echo T, " ", typeof(result.value)
+    result = SkipList[T](value: value)
+
+  proc toSkipList[T](values: openArray[T] = @[]): SkipList[T] =
+    for item in items(values):
+      if result.isNil:
+        result = newSkipList(item)
+
+  proc newContainer[N, E, F](graph: Graph[N, E, F]; form: typedesc): auto =
+    result = toSkipList[form]([])
+
+  var
+    result = Graph[int, string, 0]()
+  result.nodes = result.newContainer(Node[int, string])
\ No newline at end of file
diff --git a/tests/generics/treentranttypes.nim b/tests/generics/treentranttypes.nim
new file mode 100644
index 000000000..801f0e444
--- /dev/null
+++ b/tests/generics/treentranttypes.nim
@@ -0,0 +1,114 @@
+discard """
+output: '''
+(10, ("test", 1.2))
+3x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0], [2.0, 0.0, 5.0]]
+2x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]]
+2x3 Literal [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]]
+2x3 Matrix [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+2x2 ArrayArray[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+2x3 ArrayVector[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+2x3 VectorVector [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+2x3 VectorArray [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
+@[1, 2]
+@[1, 2]
+@[1, 2]@[3, 4]
+@[1, 2]@[3, 4]
+'''
+"""
+
+# https://github.com/nim-lang/Nim/issues/5962
+
+type
+  ArrayLike[A, B] = (A, B)
+  VectorLike*[SIZE, T] = ArrayLike[SIZE, T]
+  MatrixLike*[M, N, T] = VectorLike[M, VectorLike[N, T]]
+
+proc tupleTest =
+  let m: MatrixLike[int, string, float] = (10, ("test", 1.2))
+  echo m
+
+tupleTest()
+
+type
+  Vector*[K: static[int], T] =
+    array[K, T]
+
+  Matrix*[M: static[int]; N: static[int]; T] =
+    Vector[M, Vector[N, T]]
+
+proc arrayTest =
+  # every kind of square matrix works just fine
+  let mat_good: Matrix[3, 3, float] = [[0.0, 2.0, 3.0],
+                                       [2.0, 0.0, 5.0],
+                                       [2.0, 0.0, 5.0]]
+  echo "3x3 Matrix ", repr(mat_good)
+
+  # this does not work with explicit type signature (the matrix seems to always think it is NxN instead)
+  let mat_fail: Matrix[2, 3, float] = [[0.0, 2.0, 3.0],
+                                       [2.0, 0.0, 5.0]]
+  echo "2x3 Matrix ", repr(mat_fail)
+
+  # this literal seems to work just fine
+  let mat_also_good = [[0.0, 2.0, 3.0],
+                       [2.0, 0.0, 5.0]]
+
+  echo "2x3 Literal ", repr(mat_also_good)
+
+  # but making a named type out of this leads to pretty nasty runtime behavior
+  var mat_fail_runtime: Matrix[2, 3, float]
+  echo "2x3 Matrix ", repr(mat_fail_runtime)
+
+  # cutting out the matrix type middle man seems to solve our problem
+  var mat_ok_runtime: array[2, array[3, float]]
+  echo "2x2 ArrayArray", repr(mat_ok_runtime)
+
+  # this is fine too
+  var mat_ok_runtime_2: array[2, Vector[3, float]]
+  echo "2x3 ArrayVector", repr(mat_ok_runtime_2)
+
+  # here we are in trouble again
+  var mat_fail_runtime_2: Vector[2, Vector[3, float]]
+  echo "2x3 VectorVector ", repr(mat_fail_runtime_2)
+
+  # and here we are fine again
+  var mat_ok_runtime_3: Vector[2, array[3, float]]
+  echo "2x3 VectorArray ", repr(mat_ok_runtime_3)
+
+arrayTest()
+
+# https://github.com/nim-lang/Nim/issues/5756
+
+type
+  Vec*[N : static[int]] = object
+    arr*: array[N, int32]
+
+  Mat*[M,N: static[int]] = object
+    arr*: array[M, Vec[N]]
+
+proc vec2*(x,y:int32) : Vec[2] =
+  result.arr = [x,y]
+
+proc mat2*(a,b: Vec[2]): Mat[2,2] =
+  result.arr = [a,b]
+
+const a = vec2(1,2)
+echo @(a.arr)
+let x = a
+echo @(x.arr)
+
+const b = mat2(vec2(1, 2), vec2(3, 4))
+echo @(b.arr[0].arr), @(b.arr[1].arr)
+let y = b
+echo @(y.arr[0].arr), @(y.arr[1].arr)
+
+import macros
+
+block: # issue #5121
+  type
+    A = object
+    AConst[X] = A
+
+  macro dumpType(t: typedesc): untyped =
+    result = newTree(nnkTupleConstr, newLit $t.getType[1].typeKind, newLit t.getType[1].treeRepr)
+
+  doAssert dumpType(A) == ("ntyObject", "Sym \"A\"")
diff --git a/tests/generics/treturn_inference.nim b/tests/generics/treturn_inference.nim
new file mode 100644
index 000000000..331a9d4db
--- /dev/null
+++ b/tests/generics/treturn_inference.nim
@@ -0,0 +1,184 @@
+
+{.experimental: "inferGenericTypes".}
+
+import std/tables
+
+block:
+  type
+    MyOption[T, Z] = object
+      x: T
+      y: Z
+
+  proc none[T, Z](): MyOption[T, Z] =
+    when T is int:
+      result.x = 22
+    when Z is float:
+      result.y = 12.0
+
+  proc myGenericProc[T, Z](): MyOption[T, Z] =
+    none() # implied by return type
+
+  let a = myGenericProc[int, float]()
+  doAssert a.x == 22
+  doAssert a.y == 12.0
+
+  let b: MyOption[int, float] = none() # implied by type of b
+  doAssert b.x == 22
+  doAssert b.y == 12.0
+
+# Simple template based result with inferred type for errors
+block:
+  type
+    ResultKind {.pure.} = enum
+      Ok
+      Err
+
+    Result[T] = object
+      case kind: ResultKind
+      of Ok:
+        data: T
+      of Err:
+        errmsg: cstring
+
+  template err[T](msg: static cstring): Result[T] =
+    Result[T](kind : ResultKind.Err, errmsg : msg)
+
+  proc testproc(): Result[int] =
+    err("Inferred error!") # implied by proc return
+  let r = testproc()
+  doAssert r.kind == ResultKind.Err
+  doAssert r.errmsg == "Inferred error!"
+
+# Builtin seq
+block:
+  let x: seq[int] = newSeq(1)
+  doAssert x is seq[int]
+  doAssert x.len() == 1
+
+  type
+    MyType[T, Z] = object
+      x: T
+      y: Z
+
+  let y: seq[MyType[int, float]] = newSeq(2)
+  doAssert y is seq[MyType[int, float]]
+  doAssert y.len() == 2
+
+  let z = MyType[seq[float], string](
+    x : newSeq(3),
+    y : "test"
+  )
+  doAssert z.x is seq[float]
+  doAssert z.x.len() == 3
+  doAssert z.y is string
+  doAssert z.y == "test"
+
+# array
+block:
+  proc giveArray[N, T](): array[N, T] =
+    for i in 0 .. N.high:
+      result[i] = i
+  var x: array[2, int] = giveArray()
+  doAssert x == [0, 1]
+
+# tuples
+block:
+  proc giveTuple[T, Z]: (T, Z, T) = discard
+  let x: (int, float, int) = giveTuple()
+  doAssert x is (int, float, int)
+  doAssert x == (0, 0.0, 0)
+
+  proc giveNamedTuple[T, Z]: tuple[a: T, b: Z] = discard
+  let y: tuple[a: int, b: float] = giveNamedTuple()
+  doAssert y is (int, float)
+  doAssert y is tuple[a: int, b: float]
+  doAssert y == (0, 0.0)
+
+  proc giveNestedTuple[T, Z]: ((T, Z), Z) = discard
+  let z: ((int, float), float) = giveNestedTuple()
+  doAssert z is ((int, float), float)
+  doAssert z == ((0, 0.0), 0.0)
+
+  # nesting inside a generic type
+  type MyType[T] = object
+    x: T
+  let a = MyType[(int, MyType[float])](x : giveNamedTuple())
+  doAssert a.x is (int, MyType[float])
+
+
+# basic constructors
+block:
+  type MyType[T] = object
+    x: T
+
+  proc giveValue[T](): T =
+    when T is int:
+      12
+    else:
+      default(T)
+
+  let x = MyType[int](x : giveValue())
+  doAssert x.x is int
+  doAssert x.x == 12
+
+  let y = MyType[MyType[float]](x : MyType[float](x : giveValue()))
+  doAssert y.x is MyType[float]
+  doAssert y.x.x is float
+  doAssert y.x.x == 0.0
+
+  # 'MyType[float]' is bound to 'T' directly
+  #  instead of mapping 'T' to 'float'
+  let z = MyType[MyType[float]](x : giveValue())
+  doAssert z.x is MyType[float]
+  doAssert z.x.x == 0.0
+
+  type Foo = object
+    x: Table[int, float]
+
+  let a = Foo(x: initTable())
+  doAssert a.x is Table[int, float]
+
+# partial binding
+block:
+  type
+    ResultKind = enum
+      Ok, Error
+
+    Result[T, E] = object
+      case kind: ResultKind
+      of Ok:
+        okVal: T
+      of Error:
+        errVal: E
+
+  proc err[T, E](myParam: E): Result[T, E] =
+    Result[T, E](kind : Error, errVal : myParam)
+
+  proc doStuff(): Result[int, string] = 
+    err("Error")
+
+  let res = doStuff()
+  doAssert res.kind == Error
+  doAssert res.errVal == "Error"
+
+# ufcs
+block:
+  proc getValue[T](_: string): T =
+    doAssert T is int
+    44
+  
+  proc `'test`[T](_: string): T =
+    55
+
+  let a: int = getValue("")
+  let b: int = "".getValue()
+  let c: int = "".getValue
+  let d: int = getValue ""
+  let e: int = getValue""
+  let f: int = 12345'test
+  doAssert a == 44
+  doAssert b == 44
+  doAssert c == 44
+  doAssert d == 44
+  doAssert e == 44
+  doAssert f == 55
diff --git a/tests/generics/tstatic_constrained.nim b/tests/generics/tstatic_constrained.nim
new file mode 100644
index 000000000..d356b9d1c
--- /dev/null
+++ b/tests/generics/tstatic_constrained.nim
@@ -0,0 +1,79 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  action: "reject"
+  nimout:'''
+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, 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 [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>
+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 [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>
+but expected: <T: MyConstraint, Y>
+'''
+"""
+block:
+  type 
+    MyType[T; X: static T] = object
+      data: T
+    MyOtherType[T: float or string, Y: static T] = object
+
+  func f[T,X](a: MyType[T,X]): MyType[T,X] =
+    when T is string:
+      MyType[T,X](data: a.data & X)
+    else:
+      MyType[T,X](data: a.data + X)
+
+  discard MyType[int, 2](data: 1)
+  discard MyType[string, "Helelello"](data: "Hmmm")
+  discard MyType[int, 2](data: 1).f()
+  discard MyType[string, "Helelello"](data: "Hmmm").f()
+  discard MyOtherType[float, 1.3]()
+  discard MyOtherType[string, "Hello"]()
+  discard MyOtherType[int, 10]()
+  discard MyOtherType[byte, 10u8]()
+
+block:
+  type
+    Moduloable = concept m, type M
+      m mod m is M
+    Addable = concept a, type A
+      a + a is A
+    Modulo[T: Moduloable; Mod: static T] = distinct T
+    ModuloAdd[T: Moduloable or Addable; Mod: static T] = distinct T
+    ModuAddable = Addable or Moduloable
+    ModdAddClass[T: ModuAddable; Mod: static T] = distinct T
+
+  proc toMod[T](val: T, modVal: static T): Modulo[T, modVal] =
+    mixin `mod`
+    Modulo[T, modVal](val mod modVal)
+  var
+    a = 3231.toMod(10)
+    b = 5483.toMod(10)
+  discard ModuloAdd[int, 3](0)
+  discard ModdAddClass[int, 3](0)
+
+block:
+  type
+    MyConstraint = int or string
+    MyOtherConstraint[T] = object
+    MyType[T: MyConstraint; Y: static T] = object
+    MyOtherType[T: MyOtherConstraint; Y: static T] = object
+
+  var 
+    a: MyType[int, 10]
+    b: MyType[string, "hello"]
+    c: MyType[float, 10d]
+    d: MyOtherType[MyOtherConstraint[float],MyOtherConstraint[float]()]
+    e: MyOtherType[MyOtherConstraint[int], MyOtherConstraint[int]()]
diff --git a/tests/generics/tsubclassgenericerror.nim b/tests/generics/tsubclassgenericerror.nim
new file mode 100644
index 000000000..87f8a8e64
--- /dev/null
+++ b/tests/generics/tsubclassgenericerror.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "cannot instantiate 'GenericParentType[T]' inside of type definition: 'GenericChildType'; Maybe generic arguments are missing?"
+  line: 8
+"""
+
+type
+  GenericParentType[T] = ref object of RootObj
+  GenericChildType[T] = ref object of GenericParentType # missing the [T]
+    val: T
+
+var instance : GenericChildType[int] = nil
diff --git a/tests/generics/tthread_generic.nim b/tests/generics/tthread_generic.nim
new file mode 100644
index 000000000..300da56a6
--- /dev/null
+++ b/tests/generics/tthread_generic.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  action: compile
+"""
+
+type
+  ThreadFuncArgs[T] = object of RootObj
+    a: proc(): T {.thread.}
+    b: proc(val: T) {.thread.}
+
+proc handleThreadFunc(arg: ThreadFuncArgs[int]){.thread.} =
+  var fn = arg.a
+  var callback = arg.b
+  var output = fn()
+  callback(output)
+
+proc `@||->`*[T](fn: proc(): T {.thread.},
+                 callback: proc(val: T){.thread.}): Thread[ThreadFuncArgs[T]] =
+  var thr: Thread[ThreadFuncArgs[T]]
+  var args: ThreadFuncArgs[T]
+  args.a = fn
+  args.b = callback
+  createThread(thr, handleThreadFunc, args)
+  return thr
+
+proc `||->`*[T](fn: proc(): T{.thread.}, callback: proc(val: T){.thread.}) =
+  discard fn @||-> callback
+
+when true:
+  import os
+  proc testFunc(): int {.thread.} =
+    return 1
+  proc callbackFunc(val: int) {.thread.} =
+    echo($(val))
+
+  var thr = (testFunc @||-> callbackFunc)
+  echo("test")
+  joinThread(thr)
+  os.sleep(3000)
diff --git a/tests/generics/tuninstantiated_failure.nim b/tests/generics/tuninstantiated_failure.nim
new file mode 100644
index 000000000..f3d5b34b8
--- /dev/null
+++ b/tests/generics/tuninstantiated_failure.nim
@@ -0,0 +1,16 @@
+discard """
+cmd: "nim check $file"
+"""
+
+type
+  Test[T, K] = object
+    name: string
+  Something = Test[int]
+
+func `[]`[T, K](x: var Test[T, K], idx: int): var Test[T, K] =
+  x
+
+var b: Something
+# Should give an error since Something isn't a valid Test
+b[0].name = "Test" #[tt.Error
+ ^  expression '' has no type (or is ambiguous)]#
diff --git a/tests/generics/tuninstantiatedgenericcalls.nim b/tests/generics/tuninstantiatedgenericcalls.nim
new file mode 100644
index 000000000..f33fc8967
--- /dev/null
+++ b/tests/generics/tuninstantiatedgenericcalls.nim
@@ -0,0 +1,517 @@
+# Cases that used to only work due to weird workarounds in the compiler
+# involving not instantiating calls in generic bodies which are removed
+# due to breaking statics.
+# The issue was that these calls are compiled as regular expressions at
+# the generic declaration with unresolved generic parameter types,
+# which are special cased in some places in the compiler, but sometimes
+# treated like real types.
+
+block:
+  type Base10 = object
+
+  func maxLen(T: typedesc[Base10], I: type): int8 =
+    when I is uint8:
+      3
+    elif I is uint16:
+      5
+    elif I is uint32:
+      10
+    elif I is uint64:
+      20
+    else:
+      when sizeof(uint) == 4:
+        10
+      else:
+        20
+  
+  type
+    Base10Buf[T: SomeUnsignedInt] = object
+      data: array[maxLen(Base10, T), byte]
+      len: int8
+
+  var x: Base10Buf[uint32]
+  doAssert x.data.len == 10
+  var y: Base10Buf[uint16]
+  doAssert y.data.len == 5
+
+import typetraits
+
+block thardcases:
+  proc typeNameLen(x: typedesc): int {.compileTime.} =
+    result = x.name.len
+  macro selectType(a, b: typedesc): typedesc =
+    result = a
+
+  type
+    Foo[T] = object
+      data1: array[T.high, int]
+      data2: array[typeNameLen(T), float]
+      data3: array[0..T.typeNameLen, selectType(float, int)]
+  
+  type MyEnum = enum A, B, C, D
+
+  var f1: Foo[MyEnum]
+  var f2: Foo[int8]
+
+  doAssert high(f1.data1) == 2 # (D = 3) - 1 == 2
+  doAssert high(f1.data2) == 5 # (MyEnum.len = 6) - 1 == 5
+
+  doAssert high(f2.data1) == 126 # 127 - 1 == 126
+  doAssert high(f2.data2) == 3 # int8.len - 1 == 3
+
+  static:
+    doAssert high(f1.data1) == ord(C)
+    doAssert high(f1.data2) == 5 # length of MyEnum minus one, because we used T.high
+
+    doAssert high(f2.data1) == 126
+    doAssert high(f2.data2) == 3
+
+    doAssert high(f1.data3) == 6 # length of MyEnum
+    doAssert high(f2.data3) == 4 # length of int8
+
+    doAssert f2.data3[0] is float
+
+import muninstantiatedgenericcalls
+
+block:
+  var x: Leb128Buf[uint32]
+  doAssert x.data.len == 5
+  var y: Leb128Buf[uint16]
+  doAssert y.data.len == 3
+
+import macros
+
+block: # issue #12415
+  macro isSomePointerImpl(t: typedesc): bool =
+    var impl = t.getTypeInst[1].getTypeImpl
+    if impl.kind == nnkDistinctTy:
+      impl = impl[0].getTypeImpl
+    if impl.kind in {nnkPtrTy,nnkRefTy}:
+      result = newLit(true)
+    elif impl.kind == nnkSym and impl.eqIdent("pointer"):
+      result = newLit(true)
+    else:
+      result = newLit(false)
+
+  proc isSomePointer[T](t: typedesc[T]): bool {.compileTime.} =
+    isSomePointerImpl(t)
+
+  type
+    Option[T] = object
+      ## An optional type that stores its value and state separately in a boolean.
+      when isSomePointer(typedesc(T)):
+        val: T
+      else:
+        val: T
+        has: bool
+  var x: Option[ref int]
+  doAssert not compiles(x.has)
+  var y: Option[int]
+  doAssert compiles(y.has)
+
+block: # issue #2002
+  proc isNillable(T: typedesc): bool =
+    when compiles((let v: T = nil)):
+      return true
+    else:
+      return false
+
+  type
+    Foo[T] = object
+      when isNillable(T):
+        nillable: float
+      else:
+        notnillable: int
+
+  var val1: Foo[ref int]
+  doAssert compiles(val1.nillable)
+  doAssert not compiles(val1.notnillable)
+  var val2: Foo[int]
+  doAssert not compiles(val2.nillable)
+  doAssert compiles(val2.notnillable)
+
+block: # issue #1771
+  type
+    Foo[X, T] = object
+      bar: array[X.low..X.high, T]
+
+  proc test[X, T](f: Foo[X, T]): T =
+    f.bar[X.low]
+
+  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/tunique_type.nim b/tests/generics/tunique_type.nim
new file mode 100644
index 000000000..1150dea49
--- /dev/null
+++ b/tests/generics/tunique_type.nim
@@ -0,0 +1,67 @@
+# Bug #2022
+
+discard """
+  output: '''@[97, 45]
+@[true, false]
+@[false, false]'''
+"""
+
+## The goal of this snippet is to provide and test a construct for general-
+## purpose, random-access mapping. I use an AST-manipulation-based approach
+## because it's more efficient than using procedure pointers and less
+## verbose than defining a new callable type for every invocation of `map`.
+
+import sugar
+import macros
+import strutils
+
+#===============================================================================
+# Define a system for storing copies of ASTs as static strings.
+# This serves the same purpose as D's `alias` parameters for types, used heavily
+# in its popular `ranges` and `algorithm` modules.
+
+var exprNodes {.compileTime.} = newSeq[NimNode]()
+
+proc refExpr(exprNode: NimNode): string {.compileTime.} =
+  exprNodes.add exprNode.copy
+  "expr" & $(exprNodes.len - 1)
+
+proc derefExpr(exprRef: string): NimNode {.compileTime.} =
+  exprNodes[parseInt(exprRef[4 .. ^1])]
+
+#===============================================================================
+# Define a type that allows a callable expression to be mapped onto elements
+# of an indexable collection.
+
+type Mapped[Input; predicate: static[string]] = object
+  input: Input
+
+macro map(input, predicate: untyped): untyped =
+  let predicate = callsite()[2]
+  newNimNode(nnkObjConstr).add(
+    newNimNode(nnkBracketExpr).add(
+      ident"Mapped",
+      newNimNode(nnkTypeOfExpr).add(input),
+      newLit(refExpr(predicate))),
+    newNimNode(nnkExprColonExpr).add(
+      ident"input", input))
+
+proc `[]`(m: Mapped, i: int): auto =
+  macro buildResult: untyped =
+    newCall(
+      derefExpr(m.predicate),
+      newNimNode(nnkBracketExpr).add(
+        newDotExpr(ident"m", ident"input"),
+        ident"i"))
+  buildResult()
+
+#===============================================================================
+# Test out our generic mapping construct.
+
+let a = "a-string".map(ord)
+let b = @["a", "seq"].map((e: string) => e == "a")
+let c = "another-string".map((e: char) => e == 'o')
+
+echo(@[a[0], a[1]]) # @[97, 45]
+echo(@[b[0], b[1]]) # @[true, false]
+echo(@[c[0], c[1]]) # @[false, false]
diff --git a/tests/generics/tvarseq_caching.nim b/tests/generics/tvarseq_caching.nim
new file mode 100644
index 000000000..f617b9335
--- /dev/null
+++ b/tests/generics/tvarseq_caching.nim
@@ -0,0 +1,48 @@
+discard """
+  output: '''@[1, 2, 3]
+@[4.0, 5.0, 6.0]
+@[1, 2, 3]
+@[4.0, 5.0, 6.0]
+@[1, 2, 3]
+@[4, 5, 6]'''
+"""
+
+# bug #3476
+
+proc foo[T]: var seq[T] =
+  ## Problem! Bug with generics makes every call to this proc generate
+  ## a new seq[T] instead of retrieving the `items {.global.}` variable.
+  var items {.global.}: seq[T]
+  return items
+
+proc foo2[T]: ptr seq[T] =
+  ## Workaround! By returning by `ptr` instead of `var` we can get access to
+  ## the `items` variable, but that means we have to explicitly deref at callsite.
+  var items {.global.}: seq[T]
+  return addr items
+
+proc bar[T]: var seq[int] =
+  ## Proof. This proc correctly retrieves the `items` variable. Notice the only thing
+  ## that's changed from `foo` is that it returns `seq[int]` instead of `seq[T]`.
+  var items {.global.}: seq[int]
+  return items
+
+
+foo[int]() = @[1, 2, 3]
+foo[float]() = @[4.0, 5.0, 6.0]
+
+foo2[int]()[] = @[1, 2, 3]
+foo2[float]()[] = @[4.0, 5.0, 6.0]
+
+bar[int]() = @[1, 2, 3]
+bar[float]() = @[4, 5, 6]
+
+
+echo foo[int]()      # prints 'nil' - BUG!
+echo foo[float]()    # prints 'nil' - BUG!
+
+echo foo2[int]()[]   # prints '@[1, 2, 3]'
+echo foo2[float]()[] # prints '@[4.0, 5.0, 6.0]'
+
+echo bar[int]()      # prints '@[1, 2, 3]'
+echo bar[float]()    # prints '@[4, 5, 6]'
diff --git a/tests/generics/twrong_field_caching.nim b/tests/generics/twrong_field_caching.nim
new file mode 100644
index 000000000..667ffbbe5
--- /dev/null
+++ b/tests/generics/twrong_field_caching.nim
@@ -0,0 +1,68 @@
+discard """
+  output: '''a23: 2x3
+a32: 3x2
+transpose A
+t32: 3x2
+transpose B
+x23: 2x3 (2x3)
+x32: 3x2 (3x2)'''
+"""
+
+# bug #2125
+# Suppose we have the following type for a rectangular array:
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+
+var a23: RectArray[2, 3, int]
+var a32: RectArray[3, 2, int]
+
+echo "a23: ", a23.R, "x", a23.C
+echo "a32: ", a32.R, "x", a32.C
+
+# Output:
+# a23: 2x3
+# a32: 3x2
+
+# Looking good. Let's add a proc:
+proc transpose*[R, C, T](m: RectArray[R, C, T]): RectArray[C, R, T] =
+  echo "transpose A"
+
+var t32 = a23.transpose
+
+echo "t32: ", t32.R, "x", t32.C
+
+# Output:
+# t32: 3x2
+
+
+# Everything is still OK. Now let's use the rectangular array inside another
+# generic type:
+type
+  Matrix*[R, C: static[int], T] = object
+    theArray*: RectArray[R, C, T]
+
+#var m23: Matrix[2, 3, int]
+#var m32: Matrix[3, 2, int]
+
+#echo "m23: ", m23.R, "x", m23.C, " (", m23.theArray.R, "x", m23.theArray.C, ")"
+#echo "m32: ", m32.R, "x", m32.C, " (", m32.theArray.R, "x", m32.theArray.C, ")"
+
+# Output:
+# m23: 2x3 (2x3)
+# m32: 3x2 (3x2)
+
+
+# Everything is still as expected. Now let's add the following proc:
+proc transpose*[R, C, T](m: Matrix[R, C, T]): Matrix[C, R, T] =
+  echo "transpose B"
+
+var x23: Matrix[2, 3, int]
+var x32 = x23.transpose
+
+echo "x23: ", x23.R, "x", x23.C, " (", x23.theArray.R, "x", x23.theArray.C, ")"
+echo "x32: ", x32.R, "x", x32.C, " (", x32.theArray.R, "x", x32.theArray.C, ")"
+
+# Output:
+# x23: 2x3 (2x3)
+# x32: 3x2 (3x2)  <--- this is incorrect. R and C do not match!
diff --git a/tests/generics/twrong_floatlit_type.nim b/tests/generics/twrong_floatlit_type.nim
new file mode 100644
index 000000000..04bacc0d9
--- /dev/null
+++ b/tests/generics/twrong_floatlit_type.nim
@@ -0,0 +1,118 @@
+discard """
+  errormsg: "type mismatch"
+  line: 116
+"""
+
+# bug #2169
+import strutils, math
+
+type
+  Point2D*[S] = object
+    x*, y*: S
+  Matrix2x3*[S] = distinct array[6, S] ## Row major order
+
+  Vector2D*[S] = object
+    x*, y*: S
+
+proc `[]`*[T](m: Matrix2x3[T], i: int): T = array[6, T](m)[i]
+
+template M11*[T](m: Matrix2x3[T]): T = m[0]
+template M12*[T](m: Matrix2x3[T]): T = m[1]
+template M13*[T](m: Matrix2x3[T]): T = m[2]
+template M21*[T](m: Matrix2x3[T]): T = m[3]
+template M22*[T](m: Matrix2x3[T]): T = m[4]
+template M23*[T](m: Matrix2x3[T]): T = m[5]
+
+proc identity*[T](): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), 0.0, 0.0,   0.0, 1.0, 0.0])
+
+proc translation*[T](p: Point2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y])
+
+proc translation*[T](p: Vector2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([T(1.0), T(0.0), p.x, T(0.0), T(1.0), p.y])
+
+proc scale*[T](v: Vector2D[T]): Matrix2x3[T] =
+    Matrix2x3[T]([v.x, T(0.0), T(0.0), T(0.0), v.y, T(0.0)])
+
+proc rotation*[T](th: T): Matrix2x3[T] =
+    let
+        c = T(cos(th.float))
+        s = T(sin(th.float))
+
+    Matrix2x3[T]([c, -s, T(0.0),   s, c, T(0.0)])
+
+proc `*`*[T](a, b: Matrix2x3[T]): Matrix2x3[T] =
+    # Here we pretend that row 3 is [0,0,0,1] without
+    # actually storing it in the matrix.
+    Matrix2x3[T]([a.M11*b.M11 + a.M12*b.M21,
+                  a.M11*b.M12 + a.M12*b.M22,
+                  a.M11*b.M13 + a.M12*b.M23 + a.M13,
+
+                  a.M21*b.M11 + a.M22*b.M21,
+                  a.M21*b.M12 + a.M22*b.M22,
+                  a.M21*b.M13 + a.M22*b.M23 + a.M23])
+
+proc `*`*[T](a: Matrix2x3[T], p: Point2D[T]): Point2D[T] =
+    let
+        x = a.M11*p.x + a.M12*p.y + a.M13
+        y = a.M21*p.x + a.M22*p.y + a.M23
+
+    Point2D[T](x: x, y: y)
+
+# making these so things like "line" that need a constructor don't stick out.
+# 2x2 determinant:  |a b|
+#                   |c d|  = ad - bc
+
+# String rendering
+#
+template ff[S](x: S): string =
+    formatFloat(float(x), ffDefault, 0)
+
+proc `$`*[S](p: Point2D[S]): string =
+    "P($1, $2)" % [ff(p.x), ff(p.y)]
+
+proc `$`*[S](p: Vector2D[S]): string =
+    "V($1, $2)" % [ff(p.x), ff(p.y)]
+
+proc `$`*[S](m: Matrix2x3[S]): string =
+    "M($1 $2 $3/$4 $5 $6)" % [ff(m.M11), ff(m.M12), ff(m.M13),
+                              ff(m.M21), ff(m.M22), ff(m.M23)]
+
+#
+# Vector operators.
+proc `-`*[S](a: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: -a.x, y: -a.y)
+
+proc `+`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x + b.x, y: a.y + b.y)
+
+proc `-`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x - b.x, y: a.y - b.y)
+
+proc `*`*[S](v: Vector2D[S], sc: S): Vector2D[S] =
+  Vector2D[S](x: v.x*sc, y: v.y*sc)
+
+proc `*`*[S](sc: S, v: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: v.x*sc, y: v.y*sc)
+
+proc `/`*[S](v: Vector2D[S], sc: S): Vector2D[S] =
+  Vector2D[S](x: v.x/sc, y: v.y/sc)
+
+proc `/`*[S](sc: S; v: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: sc/v.x, y: sc/v.y)
+
+proc `/`*[S](a, b: Vector2D[S]): Vector2D[S] =
+  Vector2D[S](x: a.x/b.x, y: a.y/b.y)
+#proc vec[S](x, y: S): Vector2D[S]
+proc vec[S](x, y: S): Vector2D[S] =
+  Vector2D[S](x: x, y: y)
+
+if true:
+  # Comment out this let, and the program will fail to
+  # compile with a type mismatch, as expected.
+
+  let s3 = scale(vec(4.0, 4.0))
+  let barf = translation(Point2D[float32](x: 1, y: 1)) * rotation(float(0.7))
+
+  echo "Badness ", barf
diff --git a/tests/generics/twrong_generic_object.nim b/tests/generics/twrong_generic_object.nim
new file mode 100644
index 000000000..4951f735f
--- /dev/null
+++ b/tests/generics/twrong_generic_object.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "'Node' is not a concrete type"
+  line: 11
+"""
+# bug #2509
+type
+  GenericNodeObj[T] = ref object
+    obj: T
+
+  Node* = ref object
+    children*: seq[Node]
+    parent*: Node
+
+    nodeObj*: GenericNodeObj # [int]
+
+proc newNode*(nodeObj: GenericNodeObj): Node =
+  result = Node(nodeObj: nodeObj)
+  newSeq(result.children, 10)
+
+var genericObj = GenericNodeObj[int]()
+var myNode = newNode(genericObj)
diff --git a/tests/global/a_module.nim b/tests/global/a_module.nim
new file mode 100644
index 000000000..1d3f4848c
--- /dev/null
+++ b/tests/global/a_module.nim
@@ -0,0 +1,6 @@
+# a.nim
+{.push stackTrace: off.}
+proc foo*(): int =
+  var a {.global.} = 0
+  result = a
+{.pop.}
\ No newline at end of file
diff --git a/tests/global/globalaux.nim b/tests/global/globalaux.nim
new file mode 100644
index 000000000..951472695
--- /dev/null
+++ b/tests/global/globalaux.nim
@@ -0,0 +1,15 @@
+type
+  TObj*[T] = object
+    val*: T
+
+var
+  totalGlobals* = 0
+
+proc makeObj[T](x: T): TObj[T] =
+  totalGlobals += 1
+  result.val = x
+
+proc globalInstance*[T]: var TObj[T] =
+  var g {.global.} = when T is int: makeObj(10) else: makeObj("hello")
+  result = g
+
diff --git a/tests/global/globalaux2.nim b/tests/global/globalaux2.nim
new file mode 100644
index 000000000..6c77f1f48
--- /dev/null
+++ b/tests/global/globalaux2.nim
@@ -0,0 +1,4 @@
+import globalaux
+
+echo "in globalaux2: ", globalInstance[int]().val
+
diff --git a/tests/global/t15005.nim b/tests/global/t15005.nim
new file mode 100644
index 000000000..6395b1dde
--- /dev/null
+++ b/tests/global/t15005.nim
@@ -0,0 +1,18 @@
+type
+  T = ref object
+    data: string
+
+template foo(): T =
+  var a15005 {.global.}: T
+  once:
+    a15005 = T(data: "hi")
+
+  a15005
+
+proc test() =
+  var b15005 = foo()
+
+  doAssert b15005.data == "hi"
+
+test()
+test()
diff --git a/tests/global/t21896.nim b/tests/global/t21896.nim
new file mode 100644
index 000000000..c7765c4dd
--- /dev/null
+++ b/tests/global/t21896.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot assign local to global variable"
+  line: 7
+"""
+
+proc example(a:int) =
+  let b {.global.} = a
+
+example(1)
diff --git a/tests/global/t3505.nim b/tests/global/t3505.nim
new file mode 100644
index 000000000..437a02ae6
--- /dev/null
+++ b/tests/global/t3505.nim
@@ -0,0 +1,41 @@
+discard """
+cmd: "nim check $options --hints:off $file"
+action: "reject"
+nimout: '''
+t3505.nim(22, 22) Error: cannot assign local to global variable
+t3505.nim(31, 28) Error: cannot assign local to global variable
+t3505.nim(39, 29) Error: cannot assign local to global variable
+
+
+
+
+'''
+"""
+
+
+
+
+
+
+proc foo =
+  let a = 0
+  var b {.global.} = a
+foo()
+
+# issue #5132
+proc initX(it: float): int = 8
+proc initX2(it: int): int = it
+
+proc main() =
+  var f: float
+  var x {.global.} = initX2(initX(f))
+  
+main()
+
+# issue #20866
+proc foo2() =
+  iterator bar() {.closure.} =
+    discard
+  var g {.global.} = rawProc(bar)
+
+foo2()
\ No newline at end of file
diff --git a/tests/global/t5958.nim b/tests/global/t5958.nim
new file mode 100644
index 000000000..9b7642363
--- /dev/null
+++ b/tests/global/t5958.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "undeclared identifier: 'a'"
+  line: 9
+"""
+
+static:
+  var a = 1
+
+echo a
diff --git a/tests/global/tglobal.nim b/tests/global/tglobal.nim
new file mode 100644
index 000000000..d44a62afc
--- /dev/null
+++ b/tests/global/tglobal.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "in globalaux2: 10\ntotal globals: 2\nint value: 100\nstring value: second"
+  disabled: "true"
+"""
+
+import globalaux, globalaux2
+
+echo "total globals: ", totalGlobals
+
+globalInstance[int]().val = 100
+echo "int value: ", globalInstance[int]().val
+
+globalInstance[string]().val = "first"
+globalInstance[string]().val = "second"
+echo "string value: ", globalInstance[string]().val
+
diff --git a/tests/global/tglobal2.nim b/tests/global/tglobal2.nim
new file mode 100644
index 000000000..73a575bbd
--- /dev/null
+++ b/tests/global/tglobal2.nim
@@ -0,0 +1,9 @@
+# b.nim
+import a_module
+doAssert foo() == 0
+
+proc hello(x: type) =
+  var s {.global.} = default(x)
+  doAssert s == 0
+
+hello(int)
diff --git a/tests/global/tglobalforvar.nim b/tests/global/tglobalforvar.nim
new file mode 100644
index 000000000..bc18f33f2
--- /dev/null
+++ b/tests/global/tglobalforvar.nim
@@ -0,0 +1,9 @@
+discard """
+output: 100
+"""
+
+var funcs: seq[proc (): int {.nimcall.}] = @[]
+for i in 0..10:
+  funcs.add((proc (): int = return i * i))
+
+echo(funcs[3]())
diff --git a/tests/gtk/ex1.nim b/tests/gtk/ex1.nim
deleted file mode 100755
index aa3ed2f66..000000000
--- a/tests/gtk/ex1.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-import 

-  cairo, glib2, gtk2

-

-proc destroy(widget: pGtkWidget, data: pgpointer) {.cdecl.} =

-  gtk_main_quit()

-

-var

-  window: pGtkWidget

-gtk_nimrod_init()

-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)

-discard gtk_signal_connect(GTKOBJECT(window), "destroy",

-                   GTK_SIGNAL_FUNC(destroy), nil)

-gtk_widget_show(window)

-gtk_main()

diff --git a/tests/gtk/ex2.nim b/tests/gtk/ex2.nim
deleted file mode 100755
index 80ff6f104..000000000
--- a/tests/gtk/ex2.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-
-import 
-  glib2, gtk2
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-var 
-  window: PGtkWidget
-  button: PGtkWidget
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-button = gtk_button_new_with_label("Click me")
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), button)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                           GTK_SIGNAL_FUNC(destroy), nil)
-gtk_widget_show(button)
-gtk_widget_show(window)
-gtk_main()
diff --git a/tests/gtk/ex3.nim b/tests/gtk/ex3.nim
deleted file mode 100755
index 460b1e4dc..000000000
--- a/tests/gtk/ex3.nim
+++ /dev/null
@@ -1,39 +0,0 @@
-
-import 
-  glib2, gtk2
-
-proc newbutton(ALabel: cstring): PGtkWidget = 
-  Result = gtk_button_new_with_label(ALabel)
-  gtk_widget_show(result)
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-var 
-  window, totalbox, hbox, vbox: PgtkWidget
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL) # Box to divide window in 2 halves:
-totalbox = gtk_vbox_new(true, 10)
-gtk_widget_show(totalbox)   # A box for each half of the screen:
-hbox = gtk_hbox_new(false, 5)
-gtk_widget_show(hbox)
-vbox = gtk_vbox_new(true, 5)
-gtk_widget_show(vbox)       # Put boxes in their halves
-gtk_box_pack_start(GTK_BOX(totalbox), hbox, true, true, 0)
-gtk_box_pack_start(GTK_BOX(totalbox), vbox, true, true, 0) # Now fill boxes with buttons.
-                                                           # Horizontal box
-gtk_box_pack_start(GTK_BOX(hbox), newbutton("Button 1"), false, false, 0)
-gtk_box_pack_start(GTK_BOX(hbox), newbutton("Button 2"), false, false, 0)
-gtk_box_pack_start(GTK_BOX(hbox), newbutton("Button 3"), false, false, 0) # 
-                                                                          # Vertical box
-gtk_box_pack_start(GTK_BOX(vbox), newbutton("Button A"), true, true, 0)
-gtk_box_pack_start(GTK_BOX(vbox), newbutton("Button B"), true, true, 0)
-gtk_box_pack_start(GTK_BOX(vbox), newbutton("Button C"), true, true, 0) # Put 
-                                                                        # totalbox in window
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), totalbox)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                           GTK_SIGNAL_FUNC(destroy), nil)
-gtk_widget_show(window)
-gtk_main()
diff --git a/tests/gtk/ex4.nim b/tests/gtk/ex4.nim
deleted file mode 100755
index a387da972..000000000
--- a/tests/gtk/ex4.nim
+++ /dev/null
@@ -1,31 +0,0 @@
-
-import 
-  glib2, gtk2
-
-proc newbutton(ALabel: cstring): PGtkWidget = 
-  Result = gtk_button_new_with_label(ALabel)
-  gtk_widget_show(result)
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-var 
-  window, maintable: PgtkWidget
-
-proc AddToTable(Widget: PGtkWidget, Left, Right, Top, Bottom: guint) = 
-  gtk_table_attach_defaults(GTK_TABLE(MainTable), Widget, Left, right, top, 
-                            bottom)
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-Maintable = gtk_table_new(6, 6, True)
-gtk_widget_show(MainTable)
-AddToTable(newbutton("1,1 At 1,1"), 1, 2, 1, 2)
-AddToTable(newbutton("2,2 At 3,1"), 3, 5, 1, 3)
-AddToTable(newbutton("4,1 At 4,1"), 1, 5, 4, 5) # Put all in window
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), maintable)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                           GTK_SIGNAL_FUNC(destroy), nil)
-gtk_widget_show(window)
-gtk_main()
diff --git a/tests/gtk/ex5.nim b/tests/gtk/ex5.nim
deleted file mode 100755
index 3a5b076c6..000000000
--- a/tests/gtk/ex5.nim
+++ /dev/null
@@ -1,24 +0,0 @@
-
-import 
-  glib2, gtk2
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-var 
-  window: PGtkWidget
-  button: PGtkWidget
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-button = gtk_button_new_with_label("Click me")
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), button)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                           GTK_SIGNAL_FUNC(destroy), nil)
-discard gtk_signal_connect_object(GTKOBJECT(button), "clicked", 
-                                  GTK_SIGNAL_FUNC(gtk_widget_destroy), 
-                                  GTKOBJECT(window))
-gtk_widget_show(button)
-gtk_widget_show(window)
-gtk_main()
diff --git a/tests/gtk/ex6.nim b/tests/gtk/ex6.nim
deleted file mode 100755
index 5f18786fe..000000000
--- a/tests/gtk/ex6.nim
+++ /dev/null
@@ -1,52 +0,0 @@
-
-import 
-  glib2, gtk2
-
-type 
-  TButtonSignalState = record 
-    Obj: PgtkObject
-    SignalID: int32
-    Disable: bool
-
-  PButtonSignalState = ptr TButtonSignalState
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-proc disablesignal(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  if PButtonSignalState(Data).Disable: 
-    gtk_signal_handler_block(PButtonSignalState(Data).Obj, SignalID)
-  else: 
-    gtk_signal_handler_unblock(PButtonSignalState(Data).Obj, SignalID)
-  PButtonSignalState(Data).disable = not PButtonSignalState(Data).disable
-
-var 
-  window: PGtkWidget
-  quitbutton: PGtkWidget
-  disablebutton: PGTKWidget
-  windowbox: PGTKWidget
-  quitsignal: guint
-  QuitState: TButtonSignalState
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-quitbutton = gtk_button_new_with_label("Quit program")
-disablebutton = gtk_button_new_with_label("Disable button")
-windowbox = gtk_vbox_new(TRUE, 10)
-gtk_box_pack_start(GTK_BOX(windowbox), disablebutton, True, false, 0)
-gtk_box_pack_start(GTK_BOX(windowbox), quitbutton, True, false, 0)
-gtk_container_set_border_width(GTK_CONTAINER(Window), 10)
-gtk_container_add(GTK_Container(window), windowbox)
-gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                   GTK_SIGNAL_FUNC(destroy), nil)
-QuitState.Obj = GTKObject(QuitButton)
-SignalID = gtk_signal_connect_object(QuitState.Obj, "clicked", GTK_SIGNAL_FUNC(
-              gtk_widget_destroy), GTKOBJECT(window))
-QuitState.Disable = True
-discard gtk_signal_connect(GTKOBJECT(disablebutton), "clicked", 
-                   GTK_SIGNAL_FUNC(disablesignal), addr(QuitState))
-gtk_widget_show(quitbutton)
-gtk_widget_show(disablebutton)
-gtk_widget_show(windowbox)
-gtk_widget_show(window)
-gtk_main()
diff --git a/tests/gtk/ex7.nim b/tests/gtk/ex7.nim
deleted file mode 100755
index 53890d1e1..000000000
--- a/tests/gtk/ex7.nim
+++ /dev/null
@@ -1,43 +0,0 @@
-
-import 
-  gdk2, glib2, gtk2
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-const 
-  Inside: cstring = "Mouse is over label"
-  OutSide: cstring = "Mouse is not over label"
-
-var 
-  OverLabel: bool
-  window, box1, box2, stackbox, label1, Label2: PGtkWidget
-
-proc ChangeLabel(P: PGtkWidget, Event: PGdkEventCrossing, 
-                Data: var bool){.cdecl.} = 
-  if not Data: gtk_label_set_text(GTKLABEL(Label2), Inside)
-  else: gtk_label_set_text(GTKLABEL(Label2), Outside)
-  Data = not Data
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-stackbox = gtk_vbox_new(TRUE, 10)
-box1 = gtk_event_box_new()
-label1 = gtk_label_new("Move mouse over label")
-gtk_container_add(GTK_CONTAINER(box1), label1)
-box2 = gtk_event_box_new()
-label2 = gtk_label_new(OutSide)
-gtk_container_add(GTK_CONTAINER(box2), label2)
-gtk_box_pack_start(GTK_BOX(stackbox), box1, TRUE, TRUE, 0)
-gtk_box_pack_start(GTK_BOX(stackbox), box2, TRUE, TRUE, 0)
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), stackbox)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                   GTK_SIGNAL_FUNC(destroy), nil)
-overlabel = False
-discard gtk_signal_connect(GTKOBJECT(box1), "enter_notify_event", 
-                   GTK_SIGNAL_FUNC(ChangeLabel), addr(Overlabel))
-discard gtk_signal_connect(GTKOBJECT(box1), "leave_notify_event", 
-                   GTK_SIGNAL_FUNC(ChangeLabel), addr(Overlabel))
-gtk_widget_show_all(window)
-gtk_main()
diff --git a/tests/gtk/ex8.nim b/tests/gtk/ex8.nim
deleted file mode 100755
index acbba2258..000000000
--- a/tests/gtk/ex8.nim
+++ /dev/null
@@ -1,32 +0,0 @@
-
-import 
-  glib2, gtk2
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-var 
-  window, stackbox, label1, Label2: PGtkWidget
-  labelstyle: pgtkstyle
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-stackbox = gtk_vbox_new(TRUE, 10)
-label1 = gtk_label_new("Red label text")
-labelstyle = gtk_style_copy(gtk_widget_get_style(label1))
-LabelStyle.fg[GTK_STATE_NORMAL].pixel = 0
-LabelStyle.fg[GTK_STATE_NORMAL].red = 0x0000FFFF
-LabelStyle.fg[GTK_STATE_NORMAL].blue = 0
-LabelStyle.fg[GTK_STATE_NORMAL].green = 0
-gtk_widget_set_style(label1, labelstyle) # Uncomment this to see the effect of setting the default style.
-                                         # 
-                                         # gtk_widget_set_default_style(labelstyle)
-label2 = gtk_label_new("Black label text")
-gtk_box_pack_start(GTK_BOX(stackbox), label1, TRUE, TRUE, 0)
-gtk_box_pack_start(GTK_BOX(stackbox), label2, TRUE, TRUE, 0)
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), stackbox)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                   GTK_SIGNAL_FUNC(destroy), nil)
-gtk_widget_show_all(window)
-gtk_main()
diff --git a/tests/gtk/ex9.nim b/tests/gtk/ex9.nim
deleted file mode 100755
index ce2f73862..000000000
--- a/tests/gtk/ex9.nim
+++ /dev/null
@@ -1,47 +0,0 @@
-
-import 
-  gdk2, glib2, gtk2
-
-proc destroy(widget: pGtkWidget, data: pgpointer){.cdecl.} = 
-  gtk_main_quit()
-
-const 
-  Inside: cstring = "Mouse is over label"
-  OutSide: cstring = "Mouse is not over label"
-
-var 
-  window, button1, Button2, Alabel, stackbox: PGtkWidget
-  buttonstyle: pgtkstyle
-  OverButton: bool
-
-proc ChangeLabel(P: PGtkWidget, Event: PGdkEventCrossing, Data: var bool){.cdecl.} = 
-  if Not Data: gtk_label_set_text(GTKLABEL(ALabel), Inside)
-  else: gtk_label_set_text(GTKLABEL(ALabel), Outside)
-  Data = Not Data
-
-gtk_nimrod_init()
-window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
-stackbox = gtk_vbox_new(TRUE, 10)
-button1 = gtk_button_new_with_label("Move mouse over button")
-buttonstyle = gtk_style_copy(gtk_widget_get_style(Button1))
-ButtonStyle.bg[GTK_STATE_PRELIGHT].pixel = 0
-ButtonStyle.bg[GTK_STATE_PRELIGHT].red = 0x0000FFFF'i16
-ButtonStyle.bg[GTK_STATE_PRELIGHT].blue = 0'i16
-ButtonStyle.bg[GTK_STATE_PRELIGHT].green = 0'i16
-gtk_widget_set_style(button1, buttonstyle)
-button2 = gtk_button_new()
-ALabel = gtk_label_new(Outside)
-gtk_container_add(GTK_CONTAINER(button2), ALAbel)
-gtk_box_pack_start(GTK_BOX(stackbox), button1, TRUE, TRUE, 0)
-gtk_box_pack_start(GTK_BOX(stackbox), button2, TRUE, TRUE, 0)
-gtk_container_set_border_width(GTK_CONTAINER(Window), 5)
-gtk_container_add(GTK_Container(window), stackbox)
-discard gtk_signal_connect(GTKOBJECT(window), "destroy", 
-                   GTK_SIGNAL_FUNC(destroy), nil)
-overbutton = False
-discard gtk_signal_connect(GTKOBJECT(button1), "enter_notify_event", 
-                   GTK_SIGNAL_FUNC(ChangeLabel), addr(OverButton))
-discard gtk_signal_connect(GTKOBJECT(button1), "leave_notify_event", 
-                   GTK_SIGNAL_FUNC(ChangeLabel), addr(OverButton))
-gtk_widget_show_all(window)
-gtk_main()
diff --git a/tests/hallo.nim b/tests/hallo.nim
deleted file mode 100755
index 070633793..000000000
--- a/tests/hallo.nim
+++ /dev/null
@@ -1,34 +0,0 @@
-# Hallo world program
-
-echo("Hi! What's your name?")
-var name = readLine(stdin)
-
-if name == "Andreas":
-  echo("What a nice name!")
-elif name == "":
-  echo("Don't you have a name?")
-else:
-  echo("Your name is not Andreas...")
-
-for i in 0..name.len-1:
-  if name[i] == 'm':
-    echo("hey, there is an *m* in your name!")
-
-echo("Please give your password: (12345)")
-var pw = readLine(stdin)
-
-while pw != "12345":
-  echo("Wrong password! Next try: ")
-  pw = readLine(stdin)
-
-echo("""Login complete!
-What do you want to do?
-delete-everything
-restart-computer
-go-for-a-walk""")
-
-case readline(stdin)
-of "delete-everything", "restart-computer":
-  echo("permission denied")
-of "go-for-a-walk":     echo("please yourself")
-else:                   echo("unknown command")
diff --git a/tests/ic/config.nims b/tests/ic/config.nims
new file mode 100644
index 000000000..a622ec309
--- /dev/null
+++ b/tests/ic/config.nims
@@ -0,0 +1 @@
+--mm:refc

diff --git a/tests/ic/mbaseobj.nim b/tests/ic/mbaseobj.nim
new file mode 100644
index 000000000..0f4e4a90d
--- /dev/null
+++ b/tests/ic/mbaseobj.nim
@@ -0,0 +1,7 @@
+
+type
+  Base* = ref object of RootObj
+    s*: string
+
+method m*(b: Base) {.base.} =
+  echo "Base ", b.s
diff --git a/tests/ic/mcompiletime_counter.nim b/tests/ic/mcompiletime_counter.nim
new file mode 100644
index 000000000..6fc7b3f2a
--- /dev/null
+++ b/tests/ic/mcompiletime_counter.nim
@@ -0,0 +1,15 @@
+
+import std/macros
+import std/macrocache
+
+const myCounter = CacheCounter"myCounter"
+
+proc getUniqueId*(): int {.compileTime.} =
+  inc myCounter
+  result = myCounter.value
+
+static:
+  myCounter.inc(3)
+  assert myCounter.value == 3
+
+
diff --git a/tests/ic/mdefconverter.nim b/tests/ic/mdefconverter.nim
new file mode 100644
index 000000000..d0a23f801
--- /dev/null
+++ b/tests/ic/mdefconverter.nim
@@ -0,0 +1,2 @@
+
+converter toBool*(x: int): bool = x != 0
diff --git a/tests/ic/mimports.nim b/tests/ic/mimports.nim
new file mode 100644
index 000000000..50773e001
--- /dev/null
+++ b/tests/ic/mimports.nim
@@ -0,0 +1,9 @@
+from mimportsb {.all.} import fnb1, hfnb3
+
+proc fn1*(): int = 1
+proc fn2*(): int = 2
+proc hfn3(): int = 3
+proc hfn4(): int = 4
+proc hfn5(): int = 5
+
+export mimportsb.fnb2, hfnb3
diff --git a/tests/ic/mimportsb.nim b/tests/ic/mimportsb.nim
new file mode 100644
index 000000000..3cae925c5
--- /dev/null
+++ b/tests/ic/mimportsb.nim
@@ -0,0 +1,4 @@
+proc fnb1*(): int = 1
+proc fnb2*(): int = 2
+proc hfnb3(): int = 3
+proc hfnb4(): int = 4
diff --git a/tests/ic/tcompiletime_counter.nim b/tests/ic/tcompiletime_counter.nim
new file mode 100644
index 000000000..695a6ec27
--- /dev/null
+++ b/tests/ic/tcompiletime_counter.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''id 4'''
+"""
+
+import mcompiletime_counter
+
+const intId = getUniqueId()
+
+echo "id ", intId
+
+#!EDIT!#
+
+discard """
+  output: '''id 4 5'''
+"""
+
+import mcompiletime_counter
+
+const
+  intId = getUniqueId()
+  floatId = getUniqueId()
+
+echo "id ", intId, " ", floatId
+
diff --git a/tests/ic/tconverter.nim b/tests/ic/tconverter.nim
new file mode 100644
index 000000000..aecdf4b48
--- /dev/null
+++ b/tests/ic/tconverter.nim
@@ -0,0 +1,18 @@
+discard """
+  output: "yes"
+"""
+
+import mdefconverter
+
+echo "yes"
+
+#!EDIT!#
+
+discard """
+  output: "converted int to bool"
+"""
+
+import mdefconverter
+
+if 4:
+  echo "converted int to bool"
diff --git a/tests/ic/tgenericinst.nim b/tests/ic/tgenericinst.nim
new file mode 100644
index 000000000..3346764f5
--- /dev/null
+++ b/tests/ic/tgenericinst.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim cpp --incremental:on $file"
+"""
+
+{.emit:"""/*TYPESECTION*/
+#include <iostream>
+  struct Foo { };
+""".}
+
+type Foo {.importcpp.} = object
+echo $Foo() #Notice the generic is instantiate in the this module if not, it wouldnt find Foo
\ No newline at end of file
diff --git a/tests/ic/tgenerics.nim b/tests/ic/tgenerics.nim
new file mode 100644
index 000000000..138799e85
--- /dev/null
+++ b/tests/ic/tgenerics.nim
@@ -0,0 +1,38 @@
+discard """
+  output: "bar"
+"""
+
+import tables
+
+var tab: Table[string, string]
+
+tab["foo"] = "bar"
+echo tab["foo"]
+
+#!EDIT!#
+
+discard """
+  output: "bar 3"
+"""
+
+import tables
+
+var tab: Table[string, string]
+var tab2: Table[string, int]
+
+tab["foo"] = "bar"
+tab2["meh"] = 3
+echo tab["foo"], " ", tab2["meh"]
+
+#!EDIT!#
+
+discard """
+  output: "3"
+"""
+
+import tables
+
+var tab2: Table[string, int]
+
+tab2["meh"] = 3
+echo tab2["meh"]
diff --git a/tests/ic/thallo.nim b/tests/ic/thallo.nim
new file mode 100644
index 000000000..7ead7c8ba
--- /dev/null
+++ b/tests/ic/thallo.nim
@@ -0,0 +1,28 @@
+discard """
+  output: "Hello World"
+"""
+
+const str = "Hello World"
+echo str
+
+# Splitters are done with this special comment:
+
+#!EDIT!#
+
+discard """
+  output: "Hello World B"
+"""
+
+const str = "Hello World"
+echo str, " B"
+
+#!EDIT!#
+
+discard """
+  output: "Hello World C"
+"""
+
+const str = "Hello World"
+var x = 7
+if 3+4 == x:
+  echo str, " C"
diff --git a/tests/ic/timports.nim b/tests/ic/timports.nim
new file mode 100644
index 000000000..518a689f5
--- /dev/null
+++ b/tests/ic/timports.nim
@@ -0,0 +1,29 @@
+import mimports
+doAssert fn1() == 1
+doAssert not declared(hfn3)
+
+#!EDIT!#
+
+import mimports {.all.}
+doAssert fn1() == 1
+doAssert declared(hfn3)
+doAssert hfn3() == 3
+doAssert mimports.hfn4() == 4
+
+# reexports
+doAssert not declared(fnb1)
+doAssert not declared(hfnb4)
+doAssert fnb2() == 2
+doAssert hfnb3() == 3
+
+#!EDIT!#
+
+from mimports {.all.} import hfn3
+doAssert not declared(fn1)
+from mimports {.all.} as bar import fn1
+doAssert fn1() == 1
+doAssert hfn3() == 3
+doAssert not declared(hfn4)
+doAssert declared(mimports.hfn4)
+doAssert mimports.hfn4() == 4
+doAssert bar.hfn4() == 4
diff --git a/tests/ic/tmethods.nim b/tests/ic/tmethods.nim
new file mode 100644
index 000000000..251f26889
--- /dev/null
+++ b/tests/ic/tmethods.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''Base abc'''
+"""
+
+import mbaseobj
+
+var c = Base(s: "abc")
+m c
+
+#!EDIT!#
+
+discard """
+  output: '''Base abc
+Inherited abc'''
+"""
+
+import mbaseobj
+
+type
+  Inherited = ref object of Base
+
+method m(i: Inherited) =
+  procCall m(Base i)
+  echo "Inherited ", i.s
+
+var c = Inherited(s: "abc")
+m c
+
diff --git a/tests/ic/tstdlib_import_changed.nim b/tests/ic/tstdlib_import_changed.nim
new file mode 100644
index 000000000..da69a53b5
--- /dev/null
+++ b/tests/ic/tstdlib_import_changed.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''yes'''
+"""
+
+echo "yes"
+
+#!EDIT!#
+
+discard """
+  output: '''yes2'''
+"""
+
+import std / [monotimes]
+#discard getMonoTime()
+echo "yes2"
diff --git a/tests/import/buzz/m21496.nim b/tests/import/buzz/m21496.nim
new file mode 100644
index 000000000..677324000
--- /dev/null
+++ b/tests/import/buzz/m21496.nim
@@ -0,0 +1 @@
+proc fb*: string = "buzz!"
\ No newline at end of file
diff --git a/tests/import/fizz/m21496.nim b/tests/import/fizz/m21496.nim
new file mode 100644
index 000000000..525b653d6
--- /dev/null
+++ b/tests/import/fizz/m21496.nim
@@ -0,0 +1 @@
+proc fb*: string = "fizz!"
\ No newline at end of file
diff --git a/tests/import/t21496.nim b/tests/import/t21496.nim
new file mode 100644
index 000000000..1a4907b12
--- /dev/null
+++ b/tests/import/t21496.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "ambiguous identifier: 'm21496'"
+"""
+
+import fizz/m21496, buzz/m21496
+
+# bug #21496
+
+discard m21496.fb()
diff --git a/tests/import/t22065.nim b/tests/import/t22065.nim
new file mode 100644
index 000000000..dfd87a107
--- /dev/null
+++ b/tests/import/t22065.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "cannot open file: ./sugar"
+"""
+
+import ./sugar
\ No newline at end of file
diff --git a/tests/import/t22208.nim b/tests/import/t22208.nim
new file mode 100644
index 000000000..b935d751c
--- /dev/null
+++ b/tests/import/t22208.nim
@@ -0,0 +1,6 @@
+import fizz/m21496 as alas
+import buzz/m21496
+
+# bug #21496
+
+doAssert m21496.fb() == "buzz!"
diff --git a/tests/import/t23167.nim b/tests/import/t23167.nim
new file mode 100644
index 000000000..0891ee2af
--- /dev/null
+++ b/tests/import/t23167.nim
@@ -0,0 +1,5 @@
+# bug #23167
+template sharedImport() =
+  import std / os
+
+sharedImport()
diff --git a/tests/import_in_config/nim.cfg b/tests/import_in_config/nim.cfg
new file mode 100644
index 000000000..af112d112
--- /dev/null
+++ b/tests/import_in_config/nim.cfg
@@ -0,0 +1,2 @@
+import = "other"
+path = "$projectDir"
diff --git a/tests/import_in_config/other.nim b/tests/import_in_config/other.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/import_in_config/other.nim
diff --git a/tests/import_in_config/tmain.nim b/tests/import_in_config/tmain.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/import_in_config/tmain.nim
diff --git a/tests/importalls/m1.nim b/tests/importalls/m1.nim
new file mode 100644
index 000000000..b6ccbf5da
--- /dev/null
+++ b/tests/importalls/m1.nim
@@ -0,0 +1,70 @@
+import ./m2
+import ./m3 {.all.} as m3
+from ./m3 as m3Bis import nil
+
+doAssert m3h2 == 2
+export m3h2
+
+export m3Bis.m3p1
+
+const foo0* = 2
+const foo1 = bar1
+
+const foo1Aux = 2
+export foo1Aux
+
+doAssert not declared(bar2)
+doAssert not compiles(bar2)
+
+var foo2 = 2
+let foo3 = 2
+
+type Foo4 = enum
+  kg1, kg2
+
+type Foo4b {.pure.} = enum
+  foo4b1, foo4b2
+
+type Foo5 = object
+  z1: string
+  z2: Foo4
+  z3: int
+  z4*: int
+
+proc `z3`*(a: Foo5): auto =
+  a.z3 * 10
+
+proc foo6(): auto = 2
+proc foo6b*(): auto = 2
+template foo7: untyped = 2
+macro foo8(): untyped = discard
+template foo9(a: int) = discard
+
+block:
+  template foo10: untyped = 2
+  type Foo11 = enum
+    kg1b, kg2b
+  proc foo12(): auto = 2
+
+proc initFoo5*(z3: int): Foo5 = Foo5(z3: z3)
+
+func foo13(): auto = 2
+iterator foo14a(): int = discard
+iterator foo14b*(): int = discard
+iterator foo14c(): int {.closure.} = discard
+iterator foo14d(): int {.inline.} = discard
+
+# fwd declare
+proc foo15(): int
+proc foo15(): int = 2
+
+proc foo16*(): int
+proc foo16(): int = 2
+
+proc foo17*(): int
+proc foo17*(): int = 2
+
+# other
+type A1 = distinct int
+type A2 = distinct int
+converter foo18(x: A1): A2 = discard
diff --git a/tests/importalls/m2.nim b/tests/importalls/m2.nim
new file mode 100644
index 000000000..186650f68
--- /dev/null
+++ b/tests/importalls/m2.nim
@@ -0,0 +1,3 @@
+const bar1* = 2
+const bar2 = 2
+const bar3 = 3
diff --git a/tests/importalls/m3.nim b/tests/importalls/m3.nim
new file mode 100644
index 000000000..caeae2a01
--- /dev/null
+++ b/tests/importalls/m3.nim
@@ -0,0 +1,5 @@
+# xxx use below naming convention in other test files: p: public, h: hidden
+const m3p1* = 2
+const m3h2 = 2
+const m3h3 = 3
+const m3h4 = 4
diff --git a/tests/importalls/m4.nim b/tests/importalls/m4.nim
new file mode 100644
index 000000000..77ec65c61
--- /dev/null
+++ b/tests/importalls/m4.nim
@@ -0,0 +1,9 @@
+import ./m3 {.all.}
+import ./m3 as m3b
+export m3b
+export m3h3
+export m3.m3h4
+
+import ./m2 {.all.} as m2b
+export m2b except bar3
+
diff --git a/tests/importalls/mt0.nim b/tests/importalls/mt0.nim
new file mode 100644
index 000000000..154d30ef9
--- /dev/null
+++ b/tests/importalls/mt0.nim
@@ -0,0 +1,9 @@
+import ./m1 as m
+doAssert compiles(foo0)
+doAssert not compiles(foo1)
+doAssert foo6b() == 2
+doAssert m3h2 == 2
+
+var f = initFoo5(z3=3)
+doAssert f.z3 == 30
+doAssert z3(f) == 30
diff --git a/tests/importalls/mt1.nim b/tests/importalls/mt1.nim
new file mode 100644
index 000000000..b7983945c
--- /dev/null
+++ b/tests/importalls/mt1.nim
@@ -0,0 +1,23 @@
+import ./m1 {.all.} as m
+doAssert foo1 == 2
+doAssert m.foo1 == 2
+
+doAssert m.m3h2 == 2
+doAssert m3h2 == 2
+doAssert m.foo1Aux == 2
+doAssert m.m3p1 == 2
+
+## field access
+import std/importutils
+privateAccess(Foo5)
+var x = Foo5(z1: "foo", z2: m.kg1)
+doAssert x.z1 == "foo"
+
+var f0: Foo5
+f0.z3 = 3
+doAssert f0.z3 == 3
+var f = initFoo5(z3=3)
+doAssert f.z3 == 3
+doAssert z3(f) == 30
+doAssert m.z3(f) == 30
+doAssert not compiles(mt1.`z3`(f)) # z3 is an imported symbol
diff --git a/tests/importalls/mt2.nim b/tests/importalls/mt2.nim
new file mode 100644
index 000000000..52edbb69e
--- /dev/null
+++ b/tests/importalls/mt2.nim
@@ -0,0 +1,104 @@
+from ./m1 {.all.} as r1 import foo1
+from ./m1 {.all.} as r2 import foo7
+
+block: # different symbol kinds
+  doAssert foo1 == 2
+  doAssert r1.foo1 == 2
+  doAssert r1.foo2 == 2
+  doAssert compiles(foo1)
+  doAssert compiles(r1.foo2)
+  doAssert not compiles(foo2)
+  doAssert not compiles(m3h2)
+  doAssert r1.foo3 == 2
+
+  block: # enum
+    var a: r1.Foo4
+    let a1 = r1.kg1
+    doAssert a1 == r1.Foo4.kg1
+    type A = r1.Foo4
+    doAssert a1 == A.kg1
+    doAssert not compiles(kg1)
+    doAssert compiles(A.kg1)
+    var witness = false
+    for ai in r1.Foo4:
+      doAssert ai == a
+      doAssert ai == a1
+      witness = true
+      break
+    doAssert witness
+
+  block: # {.pure.} enum
+    var a: r1.Foo4b
+    doAssert not compiles(r1.foo4b1) # because pure
+    doAssert not compiles(foo4b1)
+    let a1 = r1.Foo4b.foo4b1
+    doAssert a1 == a
+    type A = r1.Foo4b
+    doAssert a1 == A.foo4b1
+    var witness = false
+    for ai in A:
+      doAssert ai == a
+      doAssert ai == a1
+      witness = true
+      break
+    doAssert witness
+
+  block: # object
+    doAssert compiles(r1.Foo5)
+    var a: r1.Foo5
+    doAssert compiles(a.z4)
+    doAssert not compiles(a.z3)
+
+  block: # remaining symbol kinds
+    doAssert r1.foo6() == 2
+    doAssert r1.foo6b() == 2
+    doAssert foo7() == 2
+    doAssert r2.foo6b() == 2
+
+    r1.foo8()
+    r1.foo9(1)
+    doAssert r1.foo13() == 2
+    for a in r1.foo14a(): discard
+    for a in r1.foo14b(): discard
+    for a in r1.foo14c(): discard
+    for a in r1.foo14d(): discard
+    doAssert r1.foo15() == 2
+    doAssert r1.foo16() == 2
+    doAssert r1.foo17() == 2
+    doAssert compiles(r1.foo18)
+    doAssert declared(r1.foo18)
+
+  block: # declarations at block scope should not be visible
+    doAssert declared(foo7)
+    doAssert declared(r1.foo6)
+    doAssert not declared(foo10)
+    doAssert not declared(foo6)
+    doAssert not declared(r1.Foo11)
+    doAssert not declared(r1.kg1b)
+    doAssert not declared(r1.foo12)
+    doAssert not compiles(r1.foo12())
+
+## field access
+import std/importutils
+privateAccess(r1.Foo5)
+var x = r1.Foo5(z1: "foo", z2: r1.kg1)
+doAssert x.z1 == "foo"
+
+var f0: r1.Foo5
+f0.z3 = 3
+doAssert f0.z3 == 3
+var f = r1.initFoo5(z3=3)
+doAssert f.z3 == 3
+doAssert r1.z3(f) == 30
+
+import ./m1 as r3
+doAssert not declared(foo2)
+doAssert not declared(r3.foo2)
+
+from ./m1 {.all.} as r4 import nil
+doAssert not declared(foo2)
+doAssert declared(r4.foo2)
+
+from ./m1 {.all.} import nil
+doAssert not declared(foo2)
+doAssert declared(m1.foo2)
diff --git a/tests/importalls/mt3.nim b/tests/importalls/mt3.nim
new file mode 100644
index 000000000..2bd7fd79d
--- /dev/null
+++ b/tests/importalls/mt3.nim
@@ -0,0 +1,12 @@
+import ./m1 {.all.}
+  # D20201209T194412:here keep this as is, without `as`, so that mt8.nim test keeps
+  # checking that the original module symbol for `m1` isn't modified and that
+  # only the alias in `createModuleAlias` is affected.
+doAssert declared(m1.foo1)
+doAssert foo1 == 2
+
+
+doAssert m1.foo1 == 2
+
+doAssert not compiles(mt3.foo0) # foo0 is an imported symbol
+doAssert not compiles(mt3.foo1) # ditto
diff --git a/tests/importalls/mt4.nim b/tests/importalls/mt4.nim
new file mode 100644
index 000000000..cd7d32aad
--- /dev/null
+++ b/tests/importalls/mt4.nim
@@ -0,0 +1,4 @@
+import ./m1 {.all.} except foo1
+doAssert foo2 == 2
+doAssert declared(foo2)
+doAssert not compiles(foo1)
diff --git a/tests/importalls/mt4b.nim b/tests/importalls/mt4b.nim
new file mode 100644
index 000000000..4578bc54c
--- /dev/null
+++ b/tests/importalls/mt4b.nim
@@ -0,0 +1,3 @@
+from ./m1 {.all.} as m2 import nil
+doAssert not compiles(foo1)
+doAssert m2.foo1 == 2
diff --git a/tests/importalls/mt5.nim b/tests/importalls/mt5.nim
new file mode 100644
index 000000000..5c5785af6
--- /dev/null
+++ b/tests/importalls/mt5.nim
@@ -0,0 +1,9 @@
+import ./m1 {.all.} as m2 except foo1
+doAssert foo2 == 2
+doAssert not compiles(foo1)
+doAssert m2.foo1 == 2
+doAssert compiles(m2.foo1)
+
+from system {.all.} as s import ThisIsSystem
+doAssert ThisIsSystem
+doAssert s.ThisIsSystem
diff --git a/tests/importalls/mt6.nim b/tests/importalls/mt6.nim
new file mode 100644
index 000000000..ac6f542b6
--- /dev/null
+++ b/tests/importalls/mt6.nim
@@ -0,0 +1,13 @@
+import ./m1 {.all.} as m2
+doAssert compiles(foo1)
+doAssert compiles(m2.foo1)
+doAssert declared(foo1)
+doAssert declared(m2.foo0) # public: works fine
+
+doAssert m2.foo1 == 2
+doAssert declared(m2.foo1)
+doAssert not declared(m2.nonexistent)
+
+# also tests the quoted `""` import
+import "."/"m1" {.all.} as m1b
+doAssert compiles(m1b.foo1)
diff --git a/tests/importalls/mt7.nim b/tests/importalls/mt7.nim
new file mode 100644
index 000000000..45a664610
--- /dev/null
+++ b/tests/importalls/mt7.nim
@@ -0,0 +1,14 @@
+include ./m1
+doAssert compiles(foo1)
+doAssert compiles(mt7.foo1)
+doAssert declared(foo1)
+doAssert declared(mt7.foo1)
+doAssert declared(mt7.foo0)
+
+var f0: Foo5
+f0.z3 = 3
+doAssert f0.z3 == 3
+var f = initFoo5(z3=3)
+doAssert f.z3 == 3
+doAssert mt7.z3(f) == 30
+doAssert z3(f) == 30
diff --git a/tests/importalls/mt8.nim b/tests/importalls/mt8.nim
new file mode 100644
index 000000000..f484e7b01
--- /dev/null
+++ b/tests/importalls/mt8.nim
@@ -0,0 +1,23 @@
+#[
+test multiple imports
+]#
+
+{.warning[UnusedImport]: off.}
+import ./m1, m2 {.all.}, ./m3 {.all.}
+  # make sure this keeps using `import ./m1` without as.
+
+# m1 is regularly imported
+doAssert declared(m1.foo0)
+doAssert declared(foo0)
+
+doAssert not declared(m1.foo1)
+  # if we didn't call `createModuleAlias` even for `import f1 {.all.}`,
+  # this would fail, see D20201209T194412.
+
+# m2
+doAssert declared(m2.bar2)
+doAssert declared(bar2)
+
+# m3
+doAssert declared(m3.m3h2)
+doAssert declared(m3h2)
diff --git a/tests/importalls/mt9.nim b/tests/importalls/mt9.nim
new file mode 100644
index 000000000..42d48ecbd
--- /dev/null
+++ b/tests/importalls/mt9.nim
@@ -0,0 +1,12 @@
+# tests re-export of a module with import {.all.}
+
+import ./m4
+
+doAssert m3p1 == 2
+doAssert not declared(m3h2)
+doAssert m3h3 == 3
+doAssert m3h4 == 4
+
+doAssert bar1 == 2
+doAssert bar2 == 2
+doAssert not declared(bar3)
diff --git a/tests/importalls/tmain2.nim b/tests/importalls/tmain2.nim
new file mode 100644
index 000000000..596f0f135
--- /dev/null
+++ b/tests/importalls/tmain2.nim
@@ -0,0 +1,7 @@
+discard """
+joinable: false # for clarity, but not necessary
+"""
+
+{.warning[UnusedImport]: off.}
+# only import `mt*.nim` here; these depend on `m*.nim`
+import "."/[mt0,mt1,mt2,mt3,mt4,mt4b,mt5,mt6,mt7,mt8,mt9]
diff --git a/tests/init/t8314.nim b/tests/init/t8314.nim
new file mode 100644
index 000000000..47c8480c2
--- /dev/null
+++ b/tests/init/t8314.nim
@@ -0,0 +1,27 @@
+discard """
+  nimout: '''
+t8314.nim(14, 7) Hint: BEGIN [User]
+t8314.nim(25, 7) Hint: END [User]
+  '''
+
+output: '''
+1
+1
+1
+'''
+"""
+
+{.hint: "BEGIN".}
+proc foo(x: range[1..10]) =
+  block:
+    var (y,) = (x,)
+    echo y
+  block:
+    var (_,y) = (1,x)
+    echo y
+  block:
+    var (y,_,) = (x,1,)
+    echo y
+{.hint: "END".}
+
+foo(1)
diff --git a/tests/init/tcompiles.nim b/tests/init/tcompiles.nim
new file mode 100644
index 000000000..67e17b241
--- /dev/null
+++ b/tests/init/tcompiles.nim
@@ -0,0 +1,101 @@
+discard """
+  matrix: "--warningAsError:ProveInit --warningAsError:Uninit"
+"""
+
+{.experimental: "strictdefs".}
+
+type Test = object
+  id: int
+
+proc foo {.noreturn.} = discard
+
+block:
+  proc test(x: bool): Test =
+    if x:
+      foo()
+    else:
+      foo()
+
+block:
+  proc test(x: bool): Test =
+    if x:
+      result = Test()
+    else:
+      foo()
+
+  discard test(true)
+
+block:
+  proc test(x: bool): Test =
+    if x:
+      result = Test()
+    else:
+      return Test()
+
+  discard test(true)
+
+block:
+  proc test(x: bool): Test =
+    if x:
+      return Test()
+    else:
+      return Test()
+
+  discard test(true)
+
+block:
+  proc test(x: bool): Test =
+    if x:
+      result = Test()
+    else:
+      result = Test()
+      return
+
+  discard test(true)
+
+block:
+  proc test(x: bool): Test =
+    if x:
+      result = Test()
+      return
+    else:
+      raise newException(ValueError, "unreachable")
+
+  discard test(true)
+
+# bug #21615
+# bug #16735
+
+block:
+  type Test {.requiresInit.} = object
+    id: int
+
+  proc bar(): int =
+    raise newException(CatchableError, "error")
+
+  proc test(): Test =
+    raise newException(CatchableError, "")
+
+  template catchError(body) =
+    var done = false
+    try:
+      body
+    except CatchableError:
+      done = true
+    doAssert done
+
+  catchError:
+    echo test()
+
+  catchError:
+    echo bar()
+
+block:
+  proc foo(x: ptr int) =
+    discard
+
+  proc main =
+    var s: int
+    foo(addr s)
+
+  main()
diff --git a/tests/init/tinitchecks_v2.nim b/tests/init/tinitchecks_v2.nim
new file mode 100644
index 000000000..f7716bcca
--- /dev/null
+++ b/tests/init/tinitchecks_v2.nim
@@ -0,0 +1,83 @@
+discard """
+cmd: "nim check $file"
+action: "compile"
+"""
+
+{.experimental: "strictDefs".}
+
+proc myopen(f: out File; s: string): bool =
+  f = default(File)
+  result = false
+
+proc main =
+  var f: File
+  if myopen(f, "aarg"):
+    f.close
+
+proc invalid =
+  var s: seq[string]
+  s.add "abc" #[tt.Warning
+  ^ use explicit initialization of 's' for clarity [Uninit] ]#
+
+proc valid =
+  var s: seq[string] = @[]
+  s.add "abc" # valid!
+
+main()
+invalid()
+valid()
+
+proc branchy(cond: bool) =
+  var s: seq[string]
+  if cond:
+    s = @["y"]
+  else:
+    s = @[]
+  s.add "abc" # valid!
+
+branchy true
+
+proc p(x: out int; y: out string; cond: bool) = #[tt.Warning
+                   ^ Cannot prove that 'y' is initialized. This will become a compile time error in the future. [ProveInit] ]#
+  x = 4
+  if cond:
+    y = "abc"
+  # error: not every path initializes 'y'
+
+var gl: int
+var gs: string
+p gl, gs, false
+
+proc canRaise(x: int): int =
+  result = x
+  raise newException(ValueError, "wrong")
+
+proc currentlyValid(x: out int; y: out string; cond: bool) =
+  x = canRaise(45)
+  y = "abc" # <-- error: not every path initializes 'y'
+
+currentlyValid gl, gs, false
+
+block: # previously effects/toutparam
+  proc gah[T](x: out T) =
+    x = 3
+
+  proc arr1 =
+    var a: array[2, int]
+    var x: int
+    gah(x)
+    a[0] = 3
+    a[x] = 3
+    echo x
+
+  arr1()
+
+  proc arr2 =
+    var a: array[2, int]
+    var x: int
+    a[0] = 3
+    a[x] = 3 #[tt.Warning
+      ^ use explicit initialization of 'x' for clarity [Uninit] ]#
+    echo x
+
+  arr2()
diff --git a/tests/init/tlet.nim b/tests/init/tlet.nim
new file mode 100644
index 000000000..e32bedb18
--- /dev/null
+++ b/tests/init/tlet.nim
@@ -0,0 +1,55 @@
+{.experimental: "strictDefs".}
+
+proc bar(x: out string) =
+  x = "abc"
+
+template moe = # bug #21043
+  try:
+    discard
+  except ValueError as e:
+    echo(e.msg)
+
+template moe0 {.dirty.} = # bug #21043
+  try:
+    discard
+  except ValueError as e:
+    echo(e.msg)
+
+proc foo() =
+  block:
+    let x: string
+    if true:
+      x = "abc"
+    else:
+      x = "def"
+    doAssert x == "abc"
+  block:
+    let y: string
+    bar(y)
+    doAssert y == "abc"
+  block:
+    let x: string
+    if true:
+      x = "abc"
+      discard "abc"
+    else:
+      x = "def"
+      discard "def"
+    doAssert x == "abc"
+  block: #
+    let x {.used.} : int
+  block: #
+    let x: float
+    x = 1.234
+    doAssert x == 1.234
+
+  block:
+    try:
+      discard
+    except ValueError as e:
+      echo(e.msg)
+  moe()
+  moe0()
+
+static: foo()
+foo()
diff --git a/tests/init/tlet_uninit2.nim b/tests/init/tlet_uninit2.nim
new file mode 100644
index 000000000..174aa28f7
--- /dev/null
+++ b/tests/init/tlet_uninit2.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "'let' symbol requires an initialization"
+"""
+
+let x: int
\ No newline at end of file
diff --git a/tests/init/tlet_uninit3.nim b/tests/init/tlet_uninit3.nim
new file mode 100644
index 000000000..cb786f8c8
--- /dev/null
+++ b/tests/init/tlet_uninit3.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: "nim check $file"
+  action: "reject"
+  nimout: '''
+tlet_uninit3.nim(13, 5) Error: 'let' symbol requires an initialization
+tlet_uninit3.nim(19, 5) Error: 'x' cannot be assigned to
+tlet_uninit3.nim(23, 11) Error: 'let' symbol requires an initialization
+'''
+"""
+
+{.experimental: "strictDefs".}
+
+let global {.used.}: int
+
+proc foo() =
+  block:
+    let x: int
+    x = 13
+    x = 14
+
+  block:
+    let x: int
+    doAssert x == 0
+foo()
diff --git a/tests/init/tlet_uninit4.nim b/tests/init/tlet_uninit4.nim
new file mode 100644
index 000000000..c57d15ff8
--- /dev/null
+++ b/tests/init/tlet_uninit4.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got <string>"
+"""
+
+{.experimental: "strictDefs".}
+
+proc foo(x: var string) =
+  echo x
+
+proc bar() =
+  let x: string
+  foo(x)
diff --git a/tests/init/toutparam_subtype.nim b/tests/init/toutparam_subtype.nim
new file mode 100644
index 000000000..3597f1459
--- /dev/null
+++ b/tests/init/toutparam_subtype.nim
@@ -0,0 +1,24 @@
+discard """
+cmd: "nim check $file"
+action: "compile"
+errormsg: "type mismatch: got <Subclass[system.int]>"
+line: 21
+"""
+
+{.experimental: "strictDefs".}
+
+type
+  Superclass[T] = object of RootObj
+    a: T
+  Subclass[T] = object of Superclass[T]
+    s: string
+
+proc init[T](x: out Superclass[T]) =
+  x = Superclass(a: 8)
+
+proc subtypeCheck =
+  var v: Subclass[int]
+  init(v)
+  echo v.s # the 's' field was never initialized!
+
+subtypeCheck()
diff --git a/tests/init/toutparams.nim b/tests/init/toutparams.nim
new file mode 100644
index 000000000..590768599
--- /dev/null
+++ b/tests/init/toutparams.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "--warningAsError:ProveInit"
+"""
+
+{.experimental: "strictdefs".}
+
+proc foo(x: out int) =
+  x = 1
+
+proc bar(x: out int) =
+  foo(x)
+
+var s: int
+bar(s)
diff --git a/tests/init/tproveinit.nim b/tests/init/tproveinit.nim
new file mode 100644
index 000000000..c9f688309
--- /dev/null
+++ b/tests/init/tproveinit.nim
@@ -0,0 +1,18 @@
+discard """
+  joinable: false
+"""
+
+{.warningAsError[ProveInit]:on.}
+template main() =
+  proc fn(): var int =
+    discard
+  discard fn()
+doAssert not compiles(main())
+
+# bug #9901
+import std/[sequtils, times]
+proc parseMyDates(line: string): DateTime =
+  result = parse(line, "yyyy-MM-dd")
+var dateStrings = @["2018-12-01", "2018-12-02", "2018-12-03"]
+var parsed = dateStrings.map(parseMyDates)
+discard parsed
diff --git a/tests/init/treturns.nim b/tests/init/treturns.nim
new file mode 100644
index 000000000..18cebe0b1
--- /dev/null
+++ b/tests/init/treturns.nim
@@ -0,0 +1,106 @@
+{.experimental: "strictdefs".}
+
+type Test = object
+  id: int
+
+proc foo {.noreturn.} = discard
+
+proc test1(): Test =
+  if true: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+    return Test()
+  else:
+    return
+
+proc test0(): Test =
+  if true: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+    return
+  else:
+    foo()
+
+proc test2(): Test =
+  if true: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+    return
+  else:
+    return
+
+proc test3(): Test =
+  if true: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+    return
+  else:
+    return Test()
+
+proc test4(): Test =
+  if true: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+    return
+  else:
+    result = Test()
+    return
+
+proc test5(x: bool): Test =
+  case x: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+  of true:
+    return
+  else:
+    return Test()
+
+proc test6(x: bool): Test =
+  case x: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+  of true:
+    return
+  else:
+    return
+
+proc test7(x: bool): Test =
+  case x: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+  of true:
+    return
+  else:
+    discard
+
+proc test8(x: bool): Test =
+  case x: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+  of true:
+    discard
+  else:
+    raise
+
+proc hasImportStmt(): bool =
+  if false: #[tt.Warning
+  ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+    return true
+  else:
+    discard
+
+discard hasImportStmt()
+
+block:
+  proc hasImportStmt(): bool =
+    if false: #[tt.Warning
+    ^ Cannot prove that 'result' is initialized. This will become a compile time error in the future. [ProveInit]]#
+      return true
+    else:
+      return
+
+  discard hasImportStmt()
+
+block:
+  block:
+    proc foo(x: var int) =
+      discard
+
+    proc main =
+      var s: int
+      foo(s)#[tt.Warning
+          ^ use explicit initialization of 's' for clarity [Uninit]]#
+
+    main()
+
diff --git a/tests/init/tuninit1.nim b/tests/init/tuninit1.nim
new file mode 100644
index 000000000..ac3007e8d
--- /dev/null
+++ b/tests/init/tuninit1.nim
@@ -0,0 +1,36 @@
+discard """
+  nimout: "tuninit1.nim(34, 11) Warning: use explicit initialization of 'y' for clarity [Uninit]"
+  action: compile
+"""
+
+import strutils
+{.experimental: "strictDefs".}
+{.warning[Uninit]:on.}
+
+proc p =
+  var x, y, z: int
+  if stdin.readLine == "true":
+    x = 34
+
+    while false:
+      y = 999
+      break
+
+    while true:
+      if x == 12: break
+      y = 9999
+
+    try:
+      z = parseInt("1233")
+    except Exception:
+      case x
+      of 34: z = 123
+      of 13: z = 34
+      else: z = 8
+  else:
+    y = 3444
+    x = 3111
+    z = 0
+  echo x, y, z
+
+p()
diff --git a/tests/init/tuninit2.nim b/tests/init/tuninit2.nim
new file mode 100644
index 000000000..950895c02
--- /dev/null
+++ b/tests/init/tuninit2.nim
@@ -0,0 +1,54 @@
+# bug #2316
+
+type
+    EventType = enum
+      QuitEvent = 5
+    AppMain* = ref object of RootObj
+        width: int
+        height: int
+        title: string
+        running: bool
+        event_type: EventType
+    App* = ref object of AppMain
+        draw_proc: proc(app: AppMain): void {.closure.}
+        events_proc: proc(app: AppMain): void {.closure.}
+        update_proc: proc(app: AppMain, dt: float): void {.closure.}
+        load_proc: proc(app: AppMain): void {.closure.}
+
+
+proc initApp*(t: string, w, h: int): App =
+    App(width: w, height: h, title: t, event_type: EventType.QuitEvent)
+
+
+method getTitle*(self: AppMain): string = self.title
+method getWidth*(self: AppMain): int = self.width
+method getHeight*(self: AppMain): int = self.height
+
+
+method draw*(self: App, draw: proc(app: AppMain)): void =
+    self.draw_proc = draw
+
+method load*(self: App, load: proc(a: AppMain)): void =
+    self.load_proc = load
+
+method events*(self: App, events: proc(app: AppMain)): void =
+    self.events_proc = events
+
+method update*(self: App, update: proc(app: AppMain, delta: float)): void =
+    self.update_proc = update
+
+method run*(self: App): void = discard
+
+var mygame = initApp("Example", 800, 600)
+
+mygame.load(proc(app: AppMain): void =
+    echo app.getTitle()
+    echo app.getWidth()
+    echo app.getHeight()
+)
+
+mygame.events(proc(app: AppMain): void =
+    discard
+)
+
+mygame.run()
diff --git a/tests/init/tzeroarray.nim b/tests/init/tzeroarray.nim
new file mode 100644
index 000000000..b784b601e
--- /dev/null
+++ b/tests/init/tzeroarray.nim
@@ -0,0 +1,18 @@
+discard """
+  output: done
+"""
+
+for i in 0 .. 1:
+  var a: array[0..4, int]
+  if a[0] != 0: quit "bug"
+  a[0] = 6
+
+proc main =
+  for i in 0 .. 1:
+    var a: array[0..4, int]
+    if a[0] != 0: quit "bug"
+    a[0] = 6
+
+main()
+echo "done"
+
diff --git a/tests/int/t1.nim b/tests/int/t1.nim
new file mode 100644
index 000000000..6e5cdc8d4
--- /dev/null
+++ b/tests/int/t1.nim
@@ -0,0 +1,61 @@
+discard """
+  targets: "c cpp"
+"""
+
+doAssert typeOf(1.int64 + 1.int) is int64
+doAssert typeOf(1.uint64 + 1.uint) is uint64
+doAssert int64 is SomeNumber
+doAssert int64 is (SomeNumber and not(uint32|uint64|uint|int))
+doAssert int64 is (not(uint32|uint64|uint|int))
+doAssert int isnot int64
+doAssert int64 isnot int
+var myInt16 = 5i16
+var myInt: int
+doAssert typeOf(myInt16 + 34) is int16    # of type `int16`
+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/tarithm.nim b/tests/int/tarithm.nim
new file mode 100644
index 000000000..d0943d225
--- /dev/null
+++ b/tests/int/tarithm.nim
@@ -0,0 +1,187 @@
+discard """
+  output: '''
+int32
+int32
+1280
+1280
+3
+1
+2
+2
+3
+4294967295
+2
+0
+tUnsignedOps OK
+'''
+nimout: "tUnsignedOps OK"
+"""
+
+import typetraits
+
+
+block tand:
+  # bug #5216
+  echo(name typeof((0x0A'i8 and 0x7F'i32) shl 7'i32))
+
+  let i8 = 0x0A'i8
+  echo(name typeof((i8 and 0x7F'i32) shl 7'i32))
+
+  echo((0x0A'i8 and 0x7F'i32) shl 7'i32)
+
+  let ii8 = 0x0A'i8
+  echo((ii8 and 0x7F'i32) shl 7'i32)
+
+
+
+block tcast:
+  template crossCheck(ty: untyped, exp: untyped) =
+    let rt = ty(exp)
+    const ct = ty(exp)
+    if $rt != $ct:
+      echo astToStr(exp)
+      echo "Got ", ct
+      echo "Expected ", rt
+
+  template add1(x: uint8): untyped = x + 1
+  template add1(x: uint16): untyped = x + 1
+  template add1(x: uint32): untyped = x + 1
+
+  template sub1(x: uint8): untyped = x - 1
+  template sub1(x: uint16): untyped = x - 1
+  template sub1(x: uint32): untyped = x - 1
+
+  crossCheck(int8, 0'i16 - 5'i16)
+  crossCheck(int16, 0'i32 - 5'i32)
+  crossCheck(int32, 0'i64 - 5'i64)
+
+  crossCheck(uint8, 0'u8 - 5'u8)
+  crossCheck(uint16, 0'u16 - 5'u16)
+  crossCheck(uint32, 0'u32 - 5'u32)
+  crossCheck(uint64, 0'u64 - 5'u64)
+
+  crossCheck(uint8, uint8.high + 5'u8)
+  crossCheck(uint16, uint16.high + 5'u16)
+  crossCheck(uint32, uint32.high + 5'u32)
+  crossCheck(uint64, 0xFFFFFFFFFFFFFFFF'u64 + 5'u64)
+  crossCheck(uint64, uint64.high + 5'u64)
+
+  doAssert $sub1(0'u8) == "255"
+  doAssert $sub1(0'u16) == "65535"
+  doAssert $sub1(0'u32) == "4294967295"
+
+  doAssert $add1(255'u8) == "0"
+  doAssert $add1(65535'u16) == "0"
+  doAssert $add1(4294967295'u32) == "0"
+
+  crossCheck(int32, high(int32))
+  crossCheck(int32, high(int32).int32)
+  crossCheck(int32, low(int32))
+  crossCheck(int32, low(int32).int32)
+  crossCheck(int64, high(int8).int16.int32.int64)
+  crossCheck(int64, low(int8).int16.int32.int64)
+
+  doAssert not compiles(echo int64(0xFFFFFFFFFFFFFFFF'u64))
+  doAssert not compiles(echo int32(0xFFFFFFFFFFFFFFFF'u64))
+  doAssert not compiles(echo int16(0xFFFFFFFFFFFFFFFF'u64))
+  doAssert not compiles(echo  int8(0xFFFFFFFFFFFFFFFF'u64))
+
+block tnot:
+  # Signed types
+  block:
+    const t0: int8  = not 4
+    const t1: int16 = not 4
+    const t2: int32 = not 4
+    const t3: int64 = not 4
+    const t4: int8  = not -5
+    const t5: int16 = not -5
+    const t6: int32 = not -5
+    const t7: int64 = not -5
+    doAssert t0 == -5
+    doAssert t1 == -5
+    doAssert t2 == -5
+    doAssert t3 == -5
+    doAssert t4 == 4
+    doAssert t5 == 4
+    doAssert t6 == 4
+    doAssert t7 == 4
+
+  # Unsigned types
+  block:
+    const t0: uint8  = not 4'u8
+    const t1: uint16 = not 4'u16
+    const t2: uint32 = not 4'u32
+    const t3: uint64 = not 4'u64
+    const t4: uint8  = not 251'u8
+    const t5: uint16 = not 65531'u16
+    const t6: uint32 = not 4294967291'u32
+    const t7: uint64 = not 18446744073709551611'u64
+    doAssert t0 == 251
+    doAssert t1 == 65531
+    doAssert t2 == 4294967291'u32
+    doAssert t3 == 18446744073709551611'u64
+    doAssert t4 == 4
+    doAssert t5 == 4
+    doAssert t6 == 4
+    doAssert t7 == 4
+
+
+block tshr:
+  proc T() =
+    # let VI = -8
+    let VI64 = -8'i64
+    let VI32 = -8'i32
+    let VI16 = -8'i16
+    let VI8 = -8'i8
+    # doAssert( (VI shr 1) == 9_223_372_036_854_775_804, "Actual: " & $(VI shr 1))
+    doAssert( (VI64 shr 1) == -4, "Actual: " & $(VI64 shr 1))
+    doAssert( (VI32 shr 1) == -4, "Actual: " & $(VI32 shr 1))
+    doAssert( (VI16 shr 1) == -4, "Actual: " & $(VI16 shr 1))
+    doAssert( (VI8 shr 1) == -4, "Actual: " & $(VI8 shr 1))
+
+  T()
+  static:
+    T()
+
+
+
+block tsubrange:
+  # bug #5854
+  type
+    n16 = range[0'i16..high(int16)]
+
+  var level: n16 = 1
+  let maxLevel: n16 = 1
+
+  level = min(level + 2, maxLevel).n16
+  doAssert level == 1
+
+block tissue12177:
+  var a: uint16 = 1
+  var b: uint32 = 2
+
+  echo(b + a)
+  echo(b - a)
+  echo(b * a)
+  echo(b div a)
+
+  echo(a + b)
+  echo(a - b)
+  echo(a * b)
+  echo(a div b)
+
+block tUnsignedOps:
+  proc testUnsignedOps() =
+    let a: int8 = -128
+    let b: int8 = 127
+
+    doAssert b +% 1 == -128
+    doAssert b -% -1 == -128
+    doAssert b *% 2 == -2
+    doAssert a /% 4 == 32
+    doAssert a %% 7 == 2
+    echo "tUnsignedOps OK"
+
+  testUnsignedOps()
+  static:
+    testUnsignedOps()
diff --git a/tests/int/tashr.nim b/tests/int/tashr.nim
new file mode 100644
index 000000000..aeb3b6843
--- /dev/null
+++ b/tests/int/tashr.nim
@@ -0,0 +1,46 @@
+discard """
+  output: ''''''
+  targets: '''c js'''
+"""
+
+# issue #6255, feature request
+# arithmetic right shift
+
+var x1 = -123'i8
+var x2 = -123'i16
+var x3 = -123'i32
+var x4 = -123'i64
+var x5 = -123
+
+block codegen_test:
+  doAssert ashr(x1, 1) == -62
+  doAssert ashr(x2, 1) == -62
+  doAssert ashr(x3, 1) == -62
+  doAssert ashr(x4, 1) == -62
+  doAssert ashr(x5, 1) == -62
+
+block semfold_test:
+  doAssert ashr(-123'i8 , 1) == -62
+  doAssert ashr(-123'i16, 1) == -62
+  doAssert ashr(-123'i32, 1) == -62
+  doAssert ashr(-123'i64, 1) == -62
+  doAssert ashr(-123    , 1) == -62
+
+static: # VM test
+  doAssert ashr(-123'i8 , 1) == -62
+  doAssert ashr(-123'i16, 1) == -62
+  doAssert ashr(-123'i32, 1) == -62
+  doAssert ashr(-123'i64, 1) == -62
+  doAssert ashr(-123    , 1) == -62
+
+  var y1 = -123'i8
+  var y2 = -123'i16
+  var y3 = -123'i32
+  var y4 = -123'i64
+  var y5 = -123
+
+  doAssert ashr(y1, 1) == -62
+  doAssert ashr(y2, 1) == -62
+  doAssert ashr(y3, 1) == -62
+  doAssert ashr(y4, 1) == -62
+  doAssert ashr(y5, 1) == -62
diff --git a/tests/int/tdiv.nim b/tests/int/tdiv.nim
new file mode 100644
index 000000000..5d8eed84d
--- /dev/null
+++ b/tests/int/tdiv.nim
@@ -0,0 +1,19 @@
+discard """
+  targets: "c js"
+"""
+
+
+block divUint64:
+  proc divTest() =
+    let x1 = 12'u16
+    let y = x1 div 5'u16
+    let x2 = 1345567'u32
+    let z = x2 div 5'u32
+    let a = 1345567'u64 div uint64(x1)
+    doAssert y == 2
+    doAssert z == 269113
+    doAssert a == 112130
+
+  static: divTest()
+  divTest()
+
diff --git a/tests/int/tints.nim b/tests/int/tints.nim
new file mode 100644
index 000000000..773e8ccad
--- /dev/null
+++ b/tests/int/tints.nim
@@ -0,0 +1,150 @@
+discard """
+  matrix: "; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+  output: '''
+0 0
+0 0
+Success'''
+"""
+# Test the different integer operations
+
+
+import std/private/jsutils
+
+var testNumber = 0
+
+template test(opr, a, b, c: untyped): untyped =
+  # test the expression at compile and runtime
+  block:
+    const constExpr = opr(a, b)
+    when constExpr != c:
+      {.error: "Test failed " & $constExpr & " " & $c.}
+    inc(testNumber)
+    #Echo("Test: " & $testNumber)
+    var aa = a
+    var bb = b
+    var varExpr = opr(aa, bb)
+    assert(varExpr == c)
+
+test(`+`, 12'i8, -13'i16, -1'i16)
+test(`shl`, 0b11, 0b100, 0b110000)
+whenJsNoBigInt64: discard
+do:
+  test(`shl`, 0b11'i64, 0b100'i64, 0b110000'i64)
+when not defined(js):
+  # mixed type shr needlessly complicates codegen with bigint
+  # and thus is not yet supported in JS for 64 bit ints
+  test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64)
+test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32)
+
+test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16)
+test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16)
+
+whenJsNoBigInt64: discard
+do:
+  test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0xffffffffffffffff'i64)
+test(`shr`, 0xffff'i16, 0x4'i16, 0xffff'i16)
+test(`shr`, 0xff'i8, 0x4'i8, 0xff'i8)
+
+whenJsNoBigInt64: discard
+do:
+  test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64)
+test(`shr`, 0xffffffff'i32, 0x4'i32, 0xffffffff'i32)
+
+whenJsNoBigInt64: discard
+do:
+  test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64)
+test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16)
+test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8)
+
+whenJsNoBigInt64: discard
+do:
+  test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64)
+test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
+
+# bug #916
+proc unc(a: float): float =
+  return a
+
+echo int(unc(0.5)), " ", int(unc(-0.5))
+echo int(0.5), " ", int(-0.5)
+
+block: # Casts to uint
+  template testCast(fromValue: typed, toType: typed, expectedResult: typed) =
+    let src = fromValue
+    let dst = cast[toType](src)
+    if dst != expectedResult:
+      echo "Casting ", astToStr(fromValue), " to ", astToStr(toType), " = ", dst.int, " instead of ", astToStr(expectedResult)
+    doAssert(dst == expectedResult)
+
+  testCast(-1'i16, uint16, 0xffff'u16)
+  testCast(0xffff'u16, int16, -1'i16)
+
+  testCast(0xff'u16, uint8, 0xff'u8)
+  testCast(0xffff'u16, uint8, 0xff'u8)
+
+  testCast(-1'i16, uint32, 0xffffffff'u32)
+  testCast(0xffffffff'u32, int32, -1)
+
+  testCast(0xfffffffe'u32, int32, -2'i32)
+  testCast(0xffffff'u32, int16, -1'i32)
+
+  testCast(-5'i32, uint8, 251'u8)
+
+# issue #7174
+let c = 1'u
+let val = c > 0
+doAssert val
+
+block: # bug #6752
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    let x = 711127'i64
+    doAssert x * 86400'i64 == 61441372800'i64
+
+block: # bug #17604
+  let a = 2147483648'u
+  doAssert (a and a) == a
+  doAssert (a or 0) == a
+
+block: # bitwise not
+  let
+    z8 = 0'u8
+    z16 = 0'u16
+    z32 = 0'u32
+    z64 = 0'u64
+  doAssert (not z8) == uint8.high
+  doAssert (not z16) == uint16.high
+  doAssert (not z32) == uint32.high
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    doAssert (not z64) == uint64.high
+
+block: # shl
+  let i8 = int8.high
+  let i16 = int16.high
+  let i32 = int32.high
+  let i64 = int64.high
+  doAssert i8 shl 1 == -2
+  doAssert i8 shl 2 == -4
+  doAssert i16 shl 1 == -2
+  doAssert i16 shl 2 == -4
+  doAssert i32 shl 1 == -2
+  doAssert i32 shl 2 == -4
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    doAssert i64 shl 1 == -2
+    doAssert i64 shl 2 == -4
+
+  let u8 = uint8.high
+  let u16 = uint16.high
+  let u32 = uint32.high
+  let u64 = uint64.high
+  doAssert u8 shl 1 == u8 - 1
+  doAssert u16 shl 1 == u16 - 1
+  doAssert u32 shl 1 == u32 - 1
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    doAssert u64 shl 1 == u64 - 1
+
+block: # bug #23378
+  var neg = -1  # prevent compile-time evaluation
+  let n = abs BiggestInt neg
+  doAssert n == 1
+
+echo("Success") #OUT Success
diff --git a/tests/int/tunsigned64mod.nim b/tests/int/tunsigned64mod.nim
new file mode 100644
index 000000000..ca3286df3
--- /dev/null
+++ b/tests/int/tunsigned64mod.nim
@@ -0,0 +1,24 @@
+
+# bug #1638
+
+let v1 = 7
+let v2 = 7'u64
+
+let t1 = v1 mod 2 # works
+let t2 = 7'u64 mod 2'u64 # works
+let t3 = v2 mod 2'u64 # Error: invalid type: 'range 0..1(uint64)
+let t4 = (v2 mod 2'u64).uint64 # works
+
+# bug #2550
+
+var x: uint # doesn't work
+doAssert x mod 2 == 0
+
+var y: uint64 # doesn't work
+doAssert y mod 2 == 0
+
+var z: uint32 # works
+doAssert z mod 2 == 0
+
+var a: int # works
+doAssert a mod 2 == 0
diff --git a/tests/int/tunsignedcmp.nim b/tests/int/tunsignedcmp.nim
new file mode 100644
index 000000000..11b67ac5f
--- /dev/null
+++ b/tests/int/tunsignedcmp.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''true
+true
+true
+5
+4
+3
+2
+1
+0
+it should stop now
+18446744073709551615
+4294967295
+'''
+"""
+
+# bug 1420
+var x = 40'u32
+var y = 30'u32
+echo x > y # works
+
+echo((40'i32) > (30'i32))
+echo((40'u32) > (30'u32)) # Error: ordinal type expected
+
+# bug #4220
+
+const count: uint = 5
+var stop_me = false
+
+for i in countdown(count, 0):
+  echo i
+  if stop_me: break
+  if i == 0:
+    echo "it should stop now"
+    stop_me = true
+
+# bug #3985
+const
+  HIGHEST_64BIT_UINT = 0xFFFFFFFFFFFFFFFF'u
+  HIGHEST_32BIT_UINT = 0xFFFFFFFF'u
+
+echo($HIGHEST_64BIT_UINT)
+echo($HIGHEST_32BIT_UINT)
diff --git a/tests/int/tunsignedcomp.nim b/tests/int/tunsignedcomp.nim
new file mode 100644
index 000000000..970c4ae9d
--- /dev/null
+++ b/tests/int/tunsignedcomp.nim
@@ -0,0 +1,136 @@
+discard """
+  output: ''''''
+  disabled: "true"
+"""
+
+# All operations involving uint64 are commented out
+# as they're not yet supported.
+# All other operations are handled by implicit conversions from uints to ints
+# uint64 could be supported but would need special implementation of the operators
+
+# unsigned < signed
+
+doAssert 10'u8 < 20'i8
+doAssert 10'u8 < 20'i16
+doAssert 10'u8 < 20'i32
+doAssert 10'u8 < 20'i64
+
+doAssert 10'u16 < 20'i8
+doAssert 10'u16 < 20'i16
+doAssert 10'u16 < 20'i32
+doAssert 10'u16 < 20'i64
+
+doAssert 10'u32 < 20'i8
+doAssert 10'u32 < 20'i16
+doAssert 10'u32 < 20'i32
+doAssert 10'u32 < 20'i64
+
+# doAssert 10'u64 < 20'i8
+# doAssert 10'u64 < 20'i16
+# doAssert 10'u64 < 20'i32
+# doAssert 10'u64 < 20'i64
+
+# signed < unsigned
+doAssert 10'i8 < 20'u8
+doAssert 10'i8 < 20'u16
+doAssert 10'i8 < 20'u32
+# doAssert 10'i8 < 20'u64
+
+doAssert 10'i16 < 20'u8
+doAssert 10'i16 < 20'u16
+doAssert 10'i16 < 20'u32
+# doAssert 10'i16 < 20'u64
+
+doAssert 10'i32 < 20'u8
+doAssert 10'i32 < 20'u16
+doAssert 10'i32 < 20'u32
+# doAssert 10'i32 < 20'u64
+
+doAssert 10'i64 < 20'u8
+doAssert 10'i64 < 20'u16
+doAssert 10'i64 < 20'u32
+# doAssert 10'i64 < 20'u64
+
+# unsigned <= signed
+doAssert 10'u8 <= 20'i8
+doAssert 10'u8 <= 20'i16
+doAssert 10'u8 <= 20'i32
+doAssert 10'u8 <= 20'i64
+
+doAssert 10'u16 <= 20'i8
+doAssert 10'u16 <= 20'i16
+doAssert 10'u16 <= 20'i32
+doAssert 10'u16 <= 20'i64
+
+doAssert 10'u32 <= 20'i8
+doAssert 10'u32 <= 20'i16
+doAssert 10'u32 <= 20'i32
+doAssert 10'u32 <= 20'i64
+
+# doAssert 10'u64 <= 20'i8
+# doAssert 10'u64 <= 20'i16
+# doAssert 10'u64 <= 20'i32
+# doAssert 10'u64 <= 20'i64
+
+# signed <= unsigned
+doAssert 10'i8 <= 20'u8
+doAssert 10'i8 <= 20'u16
+doAssert 10'i8 <= 20'u32
+# doAssert 10'i8 <= 20'u64
+
+doAssert 10'i16 <= 20'u8
+doAssert 10'i16 <= 20'u16
+doAssert 10'i16 <= 20'u32
+# doAssert 10'i16 <= 20'u64
+
+doAssert 10'i32 <= 20'u8
+doAssert 10'i32 <= 20'u16
+doAssert 10'i32 <= 20'u32
+# doAssert 10'i32 <= 20'u64
+
+doAssert 10'i64 <= 20'u8
+doAssert 10'i64 <= 20'u16
+doAssert 10'i64 <= 20'u32
+# doAssert 10'i64 <= 20'u64
+
+# signed == unsigned
+doAssert 10'i8 == 10'u8
+doAssert 10'i8 == 10'u16
+doAssert 10'i8 == 10'u32
+# doAssert 10'i8 == 10'u64
+
+doAssert 10'i16 == 10'u8
+doAssert 10'i16 == 10'u16
+doAssert 10'i16 == 10'u32
+# doAssert 10'i16 == 10'u64
+
+doAssert 10'i32 == 10'u8
+doAssert 10'i32 == 10'u16
+doAssert 10'i32 == 10'u32
+# doAssert 10'i32 == 10'u64
+
+doAssert 10'i64 == 10'u8
+doAssert 10'i64 == 10'u16
+doAssert 10'i64 == 10'u32
+# doAssert 10'i64 == 10'u64
+
+# unsigned == signed
+doAssert 10'u8 == 10'i8
+doAssert 10'u8 == 10'i16
+doAssert 10'u8 == 10'i32
+# doAssert 10'u8 == 10'i64
+
+doAssert 10'u16 == 10'i8
+doAssert 10'u16 == 10'i16
+doAssert 10'u16 == 10'i32
+# doAssert 10'u16 == 10'i64
+
+doAssert 10'u32 == 10'i8
+doAssert 10'u32 == 10'i16
+doAssert 10'u32 == 10'i32
+# doAssert 10'u32 == 10'i64
+
+# doAssert 10'u64 == 10'i8
+# doAssert 10'u64 == 10'i16
+# doAssert 10'u64 == 10'i32
+# doAssert 10'u64 == 10'i64
diff --git a/tests/int/tunsignedconv.nim b/tests/int/tunsignedconv.nim
new file mode 100644
index 000000000..6c73521d3
--- /dev/null
+++ b/tests/int/tunsignedconv.nim
@@ -0,0 +1,115 @@
+discard """
+  targets: "c cpp js"
+"""
+
+# Tests unsigned literals and implicit conversion between uints and ints
+
+var h8: uint8 = 128
+var h16: uint16 = 32768
+var h32: uint32 = 2147483648'u32
+var h64: uint64 = 9223372036854775808'u64
+var foobar: uint64 = 9223372036854775813'u64 # Issue 728
+
+var v8: uint8 = 10
+var v16: uint16 = 10
+var v32: uint32 = 10
+var v64: uint64 = 10
+
+# u8 + literal produces u8:
+var a8: uint8 = v8 + 10
+var a16: uint16 = v16 + 10
+
+when false:
+  var d8  = v8 + 10'i8
+  var d16 = v8 + 10'i16
+  var d32 = v8 + 10'i32
+
+when false:
+  # these don't work yet because unsigned.nim is stupid. XXX We need to fix this.
+  var f8  = v16 + 10'u8
+  var f16 = v16 + 10'u16
+  var f32 = v16 + 10'u32
+
+  var g8  = v32 + 10'u8
+  var g16 = v32 + 10'u16
+  var g32 = v32 + 10'u32
+
+var ar: array[0..20, int]
+var n8 = ar[v8]
+var n16 = ar[v16]
+var n32 = ar[v32]
+var n64 = ar[v64]
+
+
+block t4176:
+  var yyy: uint8 = 0
+  yyy = yyy - 127
+  doAssert type(yyy) is uint8
+
+# bug #13661
+
+proc fun(): uint = cast[uint](-1)
+const x0 = fun()
+
+doAssert typeof(x0) is uint
+
+discard $x0
+
+# bug #13671
+
+const x1 = cast[uint](-1)
+discard $(x1,)
+
+# bug #13698
+let n2: csize_t = 1
+doAssert $n2.int32 == "1"
+
+# bug #14616
+
+let limit = 1'u64
+
+let rangeVar = 0'u64 ..< limit
+
+when not defined(gcRefc):
+  doAssert repr(rangeVar) == """0 .. 0""", repr(rangeVar)
+
+# bug #15210
+
+let a3 = not 0'u64
+var success = false
+try:
+  discard a3.int64
+except RangeDefect:
+  success = true
+
+doAssert success, "conversion should fail at runtime"
+
+template main() =
+  # xxx move all tests under here so it gets tested in CT and RT
+  block: # bug #17572
+    type T = distinct uint64
+    func f(x: uint64): auto =
+      let a = T(x)
+      (x, a.uint64)
+    const x = 1'u64 shl 63 or 7
+    const b = T(x)
+    doAssert b.uint64 == 9223372036854775815'u64
+    doAssert $b.uint64 == "9223372036854775815"
+    doAssert f(x) == (9223372036854775815'u64, 9223372036854775815'u64)
+
+static: main()
+main()
+
+block:
+  let a = uint64.high
+  let b = uint32.high
+
+  doAssert a.uint64 == a
+  doAssert a.uint32 == uint32.high
+  doAssert a.uint16 == uint16.high
+  doAssert a.uint8 == uint8.high
+
+  doAssert b.uint64 == b
+  doAssert b.uint32 == b
+  doAssert b.uint16 == uint16.high
+  doAssert b.uint8 == uint8.high
diff --git a/tests/int/tunsignedinc.nim b/tests/int/tunsignedinc.nim
new file mode 100644
index 000000000..9392f1b74
--- /dev/null
+++ b/tests/int/tunsignedinc.nim
@@ -0,0 +1,40 @@
+
+block: # bug #2427
+  var x = 0'u8
+  dec x # OverflowDefect
+  x -= 1 # OverflowDefect
+  x = x - 1 # No error
+
+  doAssert(x == 253'u8)
+
+block:
+  var x = 130'u8
+  x += 130'u8
+  doAssert(x == 4'u8)
+
+block:
+  var x = 40000'u16
+  x = x + 40000'u16
+  doAssert(x == 14464'u16)
+
+block:
+  var x = 4000000000'u32
+  x = x + 4000000000'u32
+  doAssert(x == 3705032704'u32)
+
+block:
+  var x = 123'u16
+  x -= 125
+  doAssert(x == 65534'u16)
+
+block t4175:
+  let i = 0u - 1u
+  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/tunsignedmisc.nim b/tests/int/tunsignedmisc.nim
new file mode 100644
index 000000000..b2a3849cf
--- /dev/null
+++ b/tests/int/tunsignedmisc.nim
@@ -0,0 +1,66 @@
+discard """
+  errormsg: "number out of range: '0x123'u8'"
+"""
+
+# Bug #1179
+
+# Unsigneds
+
+# 8 bit
+let ref1 = 128'u8 shr 7
+let hex1 = 0x80'u8 shr 7
+let oct1 = 0o200'u8 shr 7
+let dig1 = 0b10000000'u8 shr 7
+
+doAssert(ref1 == 1)
+doAssert(ref1 == hex1)
+doAssert(ref1 == oct1)
+doAssert(ref1 == dig1)
+
+# 16 bit
+let ref2 = 32768'u16 shr 15
+let hex2 = 0x8000'u16 shr 15
+let oct2 = 0o100000'u16 shr 15
+let dig2 = 0b1000000000000000'u16 shr 15
+
+doAssert(ref2 == 1)
+doAssert(ref2 == hex2)
+doAssert(ref2 == oct2)
+doAssert(ref2 == dig2)
+
+# 32 bit
+let ref3 = 2147483648'u32 shr 31
+let hex3 = 0x80000000'u32 shr 31
+let oct3 = 0o20000000000'u32 shr 31
+let dig3 = 0b10000000000000000000000000000000'u32 shr 31
+
+doAssert(ref3 == 1)
+doAssert(ref3 == hex3)
+doAssert(ref3 == oct3)
+doAssert(ref3 == dig3)
+
+# Below doesn't work for lexer stage errors...
+# doAssert(compiles(0xFF'u8) == true)
+# doAssert(compiles(0xFFF'u16) == true)
+# doAssert(compiles(0x7FFF'i16) == true)
+
+# doAssert(compiles(0x123'u8) == false)
+# doAssert(compiles(0x123'i8) == false)
+# doAssert(compiles(0x123123'u16) == false)
+# doAssert(compiles(0x123123'i16) == false)
+
+# Should compile #
+let boundOkHex1 = 0xFF'u8
+let boundOkHex2 = 0xFFFF'u16
+let boundOkHex3 = 0x7FFF'i16
+
+let boundOkHex4 = 0x80'i8
+let boundOkHex5 = 0xFF'i8
+let boundOkHex6 = 0xFFFF'i16
+let boundOkHex7 = 0x7FFF'i16
+
+# Should _not_ compile #
+let boundBreakingHex1 = 0x123'u8
+let boundBreakingHex2 = 0x123'i8
+let boundBreakingHex3 = 0x123123'u16
+let boundBreakingHex4 = 0x123123'i16
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/isolate/tisolate.nim b/tests/isolate/tisolate.nim
new file mode 100644
index 000000000..a0e71e321
--- /dev/null
+++ b/tests/isolate/tisolate.nim
@@ -0,0 +1,41 @@
+discard """
+  errormsg: "expression cannot be isolated: select(a, b)"
+  line: 39
+"""
+
+import std / isolation
+
+import json, streams
+
+proc myParseJson(s: Stream; filename: string): JsonNode =
+  {.cast(noSideEffect).}:
+    result = parseJson(s, filename)
+
+
+proc f(): seq[int] =
+  @[1, 2, 3]
+
+type
+  Node = ref object
+    x: string
+
+proc g(): Node = nil
+
+proc select(a, b: Node): Node =
+  a
+
+proc main =
+  discard isolate f()
+
+
+  discard isolate g()
+
+  discard isolate select(Node(x: "a"), nil)
+  discard isolate select(Node(x: "a"), Node(x: "b"))
+
+  discard isolate myParseJson(newFileStream("my.json"), "my.json")
+
+  var a, b: Node
+  discard isolate select(a, b)
+
+main()
diff --git a/tests/isolate/tisolate2.nim b/tests/isolate/tisolate2.nim
new file mode 100644
index 000000000..9bf92d82e
--- /dev/null
+++ b/tests/isolate/tisolate2.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "expression cannot be isolated: a_to_b(a)"
+  line: 22
+"""
+
+# bug #19013
+import std/isolation
+
+type Z = ref object
+  i: int
+
+type A = object
+  z: Z
+
+type B = object
+  z: Z
+
+func a_to_b(a: A): B =
+  result = B(z: a.z)
+
+let a = A(z: Z(i: 3))
+let b = isolate(a_to_b(a))
diff --git a/tests/isolate/tisolated_lock.nim b/tests/isolate/tisolated_lock.nim
new file mode 100644
index 000000000..312abf0f6
--- /dev/null
+++ b/tests/isolate/tisolated_lock.nim
@@ -0,0 +1,67 @@
+discard """
+  cmd: "nim $target --threads:on $options $file"
+  action: "compile"
+"""
+
+import std / [os, locks, atomics, isolation]
+
+type
+  MyList {.acyclic.} = ref object
+    data: string
+    next: Isolated[MyList]
+
+template withMyLock*(a: Lock, body: untyped) =
+  acquire(a)
+  {.gcsafe.}:
+    try:
+      body
+    finally:
+      release(a)
+
+var head: Isolated[MyList]
+var headL: Lock
+
+var shouldStop: Atomic[bool]
+
+initLock headL
+
+proc send(x: sink string) =
+  withMyLock headL:
+    head = isolate MyList(data: x, next: move head)
+
+proc worker() {.thread.} =
+  var workItem = MyList(nil)
+  var echoed = 0
+  while true:
+    withMyLock headL:
+      var h = extract head
+      if h != nil:
+        workItem = h
+        # workitem is now isolated:
+        head = move h.next
+      else:
+        workItem = nil
+    # workItem is isolated, so we can access it outside
+    # the lock:
+    if workItem.isNil:
+      if shouldStop.load:
+        break
+      else:
+        # give producer time to breath:
+        os.sleep 30
+    else:
+      if echoed < 100:
+        echo workItem.data
+      inc echoed
+
+var thr: Thread[void]
+createThread(thr, worker)
+
+send "abc"
+send "def"
+for i in 0 ..< 10_000:
+  send "xzy"
+  send "zzz"
+shouldStop.store true
+
+joinThread(thr)
diff --git a/tests/iter/t1550.nim b/tests/iter/t1550.nim
new file mode 100644
index 000000000..c971943ee
--- /dev/null
+++ b/tests/iter/t1550.nim
@@ -0,0 +1,24 @@
+discard """
+  targets: "c js"
+"""
+
+type
+  A[T] = iterator(x: T): T {.gcsafe, closure.}
+
+iterator aimp[T](x: T): T {.gcsafe, closure.} =
+  var total = 0
+  while (total < 100):
+    yield total
+    total += x
+
+iterator bimp(y: A[int], z:int): int {.gcsafe, closure.} =
+  for i in y(z):
+    yield i
+
+for x in aimp[int](3):
+  discard x
+
+var y = aimp[int]
+var z = bimp
+for x in z(y, 1):
+  discard x
\ No newline at end of file
diff --git a/tests/iter/t16076.nim b/tests/iter/t16076.nim
new file mode 100644
index 000000000..2eb409068
--- /dev/null
+++ b/tests/iter/t16076.nim
@@ -0,0 +1,45 @@
+discard """
+  targets: "c js"
+"""
+
+proc main() =
+  block: # bug #17485
+    type
+      O = ref object
+        i: int
+
+    iterator t(o: O): int =
+      if o != nil:
+        yield o.i
+      yield 0
+
+    proc m =
+      var data = ""
+      for i in t(nil):
+        data.addInt i
+
+      doAssert data == "0"
+
+    m()
+
+
+  block: # bug #16076
+    type
+      R = ref object
+        z: int
+
+    var data = ""
+
+    iterator foo(x: int; y: R = nil): int {.inline.} =
+      if y == nil:
+        yield x
+      else:
+        yield y.z
+
+    for b in foo(10):
+      data.addInt b
+
+    doAssert data == "10"
+
+static: main()
+main()
diff --git a/tests/iter/t20891.nim b/tests/iter/t20891.nim
new file mode 100644
index 000000000..34deec41b
--- /dev/null
+++ b/tests/iter/t20891.nim
@@ -0,0 +1,28 @@
+import macros, tables
+
+var mapping {.compileTime.}: Table[string, NimNode]
+
+macro register(a: static[string], b: typed): untyped =
+  mapping[a] = b
+
+macro getPtr(a: static[string]): untyped =
+  result = mapping[a]
+
+proc foo() =
+  iterator it() {.closure.} =
+    discard
+  proc getIterPtr(): pointer {.nimcall.} =
+    rawProc(it)
+  register("foo", getIterPtr())
+  discard getIterPtr() # Comment either this to make it work
+foo() # or this
+
+proc bar() =
+  iterator it() {.closure.} =
+    discard getPtr("foo") # Or this
+    discard
+  proc getIterPtr(): pointer {.nimcall.} =
+    rawProc(it)
+  register("bar", getIterPtr())
+  discard getIterPtr()
+bar()
diff --git a/tests/iter/t21306.nim b/tests/iter/t21306.nim
new file mode 100644
index 000000000..4d0396294
--- /dev/null
+++ b/tests/iter/t21306.nim
@@ -0,0 +1,118 @@
+discard """
+  targets: "c js"
+"""
+
+# bug #21306
+type
+  FutureState {.pure.} = enum
+    Pending, Finished, Cancelled, Failed
+
+  FutureBase = ref object of RootObj
+    state: FutureState
+    error: ref CatchableError
+    id: uint
+
+  Future[T] = ref object of FutureBase
+    closure: iterator(f: Future[T]): FutureBase {.raises: [Defect, CatchableError, Exception], gcsafe.}
+    value: T
+
+template setupFutureBase() =
+  new(result)
+  result.state = FutureState.Pending
+
+proc newFutureImpl[T](): Future[T] =
+  setupFutureBase()
+
+template newFuture[T](fromProc: static[string] = ""): Future[T] =
+  newFutureImpl[T]()
+
+proc internalRead[T](fut: Future[T]): T =
+  when T isnot void:
+    return fut.value
+
+template await[T](f: Future[T]): untyped =
+  when declared(chronosInternalRetFuture):
+    when not declaredInScope(chronosInternalTmpFuture):
+      var chronosInternalTmpFuture {.inject.}: FutureBase = f
+    else:
+      chronosInternalTmpFuture = f
+
+    yield chronosInternalTmpFuture
+
+    when T isnot void:
+      cast[type(f)](chronosInternalTmpFuture).internalRead()
+
+type
+  VerifierError {.pure.} = enum
+    Invalid
+    MissingParent
+    UnviableFork
+    Duplicate
+  ProcessingCallback = proc() {.gcsafe, raises: [Defect].}
+  BlockVerifier =
+    proc(signedBlock: int):
+      Future[VerifierError] {.gcsafe, raises: [Defect].}
+
+  SyncQueueKind {.pure.} = enum
+    Forward, Backward
+
+  SyncRequest[T] = object
+    kind: SyncQueueKind
+    index: uint64
+    slot: uint64
+    count: uint64
+    item: T
+
+  SyncResult[T] = object
+    request: SyncRequest[T]
+    data: seq[ref int]
+
+  SyncQueue[T] = ref object
+    kind: SyncQueueKind
+    readyQueue: seq[SyncResult[T]]
+    blockVerifier: BlockVerifier
+
+iterator blocks[T](sq: SyncQueue[T],
+                    sr: SyncResult[T]): ref int =
+  case sq.kind
+  of SyncQueueKind.Forward:
+    for i in countup(0, len(sr.data) - 1):
+      yield sr.data[i]
+  of SyncQueueKind.Backward:
+    for i in countdown(len(sr.data) - 1, 0):
+      yield sr.data[i]
+
+proc push[T](sq: SyncQueue[T]; sr: SyncRequest[T]; data: seq[ref int];
+             processingCb: ProcessingCallback = nil): Future[void] {.
+    stackTrace: off, gcsafe.} =
+  iterator push_436208182(chronosInternalRetFuture: Future[void]): FutureBase {.
+      closure, gcsafe, raises: [Defect, CatchableError, Exception].} =
+    block:
+      template result(): auto {.used.} =
+        {.fatal: "You should not reference the `result` variable inside" &
+            " a void async proc".}
+
+      let item = default(SyncResult[T])
+      for blk in sq.blocks(item):
+        let res = await sq.blockVerifier(blk[])
+
+  var resultFuture = newFuture[void]("push")
+  resultFuture.closure = push_436208182
+  return resultFuture
+
+type
+  SomeTPeer = ref object
+    score: int
+
+proc getSlice(): seq[ref int] =
+  discard
+
+template smokeTest(kkind: SyncQueueKind, start, finish: uint64,
+                   chunkSize: uint64) =
+  var queue: SyncQueue[SomeTPeer]
+  var request: SyncRequest[SomeTPeer]
+  discard queue.push(request, getSlice())
+
+for k in {SyncQueueKind.Forward}:
+  for item in [(uint64(1181), uint64(1399), 41'u64)]:
+    smokeTest(k, item[0], item[1], item[2])
\ No newline at end of file
diff --git a/tests/iter/t21737.nim b/tests/iter/t21737.nim
new file mode 100644
index 000000000..da06faea7
--- /dev/null
+++ b/tests/iter/t21737.nim
@@ -0,0 +1,22 @@
+discard """
+  action: compile
+"""
+
+template mytoSeq*(iter: untyped): untyped =
+  var result: seq[typeof(iter)]# = @[]
+  for x in iter:
+    result.add(x)
+  result
+
+iterator test(dir:int): int =
+  yield 1234
+
+iterator walkGlobKinds (): int =
+  let dir2 = 123
+  let it = mytoSeq(test(dir2))  
+
+proc main()=
+    let it = iterator(): int=
+      for path in walkGlobKinds():
+          yield path
+main()
diff --git a/tests/iter/t22148.nim b/tests/iter/t22148.nim
new file mode 100644
index 000000000..9954eed87
--- /dev/null
+++ b/tests/iter/t22148.nim
@@ -0,0 +1,15 @@
+discard """

+  action: compile

+"""

+

+import std/memfiles

+

+# bug #22148

+proc make*(input: string) =

+  var inp = memfiles.open(input)

+  for line in memSlices(inp):

+    let lineF = MemFile(mem: line.data, size: line.size)

+    for word in memSlices(lineF, ','):

+      discard

+

+make("") # Must call to trigger

diff --git a/tests/iter/t22548.nim b/tests/iter/t22548.nim
new file mode 100644
index 000000000..b9abb75d0
--- /dev/null
+++ b/tests/iter/t22548.nim
@@ -0,0 +1,21 @@
+discard """
+  action: compile
+"""
+
+type Xxx[T] = object
+
+iterator x(v: string): char =
+  var v2: Xxx[int]
+
+  var y: v2.T
+
+  echo y
+
+proc bbb(vv: string): proc () =
+  proc xxx() =
+    for c in x(vv):
+      echo c
+
+  return xxx
+
+bbb("test")()
diff --git a/tests/iter/t22619.nim b/tests/iter/t22619.nim
new file mode 100644
index 000000000..6a98391f3
--- /dev/null
+++ b/tests/iter/t22619.nim
@@ -0,0 +1,83 @@
+# bug #22619
+
+when false: # todo fixme
+  block:
+    type
+      Resource = object
+        value: int
+  
+      Object = object
+        r {.cursor.}: Resource
+        s {.cursor.}: seq[Resource]
+  
+    var numDestroy = 0
+  
+    proc `=copy`(x: var Resource, y: Resource) {.error.} # disallow full copies
+    proc `=destroy`(x: Resource) =
+      inc numDestroy
+  
+    proc test() =
+      # perform the test in procedure so that globals aren't used (their different
+      # semantics with regards to destruction would interfere)
+      var
+        r = Resource(value: 1) # initialize a resource
+        s = @[Resource(value: 2)]
+  
+      # make sure no copy is required in the initializer expression:
+      var o = Object(r: r, s: s)
+  
+      # copying the object doesn't perform a full copy of the cursor fields:
+      var o2 = o
+      discard addr(o2) # prevent `o2` from being turned into a cursor
+  
+      # check that the fields were shallow-copied:
+      doAssert o2.r.value == 1
+      doAssert o2.s[0].value == 2
+  
+      # make sure no copy is required with normal field assignments:
+      o.r = r
+      o.s = s
+  
+  
+      # when `o` and `o2` are destroyed, their destructor must not be called on
+      # their fields
+  
+    test()
+  
+    # one call for the `r` local and one for the object in `s`
+    doAssert numDestroy == 2
+
+block:
+  type Value = distinct int
+
+  var numDestroy = 0
+
+  when defined(gcRefc):
+    proc `=destroy`(x: var Value) =
+      inc numDestroy
+  else:
+    proc `=destroy`(x: Value) =
+      inc numDestroy
+
+  iterator iter(s: seq[Value]): int {.closure.} =
+    # because it is used across yields, `s2` is lifted into the iterator's
+    # environment. Since non-ref cursors in object didn't have their hooks
+    # disabled inside the environments lifted hooks, this led to double
+    # frees
+    var s2 {.cursor.} = s
+    var i = 0
+    let L = s2.len
+    while i < L:
+      yield s2[i].int
+      inc i
+
+  proc test() =
+    var s = @[Value(1), Value(2)]
+    let cl = iter
+    # make sure resuming the iterator works:
+    doAssert cl(s) == 1
+    doAssert cl(s) == 2
+    doAssert cl(s) == 0
+
+  test()
+  doAssert numDestroy == 2
diff --git a/tests/iter/t2771.nim b/tests/iter/t2771.nim
new file mode 100644
index 000000000..71a8a9dcd
--- /dev/null
+++ b/tests/iter/t2771.nim
@@ -0,0 +1,25 @@
+discard """
+  targets: "c js"
+"""
+
+template t1(i: int): int=
+  i+1
+template t2(i: int): int=
+  i+1
+
+doAssert t1(10).t2() == 12
+
+
+template it1(i: int): iterator(): int =
+  iterator result(): int {.closure, gensym.} =
+    yield i+1
+  result
+
+template it2(iter: iterator(): int): iterator(): int =
+  iterator result(): int {.closure, gensym.} =
+    yield iter()+1
+  result
+
+let x2 = it1(10).it2()
+
+doAssert x2() == 12
diff --git a/tests/iter/tanoniter1.nim b/tests/iter/tanoniter1.nim
new file mode 100644
index 000000000..fee16497f
--- /dev/null
+++ b/tests/iter/tanoniter1.nim
@@ -0,0 +1,33 @@
+discard """
+  targets: "c js"
+  output: '''1
+2
+3
+4
+1
+2'''
+"""
+
+proc factory(a, b: int): iterator (): int =
+  iterator foo(): int {.closure.} =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+  return foo
+
+proc factory2(a, b: int): iterator (): int =
+  return iterator (): int =
+    var x = a
+    while x <= b:
+      yield x
+      inc x
+
+let foo = factory(1, 4)
+
+for f in foo():
+  echo f
+
+let foo2 = factory2(1,2)
+
+for f in foo2(): echo f
diff --git a/tests/iter/tarrayiter.nim b/tests/iter/tarrayiter.nim
new file mode 100644
index 000000000..eb7ba591a
--- /dev/null
+++ b/tests/iter/tarrayiter.nim
@@ -0,0 +1,14 @@
+block:
+  iterator `[]`(a: int, r: int): int = 
+    for q in 0 .. r:
+      yield a
+    
+  for val in 10[2]: discard
+  
+  type Custom = distinct string
+
+  iterator `[]`(a: Custom, r: int): char = 
+    for q in 0 .. r:
+      yield a.string[q]
+      
+  for val in Custom("test")[2]: discard
\ No newline at end of file
diff --git a/tests/iter/tchainediterators.nim b/tests/iter/tchainediterators.nim
new file mode 100644
index 000000000..796672783
--- /dev/null
+++ b/tests/iter/tchainediterators.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''16
+32
+48
+64
+128
+192
+'''
+  disabled: "true"
+"""
+
+# This all relies on non-documented and questionable features.
+
+iterator gaz(it: iterator{.inline.}): type(it) =
+  for x in it:
+    yield x*2
+
+iterator baz(it: iterator{.inline.}): auto =
+  for x in gaz(it):
+    yield x*2
+
+type T1 = auto
+
+iterator bar(it: iterator: T1{.inline.}): T1 =
+  for x in baz(it):
+    yield x*2
+
+iterator foo[T](x: iterator: T{.inline.}): T =
+  for e in bar(x):
+    yield e*2
+
+var s = @[1, 2, 3]
+
+# pass an iterator several levels deep:
+for x in s.items.foo:
+  echo x
+
+# use some complex iterator as an input for another one:
+for x in s.items.baz.foo:
+  echo x
+
diff --git a/tests/iter/tclosureiters.nim b/tests/iter/tclosureiters.nim
new file mode 100644
index 000000000..4a2639852
--- /dev/null
+++ b/tests/iter/tclosureiters.nim
@@ -0,0 +1,176 @@
+discard """
+  targets: "c js"
+  output: '''0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+5 5
+7 7
+9 9
+0
+0
+0
+0
+1
+2
+70
+0
+(1, 1)
+(1, 2)
+(1, 3)
+(2, 1)
+(2, 2)
+(2, 3)
+(3, 1)
+(3, 2)
+(3, 3)
+'''
+"""
+
+when true:
+  proc main() =
+    let
+      lo=0
+      hi=10
+
+    iterator itA(): int =
+      for x in lo..hi:
+        yield x
+
+    for x in itA():
+      echo x
+
+    var y: int
+
+    iterator itB(): int =
+      while y <= hi:
+        yield y
+        inc y
+
+    y = 5
+    for x in itB():
+      echo x, " ", y
+      inc y
+
+  main()
+
+
+iterator infinite(): int {.closure.} =
+  var i = 0
+  while true:
+    yield i
+    inc i
+
+iterator take[T](it: iterator (): T, numToTake: int): T {.closure.} =
+  var i = 0
+  for x in it():
+    if i >= numToTake:
+      break
+    yield x
+    inc i
+
+# gives wrong reasult (3 times 0)
+for x in infinite.take(3):
+  echo x
+
+# does what we want
+let inf = infinite
+for x in inf.take(3):
+  echo x
+
+# bug #3583
+proc foo(f: (iterator(): int)) =
+  for i in f(): echo i
+
+let fIt = iterator(): int = yield 70
+foo fIt
+
+# bug #5321
+
+proc lineIter*(filename: string): iterator(): string =
+  result = iterator(): string {.closure.} =
+    for line in lines(filename):
+      yield line
+
+proc unused =
+  var count = 0
+  let iter = lineIter("temp10.nim")
+  for line in iter():
+    count += 1
+
+iterator lineIter2*(filename: string): string {.closure.} =
+  var f = open(filename, bufSize=8000)
+  defer: close(f)   # <-- commenting defer "solves" the problem
+  var res = newStringOfCap(80)
+  while f.readLine(res): yield res
+
+proc unusedB =
+  var count = 0
+  for line in lineIter2("temp10.nim"):
+    count += 1
+
+# bug #5519
+import os, algorithm
+
+iterator filesIt(path: string): auto {.closure.} =
+  var files = newSeq[string]()
+  var dirs = newSeq[string]()
+  for k, p in os.walkDir(path):
+    let (_, n, e) = p.splitFile
+    if e != "":
+      continue
+    case k
+    of pcFile, pcLinkToFile:
+      files.add(n)
+    else:
+      dirs.add(n)
+  files.sort(system.cmp)
+  dirs.sort(system.cmp)
+  for f in files:
+    yield f
+
+  for d in dirs:
+    files = newSeq[string]()
+    for k, p in os.walkDir(path / d):
+      let (_, n, e) = p.splitFile
+      if e != "":
+        continue
+      case k
+      of pcFile, pcLinkToFile:
+        files.add(n)
+      else:
+        discard
+    files.sort(system.cmp)
+    let prefix = path.splitPath[1]
+    for f in files:
+      yield prefix / f
+
+# bug #13815
+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.} =
+  for i in 1..3:
+    for j in 1..3:
+      yield (i, j)
+
+for pair in pairs():
+  echo pair
diff --git a/tests/iter/tcountup.nim b/tests/iter/tcountup.nim
new file mode 100644
index 000000000..5f75e653c
--- /dev/null
+++ b/tests/iter/tcountup.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+0123456789
+0.0
+'''
+"""
+
+# Test new countup
+
+for i in 0 ..< 10'i64:
+  stdout.write(i)
+
+echo()
+
+# 11099
+
+var
+  x: uint32
+  y: float
+
+for i in 0 ..< x:
+  if i == 1: echo i
+  y += 1
+
+echo y
diff --git a/tests/iter/tgeniteratorinblock.nim b/tests/iter/tgeniteratorinblock.nim
new file mode 100644
index 000000000..2ab903996
--- /dev/null
+++ b/tests/iter/tgeniteratorinblock.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''30
+60
+90
+150
+180
+210
+240
+60
+180
+240
+[60, 180, 240]
+[60, 180]'''
+"""
+import std/enumerate
+
+template map[T; Y](i: iterable[T], fn: proc(x: T): Y): untyped =
+  iterator internal(): Y  {.gensym.} =
+    for it in i:
+      yield fn(it)
+  internal()
+
+template filter[T](i: iterable[T], fn: proc(x: T): bool): untyped =
+  iterator internal(): T {.gensym.} =
+    for it in i:
+      if fn(it):
+        yield it
+  internal()
+
+template group[T](i: iterable[T], amount: static int): untyped =
+  iterator internal(): array[amount, T] {.gensym.} =
+    var val: array[amount, T]
+    for ind, it in enumerate i:
+      val[ind mod amount] = it
+      if ind mod amount == amount - 1:
+        yield val
+  internal()
+
+var a = [10, 20, 30, 50, 60, 70, 80]
+
+proc mapFn(x: int): int = x * 3
+proc filterFn(x: int): bool = x mod 20 == 0
+
+for x in a.items.map(mapFn):
+  echo x
+
+for y in a.items.map(mapFn).filter(filterFn):
+  echo y
+
+for y in a.items.map(mapFn).filter(filterFn).group(3):
+  echo y
+
+for y in a.items.map(mapFn).filter(filterFn).group(2):
+  echo y
diff --git a/tests/iter/timplicit_auto.nim b/tests/iter/timplicit_auto.nim
new file mode 100644
index 000000000..1b9f06843
--- /dev/null
+++ b/tests/iter/timplicit_auto.nim
@@ -0,0 +1,18 @@
+# bug #1838
+
+type State = enum Empty, Tree, Fire
+
+const
+  disp: array[State, string] = ["  ", "\e[32m/\\\e[m", "\e[07;31m/\\\e[m"]
+
+proc univ(x, y: int): State = Tree
+
+var w, h = 30
+
+iterator fields(a = (0,0), b = (h-1,w-1)): auto =
+  for y in max(a[0], 0) .. min(b[0], h-1):
+    for x in max(a[1], 0) .. min(b[1], w-1):
+      yield (y,x)
+
+for y,x in fields():
+  doAssert disp[univ(x, y)] == disp[Tree]
diff --git a/tests/iter/titer.nim b/tests/iter/titer.nim
new file mode 100644
index 000000000..b03d43f36
--- /dev/null
+++ b/tests/iter/titer.nim
@@ -0,0 +1,147 @@
+discard """
+output: '''
+testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest2!test3?hi
+what's
+your
+name
+hi
+what's
+your
+name
+'''
+"""
+
+# Test the new iterators
+
+iterator xrange(fromm, to: int, step = 1): int =
+  var a = fromm
+  while a <= to:
+    yield a
+    inc(a, step)
+
+iterator interval[T](a, b: T): T =
+  var x = a
+  while x <= b:
+    yield x
+    inc(x)
+
+#
+#iterator lines(filename: string): (line: string) =
+#  var
+#    f: tTextfile
+#    shouldClose = open(f, filename)
+#  if shouldClose:
+#    setSpace(line, 256)
+#    while readTextLine(f, line):
+#      yield line
+#  finally:
+#    if shouldClose: close(f)
+#
+
+for i in xrange(0, 5):
+  for k in xrange(1, 7):
+    write(stdout, "test")
+
+for j in interval(45, 45):
+  write(stdout, "test2!")
+  write(stdout, "test3?")
+
+for x in items(["hi", "what's", "your", "name"]):
+  echo(x)
+
+const
+  stringArray = ["hi", "what's", "your", "name"]
+
+for i in 0..len(stringArray)-1:
+  echo(stringArray[i])
+
+# bug #15360
+
+type Rule[T] = (int, T)
+
+var t: seq[Rule[int]]
+for (c, t) in t:
+  discard
+
+
+
+import std/sugar
+
+# bug #14165
+iterator log_nodups_hamming(): int {.inline.} =
+  let lb3 = 1
+  let lb4 = 123
+  proc mul3(): int = lb3 + lb4
+  yield mul3()
+
+for h in log_nodups_hamming():
+  break
+for h in log_nodups_hamming():
+  break
+for h in log_nodups_hamming():
+  break
+
+# bug #18536
+iterator envPairs*(): int =
+  var foo: seq[int]
+  proc fun() =
+    foo = @[]
+  fun()
+  yield 3
+
+proc main() =
+  for a in envPairs():
+    discard
+  for a in envPairs():
+    discard
+static: main()
+main()
+
+# bug #6269
+iterator makeFn(outer_val: int): proc(a: int): int =
+  for i in 0..1:
+    yield proc(a:int): int =
+      return a + i.int
+
+let v1 = 42
+
+let res = collect:
+  for fn1 in makeFn(v1):
+    let v2 = fn1(v1)
+    for fn2 in makeFn(v2):
+      fn2(v2)
+
+doAssert res == @[42, 43, 43, 44]
+
+block: # bug #21110
+  iterator p(): int =
+    when nimvm:
+      yield 0
+    else:
+      yield 0
+
+  template foo =
+    for k in p():
+      let m = ""
+      proc e() = discard m & ""
+      e()
+  static: foo()
+  foo()
+
+
+# bug #15924
+iterator walk(): (int, int) {.closure.} =
+  yield (10,11)
+
+for (i,j) in walk():
+  doAssert i == 10
+
+proc main123() =
+  let x = false
+  iterator it(): (bool, bool) {.closure.} = # normally {.closure.} here makes #21476 work
+    discard x
+
+  for (_, _) in it():
+    discard
+
+main123()
diff --git a/tests/iter/titer10.nim b/tests/iter/titer10.nim
new file mode 100644
index 000000000..ae36aa519
--- /dev/null
+++ b/tests/iter/titer10.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''3
+2
+5
+1
+@[@[0, 0], @[0, 1]]
+@[@[0, 0], @[0, 1]]
+@[@[2, 2], @[2, 3]]
+@[@[2, 2], @[2, 3]]'''
+"""
+
+when true:
+  # bug #2604
+
+  import algorithm
+
+  iterator byDistance*[int]( ints: openArray[int], base: int ): int =
+      var sortable = @ints
+
+      sortable.sort do (a, b: int) -> int:
+          result = cmp( abs(base - a), abs(base - b) )
+
+      for val in sortable:
+          yield val
+
+  when true:
+    proc main =
+      for val in byDistance([2, 3, 5, 1], 3):
+          echo val
+    main()
+
+when true:
+  # bug #1527
+
+  import sequtils
+
+  let thread = @[@[0, 0],
+                 @[0, 1],
+                 @[2, 2],
+                 @[2, 3]]
+
+  iterator threadUniqs(seq1: seq[seq[int]]): seq[seq[int]] =
+    for i in 0 ..< seq1.len:
+      block:
+        let i = i
+        yield seq1.filter do (x: seq[int]) -> bool: x[0] == seq1[i][0]
+  proc main2 =
+    for uniqs in thread.threadUniqs:
+      echo uniqs
+
+  main2()
diff --git a/tests/iter/titer11.nim b/tests/iter/titer11.nim
new file mode 100644
index 000000000..153b3c29a
--- /dev/null
+++ b/tests/iter/titer11.nim
@@ -0,0 +1,40 @@
+discard """
+targets: "c js"
+output: '''
+[
+1
+2
+3
+]
+'''
+"""
+
+proc represent(i: int): iterator(): string =
+  result = iterator(): string =
+    yield $i
+
+proc represent(s: seq[int]): iterator(): string =
+  result = iterator(): string =
+    yield "["
+    for i in s:
+      var events = represent(i)
+      for event in events():
+        yield event
+    yield "]"
+
+let s = @[1, 2, 3]
+var output = represent(s)
+
+for item in output():
+  echo item
+
+
+#------------------------------------------------------------------------------
+# Issue #12747
+
+type
+  ABC = ref object
+      arr: array[0x40000, pointer]
+let a = ABC()
+for a in a.arr:
+    assert a == nil
\ No newline at end of file
diff --git a/tests/iter/titer12.nim b/tests/iter/titer12.nim
new file mode 100644
index 000000000..f264a0e82
--- /dev/null
+++ b/tests/iter/titer12.nim
@@ -0,0 +1,83 @@
+discard """
+targets: "c js"
+output: '''
+Selecting 2
+1.0
+Selecting 4
+2.0
+'''
+"""
+
+
+# bug #5522
+import macros, sugar, sequtils
+
+proc tryS(f: () -> void): void =
+  (try: f() except: discard)
+
+template trySTImpl(body: untyped): untyped =
+  tryS do() -> auto:
+    `body`
+
+macro tryST*(body: untyped): untyped =
+  var b = if body.kind == nnkDo: body[^1] else: body
+  result = quote do:
+    trySTImpl((block:
+      `b`
+    ))
+
+iterator testIt(): int {.closure.} =
+  for x in 0..10:
+    yield x
+
+var xs = newSeq[int]()
+proc test = tryST do:
+  for x in testIt():
+    xs.add(x)
+
+test()
+
+doAssert xs == toSeq(0..10)
+
+
+
+# bug #5690
+proc filter[T](it: (iterator : T), f: proc(x: T): bool): (iterator : T) =
+  return iterator (): T {.closure.} =
+    for x in it():
+      if f(x): 
+        yield x
+
+proc len[T](it : iterator : T) : Natural =
+  for i in it():
+    result += 1
+
+proc simpleSeqIterator(s :seq[int]) : iterator : int =
+  iterator it: int {.closure.} =
+    for x in s:
+      yield x
+  result = it
+
+let a = newSeq[int](99)
+
+doAssert len(simpleSeqIterator(a).filter(proc(x : int) : bool = true)) == 99
+
+
+
+# bug #5340
+proc where[A](input: seq[A], filter: (A) -> bool): iterator (): A =
+  result = iterator (): A {.closure.} = 
+    for item in input:
+      if filter(item):
+        yield item
+
+proc select[A,B](input: iterator(): A {.closure.}, selector: (A) -> B): iterator (): B {.closure.} = 
+  result = iterator (): B =
+    for item in input():
+      echo "Selecting " & $item
+      yield selector(item)
+
+let query = @[1,2,3,4].where(x=>x mod 2==0).select((x)=>x/2)
+
+for i in query():
+  echo $i
diff --git a/tests/iter/titer13.nim b/tests/iter/titer13.nim
new file mode 100644
index 000000000..086c40ca4
--- /dev/null
+++ b/tests/iter/titer13.nim
@@ -0,0 +1,83 @@
+discard """
+  output: '''b yields
+c yields
+a returns
+b yields
+b returns
+c yields
+
+
+1
+2
+3
+4
+'''
+"""
+
+block:
+  template tloop(iter: untyped) =
+    for i in iter():
+      echo i
+
+  template twhile(iter: untyped) =
+    let it = iter
+    while not finished(it):
+      echo it()
+
+  iterator a(): auto {.closure.} =
+    if true: return "a returns"
+    yield "a yields"
+
+  iterator b(): auto {.closure.} =
+    yield "b yields"
+    if true: return "b returns"
+
+  iterator c(): auto {.closure.} =
+    yield "c yields"
+    if true: return
+
+  iterator d(): auto {.closure.} =
+    if true: return
+    yield "d yields"
+
+  tloop(a)
+  tloop(b)
+  tloop(c)
+  tloop(d)
+  twhile(a)
+  twhile(b)
+  twhile(c)
+  twhile(d)
+
+block:
+  iterator a: auto =
+    yield 1
+  for x in a():
+    echo x
+
+  let b = iterator: int =
+    yield 2
+  for x in b():
+    echo x
+
+  let c = iterator: auto =
+    yield 3
+  for x in c():
+    echo x
+
+block:
+  iterator myIter2(): auto {.closure.} =
+    yield 4
+  for a in myIter2():
+    echo a
+
+block t5859:
+  proc flatIterator[T](s: openArray[T]): auto {.noSideEffect.}=
+    result = iterator(): auto =
+      when (T is not seq|array):
+        for item in s:
+          yield item
+      else:
+        yield 123456
+  # issue #5859
+  let it = flatIterator(@[@[1,2], @[3,4]])
diff --git a/tests/iter/titer14.nim b/tests/iter/titer14.nim
new file mode 100644
index 000000000..7e483bbae
--- /dev/null
+++ b/tests/iter/titer14.nim
@@ -0,0 +1,7 @@
+proc f() =
+  var s: seq[int]
+  iterator a(): int =
+    for x in s: yield x
+
+  iterator b(): int =
+    for x in a(): yield x
diff --git a/tests/iter/titer2.nim b/tests/iter/titer2.nim
new file mode 100644
index 000000000..975cc786c
--- /dev/null
+++ b/tests/iter/titer2.nim
@@ -0,0 +1,66 @@
+discard """
+  output: '''true
+3
+4
+5
+0
+1
+2
+3
+4'''
+  cmd: "nim $target --gc:none --hints:on --warnings:off $options $file"
+"""
+
+import hashes
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+  TTable*[A, B] {.final.} = object
+    data: TKeyValuePairSeq[A, B]
+    counter: int
+
+iterator mycountup(a, b: int): int =
+  var res = a
+  while res <= b:
+    yield res
+    inc(res)
+
+when true:
+  iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
+    ## iterates over any (key, value) pair in the table `t`.
+    for h in mycountup(0, high(t.data)):
+      var k = t.data[h].key
+      if t.data[h].slot == seFilled: yield (k, t.data[h].val)
+else:
+  iterator pairs*(t: TTable[int, string]): tuple[key: int, val: string] =
+    ## iterates over any (key, value) pair in the table `t`.
+    for h in mycountup(0, high(t.data)):
+      var k = t.data[h].key
+      if t.data[h].slot == seFilled: yield (k, t.data[h].val)
+
+proc initTable*[A, B](initialSize=64): TTable[A, B] =
+  ## creates a new hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+block Test1:
+  # generic cache does not instantiate the same iterator[types] twice. This
+  # means we have only one instantiation of 'h'. However, this is the same for
+  # a non-generic iterator!
+
+  var t = initTable[int, string]()
+  for k, v in t.pairs: discard
+  for k, v in t.pairs: discard
+
+echo "true"
+
+# bug #1560
+for i in @[3, 4, 5]:
+  echo($i)
+
+# bug #6992
+for i in 0 ..< 5u32:
+  echo i
diff --git a/tests/iter/titer3.nim b/tests/iter/titer3.nim
new file mode 100644
index 000000000..defd56c98
--- /dev/null
+++ b/tests/iter/titer3.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''1231
+4
+6
+8
+--------
+4
+6
+8
+'''
+"""
+
+iterator count1_3: int =
+  yield 1
+  yield 2
+  yield 3
+
+for x in count1_3():
+  write(stdout, $x)
+
+# yield inside an iterator, but not in a loop:
+iterator iter1(a: openArray[int]): int =
+  yield a[0]
+
+var x = [[1, 2, 3], [4, 5, 6]]
+for y in iter1(x[0]): write(stdout, $y)
+writeLine(stdout, "")
+
+# ensure closure and inline iterators have the same behaviour regarding
+# parameter passing
+
+iterator clo(a: int): int {.closure.} =
+  yield 0+a
+  yield 1+a
+  yield 2+a
+
+iterator inl(a: int): int {.inline.} =
+  yield 0+a
+  yield 1+a
+  yield 2+a
+
+proc main =
+  var y = 4
+  for i in clo(y):
+    echo i
+    inc y
+
+  echo "--------"
+  y = 4
+  for i in inl(y):
+    echo i
+    inc y
+
+main()
diff --git a/tests/iter/titer4.nim b/tests/iter/titer4.nim
new file mode 100644
index 000000000..912883a63
--- /dev/null
+++ b/tests/iter/titer4.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "iterator within for loop context expected"
+  file: "titer4.nim"
+  line: 7
+"""
+# implicit items/pairs, but not if we have 3 for loop vars:
+for x, y, z in {'a'..'z'}: #ERROR_MSG iterator within for loop context expected
+  nil
diff --git a/tests/iter/titer5.nim b/tests/iter/titer5.nim
new file mode 100644
index 000000000..cb691ffdb
--- /dev/null
+++ b/tests/iter/titer5.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "abcxyz"
+"""
+# Test method call syntax for iterators:
+import strutils
+
+const lines = """abc  xyz"""
+
+for x in lines.split():
+  stdout.write(x)
+
+#OUT abcxyz
+stdout.write "\n"
diff --git a/tests/iter/titer6.nim b/tests/iter/titer6.nim
new file mode 100644
index 000000000..69a10d868
--- /dev/null
+++ b/tests/iter/titer6.nim
@@ -0,0 +1,35 @@
+discard """
+  output: "000"
+"""
+# Test iterator with more than 1 yield statement
+
+import strutils
+
+iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] =
+  var i = 0
+  while i < s.len:
+    var j = i
+    if s[j] in seps:
+      while j < s.len and s[j] in seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), true)
+    else:
+      while j < s.len and s[j] notin seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), false)
+    i = j
+
+for word, isSep in tokenize2("ta da", WhiteSpace):
+  var titer2TestVar = 0
+  stdout.write(titer2TestVar)
+
+proc wordWrap2(s: string, maxLineWidth = 80,
+               splitLongWords = true,
+               seps: set[char] = Whitespace,
+               newLine = "\n"): string  =
+  result = ""
+  for word, isSep in tokenize2(s, seps):
+    var w = 0
+
+stdout.write "\n"
diff --git a/tests/iter/titer7.nim b/tests/iter/titer7.nim
new file mode 100644
index 000000000..9cba3038d
--- /dev/null
+++ b/tests/iter/titer7.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''--- evens
+2
+4
+6
+8
+--- squares
+1
+4
+9
+16
+25
+36
+49
+64
+81
+'''
+"""
+
+iterator `/`[T](sequence: seq[T],
+                filter: proc(e:T):bool {.closure.}) : T =
+    for element in sequence:
+        if (filter(element)):
+            yield element
+
+iterator `>>`[I,O](sequence: seq[I],
+                   map: proc(e:I):O {.closure.}) : O =
+    for element in sequence:
+        yield map(element)
+
+iterator `/>>`[I,O](sequence: seq[I],
+                    filtermap:tuple[
+                        f:proc(e:I):bool {.closure.},
+                        m:proc(e:I):O {.closure.}]) : O =
+    for element in sequence:
+        if (filtermap.f(element)):
+            yield filtermap.m(element)
+
+proc isEven(x:int): bool =
+    (x and 1) == 0
+
+proc square(x:int): int =
+    x * x
+
+let list = @[1,2,3,4,5,6,7,8,9]
+
+echo ("--- evens")
+for item in list / isEven: echo(item)
+echo ("--- squares")
+for item in list >> square: echo(item)
+#echo ("--- squares of evens, only")
+# next line doesn't compile. Generic types are not inferred
+#for item in list />> (isEven, square) : echo(item)
diff --git a/tests/iter/titer8.nim b/tests/iter/titer8.nim
new file mode 100644
index 000000000..7b6d7b6de
--- /dev/null
+++ b/tests/iter/titer8.nim
@@ -0,0 +1,117 @@
+discard """
+  output: '''tada
+1
+2
+3
+ta da1 1
+1 2
+1 3
+2 1
+2 2
+2 3
+3 1
+3 2
+3 3
+0
+1
+2
+a1: A
+a2: A
+a1: B
+a2: B
+a1: C
+a2: C
+a1: D'''
+"""
+# Test first class iterator:
+
+import strutils
+
+iterator tokenize2(s: string, seps: set[char] = Whitespace): tuple[
+  token: string, isSep: bool] {.closure.} =
+  var i = 0
+  while i < s.len:
+    var j = i
+    if s[j] in seps:
+      while j < s.len and s[j] in seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), true)
+    else:
+      while j < s.len and s[j] notin seps: inc(j)
+      if j > i:
+        yield (substr(s, i, j-1), false)
+    i = j
+
+iterator count3(): int {.closure.} =
+  yield 1
+  yield 2
+  yield 3
+
+for word, isSep in tokenize2("ta da", WhiteSpace):
+  if not isSep:
+    stdout.write(word)
+echo ""
+
+proc inProc() =
+  for c in count3():
+    echo c
+
+  for word, isSep in tokenize2("ta da", WhiteSpace):
+    stdout.write(word)
+
+  for c in count3():
+    for d in count3():
+      echo c, " ", d
+
+
+inProc()
+
+iterator count0(): int {.closure.} =
+  # note: doesn't require anything in its closure (except 'state')
+  yield 0
+
+iterator count2(): int {.closure.} =
+  # note: requires 'x' in its closure
+  var x = 1
+  yield x
+  inc x
+  yield x
+
+# a first class iterator has the type 'proc {.closure.}', but maybe
+# it shouldn't:
+proc invoke(iter: iterator(): int {.closure.}) =
+  for x in iter(): echo x
+
+invoke(count0)
+invoke(count2)
+
+
+# simple tasking:
+type
+  TTask = iterator (ticker: int)
+
+iterator a1(ticker: int) {.closure.} =
+  echo "a1: A"
+  yield
+  echo "a1: B"
+  yield
+  echo "a1: C"
+  yield
+  echo "a1: D"
+
+iterator a2(ticker: int) {.closure.} =
+  echo "a2: A"
+  yield
+  echo "a2: B"
+  yield
+  echo "a2: C"
+
+proc runTasks(t: varargs[TTask]) =
+  var ticker = 0
+  while true:
+    let x = t[ticker mod t.len]
+    if finished(x): break
+    x(ticker)
+    inc ticker
+
+runTasks(a1, a2)
diff --git a/tests/iter/titer9.nim b/tests/iter/titer9.nim
new file mode 100644
index 000000000..99874e70a
--- /dev/null
+++ b/tests/iter/titer9.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''5
+14
+0'''
+"""
+
+iterator count[T](x: T, skip: bool): int {.closure.} =
+  if skip: return x+10
+  else: yield x+1
+
+  if skip: return x+10
+  else: yield x+2
+
+proc takeProc[T](x: iterator (x: T, skip: bool): int) =
+  echo x(4, false)
+  echo x(4, true)
+  echo x(4, false)
+
+takeProc(count[int])
+
diff --git a/tests/iter/titer_issues.nim b/tests/iter/titer_issues.nim
new file mode 100644
index 000000000..c82b3902d
--- /dev/null
+++ b/tests/iter/titer_issues.nim
@@ -0,0 +1,411 @@
+discard """
+  target: "c js"
+  output: '''
+0
+1
+2
+3
+4
+1
+start
+false
+0
+1
+2
+end
+@[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 18, 20, 21, 24, 27, 30, 36, 40, 42]
+1002
+0
+1
+2
+7
+9002
+9004
+9006
+9008
+9010
+9012
+9014
+9016
+9018
+@[1, 2]
+@[1, 2, 3]
+1
+nested finally
+outer finally
+nested finally
+outer finally
+nested finally
+outer finally
+nested finally
+outer finally
+In defer
+trying
+exception caught
+finally block
+'''
+"""
+
+
+import sequtils, strutils
+
+
+block t338:
+  proc moo(): iterator (): int =
+    iterator fooGen: int {.closure.} =
+      while true:
+        yield result
+        result.inc
+    return fooGen
+
+  var foo = moo()
+
+  for i in 0 .. 4:
+    echo foo()
+
+
+
+block t8041:
+  iterator xy[T](a: T, b: set[T]): T =
+    if a in b:
+      yield a
+
+  for a in xy(1'i8, {}):
+    for b in xy(a, {}):
+      echo a
+
+
+
+block t3837_chained:
+  iterator t1(): int {.closure.} =
+    yield 1
+
+  iterator t2(): int {.closure.} =
+    for i in t1():
+      yield i
+
+  for i in t2():
+    echo $i
+
+
+  proc iter1(): (iterator: int) =
+    let coll = [0,1,2]
+    result = iterator: int {.closure.} =
+      for i in coll:
+        yield i
+
+  proc iter2(it: (iterator: int)): (iterator: int)  =
+    result = iterator: int {.closure.} =
+      echo finished(it)
+      for i in it():
+        yield i
+
+  echo "start"
+  let myiter1 = iter1()
+  let myiter2 = iter2(myiter1)
+  for i in myiter2():
+    echo i
+  echo "end"
+
+
+  type Iterable[T] = (iterator: T) | Slice[T]
+    ## Everything that can be iterated over, iterators and slices so far.
+
+  proc toIter[T](s: Slice[T]): iterator: T =
+    ## Iterate over a slice.
+    iterator it: T {.closure.} =
+      for x in s.a..s.b:
+        yield x
+    return it
+
+  proc toIter[T](i: iterator: T): iterator: T =
+    ## Nop
+    i
+
+  iterator map[T,S](i: Iterable[T], f: proc(x: T): S): S =
+    let i = toIter(i)
+    for x in i():
+      yield f(x)
+
+  proc filter[T](i: Iterable[T], f: proc(x: T): bool): iterator: T =
+    let i = toIter(i)
+    iterator it: T {.closure.} =
+      for x in i():
+        if f(x):
+          yield x
+    result = it
+
+  iterator filter[T](i: Iterable[T], f: proc(x: T): bool): T =
+    let i = toIter(i)
+    for x in i():
+      if f(x):
+        yield x
+
+  var it = toSeq(filter(2..10, proc(x: int): bool = x mod 2 == 0))
+  doAssert it == @[2, 4, 6, 8, 10]
+  it = toSeq(map(filter(2..10, proc(x: int): bool = x mod 2 == 0), proc(x: int): int = x * 2))
+  doAssert it == @[4, 8, 12, 16, 20]
+
+
+
+block t3221_complex:
+  iterator permutations[T](ys: openArray[T]): seq[T] =
+    var
+      d = 1
+      c = newSeq[int](ys.len)
+      xs = newSeq[T](ys.len)
+    for i, y in ys: xs[i] = y
+    yield xs
+    block outer:
+      while true:
+        while d > 1:
+          dec d
+          c[d] = 0
+        while c[d] >= d:
+          inc d
+          if d >= ys.len: break outer
+        let i = if (d and 1) == 1: c[d] else: 0
+        swap xs[i], xs[d]
+        yield xs
+        inc c[d]
+
+  proc dig_vectors(): void =
+    var v_nums: seq[int]
+    v_nums = newSeq[int](1)
+    for perm in permutations(toSeq(0 .. 1)):
+      v_nums[0] = 1
+
+  dig_vectors()
+
+
+
+block t3499_keepstate:
+  proc slice[T](iter: iterator(): T {.closure.}, sl: auto): seq[T] =
+    var res: seq[int64] = @[]
+    var i = 0
+    for n in iter():
+      if i > sl.b:
+        break
+      if i >= sl.a:
+        res.add(n)
+      inc i
+    res
+
+  iterator harshad(): int64 {.closure.} =
+    for n in 1 ..< int64.high:
+      var sum = 0
+      for ch in string($n):
+        sum += parseInt("" & ch)
+      if n mod sum == 0:
+        yield n
+
+  echo harshad.slice 0 ..< 20
+
+  for n in harshad():
+    if n > 1000:
+      echo n
+      break
+
+  # bug #3499 last snippet fixed
+  # bug #705  last snippet fixed
+
+
+
+block t1725_nested:
+  iterator factory(): int {.closure.} =
+    iterator bar(): int {.closure.} =
+      yield 0
+      yield 1
+      yield 2
+
+    for x in bar(): yield x
+
+  for x in factory():
+    echo x
+
+
+
+block t2023_objiter:
+  type
+    Obj = object
+      iter: iterator (): int8 {.closure.}
+
+  iterator test(): int8 {.closure.} =
+    yield 7
+
+  proc init():Obj=
+    result.iter = test
+
+  var o = init()
+  echo(o.iter())
+
+
+block:
+  # bug #13739
+  iterator myIter(arg: openArray[int]): int =
+    var tmp = 0
+    let len = arg.len
+    while tmp < len:
+      yield arg[tmp] * 2
+      inc tmp
+
+  proc someProc() =
+    var data = [4501,4502,4503,4504,4505,4506,4507,4508,4509]
+    # StmtListExpr should not get special treatment.
+    for x in myIter((discard;data)):
+      echo x
+
+  someProc()
+
+block:
+  # bug #12576
+  iterator ff(sq: varargs[seq[int]]): int =
+    for x in sq:
+      echo x
+
+  for x in ff(@[1, 2], @[1, 2, 3]):
+    echo x
+
+
+# bug #19575
+
+iterator bb() {.closure.} =
+    while true:
+        try: discard
+        except: break
+        finally: break
+
+var a = bb
+
+iterator cc() {.closure.} =
+    while true:
+        try: discard
+        except:
+          if true:
+            break
+        finally:
+          if true:
+            break
+
+var a2 = cc
+
+# bug #16876
+block:
+  iterator a(num: int): int {.closure.} =
+      if num == 1:
+          yield num
+      else:
+          for i in a(num - 1):
+              yield i
+
+  for i in a(5):
+    echo i
+
+block:
+  # bug #19911 (return in nested try)
+
+  # try yield -> try
+  iterator p1: int {.closure.} =
+    try:
+      yield 0
+      try:
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p1():
+    discard
+
+  # try -> try yield
+  iterator p2: int {.closure.} =
+    try:
+      try:
+        yield 0
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p2():
+    discard
+
+  # try yield -> try yield
+  iterator p3: int {.closure.} =
+    try:
+      yield 0
+      try:
+        yield 0
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p3():
+    discard
+
+  # try -> try
+  iterator p4: int {.closure.} =
+    try:
+      try:
+        return
+      finally:
+        echo "nested finally"
+      echo "shouldn't run"
+    finally:
+      echo "outer finally"
+    echo "shouldn't run"
+
+  for _ in p4():
+    discard
+
+# bug #18824
+iterator poc_iterator: int {.closure.}  =
+  block bug18824:
+    try:
+      break bug18824
+    finally:
+      echo "In defer"
+
+for _ in poc_iterator():
+  discard
+
+# bug #20624
+iterator tryFinally() {.closure.} =
+  block route:
+    try:
+      echo "trying"
+      raise
+    except:
+      echo "exception caught"
+      break route
+    finally:
+      echo "finally block"
+
+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/titer_no_tuple_unpack.nim b/tests/iter/titer_no_tuple_unpack.nim
new file mode 100644
index 000000000..d8df10189
--- /dev/null
+++ b/tests/iter/titer_no_tuple_unpack.nim
@@ -0,0 +1,27 @@
+discard """
+output: '''
+3 4
+4 5
+5 6
+6 7
+7 8
+(x: 3, y: 4)
+(x: 4, y: 5)
+(x: 5, y: 6)
+(x: 6, y: 7)
+(x: 7, y: 8)
+'''
+"""
+
+
+iterator xrange(fromm, to: int, step = 1): tuple[x, y: int] =
+  var a = fromm
+  while a <= to:
+    yield (a, a+1)
+    inc(a, step)
+
+for a, b in xrange(3, 7):
+  echo a, " ", b
+
+for tup in xrange(3, 7):
+  echo tup
diff --git a/tests/iter/titerable.nim b/tests/iter/titerable.nim
new file mode 100644
index 000000000..f503836d3
--- /dev/null
+++ b/tests/iter/titerable.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''2
+4
+6
+4
+8
+12
+'''
+  disabled: "true"
+"""
+
+# Will eventually fix it...
+
+iterator map[T, U](s: iterator:T{.inline.}, f: proc(x: T): U): U =
+  for e in s: yield f(e)
+
+template toSeq(s: untyped): untyped =
+  var res = newSeq[type(s)](0)
+  for e in s: res.add(e)
+  res
+
+var s1 = @[1, 2, 3]
+for x in map(s1.items, proc (a:int): int = a*2):
+  echo x
+
+var s2 = toSeq(map(s1.items, proc (a:int): int = a*4))
+for x in s2:
+  echo x
+
diff --git a/tests/iter/titerautoerr1.nim b/tests/iter/titerautoerr1.nim
new file mode 100644
index 000000000..c7e5642c8
--- /dev/null
+++ b/tests/iter/titerautoerr1.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <int literal(1)> but expected 'string'"
+  line: 8
+"""
+
+iterator a(): auto {.closure.} =
+  if true: return "str"
+  yield 1
diff --git a/tests/iter/titerautoerr2.nim b/tests/iter/titerautoerr2.nim
new file mode 100644
index 000000000..eb48a36f9
--- /dev/null
+++ b/tests/iter/titerautoerr2.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <string> but expected 'int literal(1)'"
+  line: 8
+"""
+
+iterator b(): auto {.closure.} =
+  yield 1
+  if true: return "str"
diff --git a/tests/iter/titerautoerr3.nim b/tests/iter/titerautoerr3.nim
new file mode 100644
index 000000000..e47b65540
--- /dev/null
+++ b/tests/iter/titerautoerr3.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot infer the return type of 'bar'"
+  line: 6
+"""
+
+iterator bar(): auto =
+  discard
+for t in bar():
+  discard
diff --git a/tests/iter/titerconcat.nim b/tests/iter/titerconcat.nim
new file mode 100644
index 000000000..477ac5e26
--- /dev/null
+++ b/tests/iter/titerconcat.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''1
+2
+3
+4
+20
+21
+22
+23'''
+"""
+
+proc toIter*[T](s: Slice[T]): iterator: T =
+  iterator it: T {.closure.} =
+    for x in s.a..s.b:
+      yield x
+  return it
+
+iterator concat*[T](its: varargs[T, toIter]): auto =
+  for i in its:
+    for x in i():
+      yield x
+
+for i in concat(1..4, 20..23):
+  echo i
diff --git a/tests/iter/titerovl.nim b/tests/iter/titerovl.nim
new file mode 100644
index 000000000..be665b2b7
--- /dev/null
+++ b/tests/iter/titerovl.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''9
+1
+2
+3
+'''
+"""
+
+# Test the new overloading rules for iterators:
+
+# test that iterator 'p' is preferred:
+proc p(): seq[int] = @[1, 2, 3]
+iterator p(): int = yield 9
+
+for x in p(): echo x
+
+# test that 'q' works in this position:
+proc q(): seq[int] = @[1, 2, 3]
+
+for x in q(): echo x
+
diff --git a/tests/iter/titerslice.nim b/tests/iter/titerslice.nim
new file mode 100644
index 000000000..e5d2e14a3
--- /dev/null
+++ b/tests/iter/titerslice.nim
@@ -0,0 +1,9 @@
+discard """
+  output: '''2
+3
+4'''
+"""
+
+var t1 = @["1", "2", "3", "4"]
+for t in t1[1..3]:
+  echo t
diff --git a/tests/iter/titertypedesc.nim b/tests/iter/titertypedesc.nim
new file mode 100644
index 000000000..a69f703c6
--- /dev/null
+++ b/tests/iter/titertypedesc.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''0
+(id: 0)
+@[]
+[0, 0, 0]'''
+"""
+
+iterator foo*(T: typedesc): T =
+  var x: T
+  yield x
+
+for a in foo(int): echo a
+for b in foo(tuple[id: int]): echo b
+for c in foo(seq[int]): echo c
+
+type Generic[T] = T
+for d in foo(Generic[array[0..2, int]]): echo d
diff --git a/tests/titer2.nim b/tests/iter/titervaropenarray.nim
index b9cdb53fe..b2fe71ceb 100755..100644
--- a/tests/titer2.nim
+++ b/tests/iter/titervaropenarray.nim
@@ -1,3 +1,7 @@
+discard """
+  output: "123"
+  targets: "c cpp"
+"""
 # Try to break the transformation pass:
 iterator iterAndZero(a: var openArray[int]): int =
   for i in 0..len(a)-1:
@@ -8,3 +12,4 @@ var x = [[1, 2, 3], [4, 5, 6]]
 for y in iterAndZero(x[0]): write(stdout, $y)
 #OUT 123
 
+write stdout, "\n"
diff --git a/tests/iter/tmoditer.nim b/tests/iter/tmoditer.nim
new file mode 100644
index 000000000..99e5b642d
--- /dev/null
+++ b/tests/iter/tmoditer.nim
@@ -0,0 +1,88 @@
+discard """
+  output: "XXXXX01234"
+"""
+
+iterator modPairs(a: var array[0..4,string]): tuple[key: int, val: var string] =
+  for i in 0..a.high:
+    yield (key: i, val: a[i])
+
+iterator modItems*[T](a: var array[0..4,T]): var T =
+  for i in 0..a.high:
+    yield a[i]
+
+var
+  arr = ["a", "b", "c", "d", "e"]
+
+for a in modItems(arr):
+  a = "X"
+
+for a in items(arr):
+  stdout.write(a)
+
+for i, a in modPairs(arr):
+  a = $i
+
+for a in items(arr):
+  stdout.write(a)
+
+echo ""
+
+#--------------------------------------------------------------------
+# Lent iterators
+#--------------------------------------------------------------------
+type
+  NonCopyable = object
+    x: int
+
+
+proc `=destroy`(o: var NonCopyable) =
+  discard
+
+proc `=copy`(dst: var NonCopyable, src: NonCopyable) {.error.}
+
+proc `=sink`(dst: var NonCopyable, src: NonCopyable) =
+  dst.x = src.x
+
+iterator lentItems[T](a: openArray[T]): lent T =
+  for i in 0..a.high:
+    yield a[i]
+
+iterator lentPairs[T](a: array[0..1, T]): tuple[key: int, val: lent T] =
+  for i in 0..a.high:
+    yield (key: i, val: a[i])
+
+
+let arr1 = [1, 2, 3]
+let arr2 = @["a", "b", "c"]
+let arr3 = [NonCopyable(x: 1), NonCopyable(x: 2)]
+let arr4 = @[(1, "a"), (2, "b"), (3, "c")]
+
+var accum: string
+for x in lentItems(arr1):
+  accum &= $x
+doAssert(accum == "123")
+
+accum = ""
+for x in lentItems(arr2):
+  accum &= $x
+doAssert(accum == "abc")
+
+accum = ""
+for val in lentItems(arr3):
+  accum &= $val.x
+doAssert(accum == "12")
+
+accum = ""
+for i, val in lentPairs(arr3):
+  accum &= $i & "-" & $val.x & " "
+doAssert(accum == "0-1 1-2 ")
+
+accum = ""
+for i, val in lentItems(arr4):
+  accum &= $i & "-" & $val & " "
+doAssert(accum == "1-a 2-b 3-c ")
+
+accum = ""
+for (i, val) in lentItems(arr4):
+  accum &= $i & "-" & $val & " "
+doAssert(accum == "1-a 2-b 3-c ")
diff --git a/tests/iter/tpermutations.nim b/tests/iter/tpermutations.nim
new file mode 100644
index 000000000..30a66460f
--- /dev/null
+++ b/tests/iter/tpermutations.nim
@@ -0,0 +1,69 @@
+discard """
+output: '''
+@[@[1.0, 2.0], @[3.0, 4.0]]
+perm: 10.0 det: -2.0
+@[@[1.0, 2.0, 3.0, 4.0], @[4.0, 5.0, 6.0, 7.0], @[7.0, 8.0, 9.0, 10.0], @[10.0, 11.0, 12.0, 13.0]]
+perm: 29556.0 det: 0.0
+@[@[0.0, 1.0, 2.0, 3.0, 4.0], @[5.0, 6.0, 7.0, 8.0, 9.0], @[10.0, 11.0, 12.0, 13.0, 14.0], @[15.0, 16.0, 17.0, 18.0, 19.0], @[20.0, 21.0, 22.0, 23.0, 24.0]]
+perm: 6778800.0 det: 0.0
+'''
+"""
+
+
+import sequtils, sugar
+
+iterator permutations*[T](ys: openArray[T]): tuple[perm: seq[T], sign: int] =
+  var
+    d = 1
+    c = newSeq[int](ys.len)
+    xs = newSeq[T](ys.len)
+    sign = 1
+
+  for i, y in ys: xs[i] = y
+  yield (xs, sign)
+
+  block outter:
+    while true:
+      while d > 1:
+        dec d
+        c[d] = 0
+      while c[d] >= d:
+        inc d
+        if d >= ys.len: break outter
+
+      let i = if (d and 1) == 1: c[d] else: 0
+      swap xs[i], xs[d]
+      sign *= -1
+      yield (xs, sign)
+      inc c[d]
+
+proc det(a: seq[seq[float]]): float =
+  let n = toSeq 0..a.high
+  for sigma, sign in n.permutations:
+    result += sign.float * n.map((i: int) => a[i][sigma[i]]).foldl(a * b)
+
+proc perm(a: seq[seq[float]]): float =
+  let n = toSeq 0..a.high
+  for sigma, sign in n.permutations:
+    result += n.map((i: int) => a[i][sigma[i]]).foldl(a * b)
+
+for a in [
+    @[ @[1.0, 2.0]
+     , @[3.0, 4.0]
+    ],
+    @[ @[ 1.0,  2,  3,  4]
+     , @[ 4.0,  5,  6,  7]
+     , @[ 7.0,  8,  9, 10]
+     , @[10.0, 11, 12, 13]
+    ],
+    @[ @[ 0.0,  1,  2,  3,  4]
+     , @[ 5.0,  6,  7,  8,  9]
+     , @[10.0, 11, 12, 13, 14]
+     , @[15.0, 16, 17, 18, 19]
+     , @[20.0, 21, 22, 23, 24]
+    ] ]:
+  echo a
+  echo "perm: ", a.perm, " det: ", a.det
+
+# bug #3499 last snippet fixed
+# bug 705  last snippet fixed
diff --git a/tests/iter/treciter.nim b/tests/iter/treciter.nim
new file mode 100644
index 000000000..11fb58224
--- /dev/null
+++ b/tests/iter/treciter.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "recursion is not supported in iterators: 'myrec'"
+  file: "treciter.nim"
+  line: 9
+"""
+# Test that an error message occurs for a recursive iterator
+
+iterator myrec(n: int): int =
+  for x in myrec(n-1): #ERROR_MSG recursive dependency: 'myrec'
+    yield x
+
+for x in myrec(10): echo x
diff --git a/tests/iter/tscheduler.nim b/tests/iter/tscheduler.nim
new file mode 100644
index 000000000..f4b04f311
--- /dev/null
+++ b/tests/iter/tscheduler.nim
@@ -0,0 +1,77 @@
+discard """
+  output: '''a1 5
+a2 10
+a1 3
+a1 1
+a2 8
+a2 6
+a2 4
+a2 2'''
+  disabled: "true"
+"""
+
+import os, strutils, times, algorithm
+
+
+type TaskFn = iterator (): float
+
+type Task = object
+    coro: TaskFn
+    next_run: float
+
+
+type Scheduler = object
+    tasks: seq[Task]
+
+
+proc newScheduler(): Scheduler =
+    var s = Scheduler()
+    s.tasks = @[]
+    return s
+
+
+proc start(this: var Scheduler, task: TaskFn) =
+    var t = Task()
+    t.coro = task
+    t.next_run = 0.0
+    this.tasks.add(t)
+
+
+proc run(this: var Scheduler) =
+    while this.tasks.len > 0:
+        var dead: seq[int] = @[]
+        for i in this.tasks.low..this.tasks.high:
+            var task = this.tasks[i]
+            if finished(task.coro):
+                dead.add(i)
+                continue
+            if task.next_run <= epochTime():
+                task.next_run = task.coro() + epochTime()
+            this.tasks[i] = task
+        for i in dead:
+            this.tasks.delete(i)
+        if this.tasks.len > 0:
+            sort(this.tasks, proc (t1: Task, t2: Task): int = cmp(t1.next_run, t2.next_run))
+            sleep(int((this.tasks[0].next_run - epochTime()) * 1000))
+
+
+iterator a1(): float {.closure.} =
+    var k = 5
+    while k > 0:
+        echo "a1 $1" % [$k]
+        dec k, 2
+        yield 0.5
+
+
+iterator a2(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a2 $1" % [$k]
+        dec k, 2
+        yield 1.5
+
+
+var sched = newScheduler()
+sched.start(a1)
+sched.start(a2)
+sched.run()
diff --git a/tests/iter/tshallowcopy_closures.nim b/tests/iter/tshallowcopy_closures.nim
new file mode 100644
index 000000000..06b04a788
--- /dev/null
+++ b/tests/iter/tshallowcopy_closures.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc"
+  ccodecheck: "!@('{' \\s* 'NI HEX3Astate;' \\s* '}')"
+  output: '''
+a1 10
+a1 9
+'''
+"""
+
+# bug #1803
+type TaskFn = iterator (): float
+
+iterator a1(): float {.closure.} =
+    var k = 10
+    while k > 0:
+        echo "a1 ", k
+        dec k
+        yield 1.0
+
+
+iterator a2(): float {.closure.} =
+    var k = 15
+    while k > 0:
+        echo "a2 ", k
+        dec k
+        yield 2.0
+
+var
+  x = a1
+  y = a2
+  z: TaskFn
+
+discard x()
+shallowCopy(z, x)
+shallowCopy(z, y)
+discard x()
diff --git a/tests/iter/twrap_walkdir.nim b/tests/iter/twrap_walkdir.nim
new file mode 100644
index 000000000..1d52e9791
--- /dev/null
+++ b/tests/iter/twrap_walkdir.nim
@@ -0,0 +1,17 @@
+discard """
+action: compile
+"""
+
+import os
+
+# bug #3636
+
+proc fooIt(foo: string): iterator(): (string) =
+  iterator temp(): (string) =
+    for f in walkDirRec(foo): # No problem with walkFiles
+      yield f
+  return temp
+
+let it = fooIt(".")
+for x in it():
+  echo x
diff --git a/tests/iter/twrongiter.nim b/tests/iter/twrongiter.nim
new file mode 100644
index 000000000..577b8c4f1
--- /dev/null
+++ b/tests/iter/twrongiter.nim
@@ -0,0 +1,13 @@
+discard """
+errormsg: "type mismatch"
+line: 12
+"""
+
+proc first(it: iterator(): int): seq[int] =
+  return @[]
+
+iterator primes(): int =
+  yield 1
+
+for i in first(primes):
+  break
diff --git a/tests/iter/tyieldintry.nim b/tests/iter/tyieldintry.nim
new file mode 100644
index 000000000..e51ab7f0d
--- /dev/null
+++ b/tests/iter/tyieldintry.nim
@@ -0,0 +1,529 @@
+discard """
+  matrix: "; --experimental:strictdefs; -d:nimOptIters"
+  targets: "c cpp"
+"""
+
+var closureIterResult = newSeq[int]()
+
+proc checkpoint(arg: int) =
+  closureIterResult.add(arg)
+
+type
+  TestError = object of CatchableError
+  AnotherError = object of CatchableError
+
+proc testClosureIterAux(it: iterator(): int, exceptionExpected: bool, expectedResults: varargs[int]) =
+  closureIterResult.setLen(0)
+
+  var exceptionCaught = false
+
+  try:
+    for i in it():
+      closureIterResult.add(i)
+  except TestError:
+    exceptionCaught = true
+
+  if closureIterResult != @expectedResults or exceptionCaught != exceptionExpected:
+    if closureIterResult != @expectedResults:
+      echo "Expected: ", @expectedResults
+      echo "Actual: ", closureIterResult
+    if exceptionCaught != exceptionExpected:
+      echo "Expected exception: ", exceptionExpected
+      echo "Got exception: ", exceptionCaught
+    doAssert(false)
+
+proc test(it: iterator(): int, expectedResults: varargs[int]) =
+  testClosureIterAux(it, false, expectedResults)
+
+proc testExc(it: iterator(): int, expectedResults: varargs[int]) =
+  testClosureIterAux(it, true, expectedResults)
+
+proc raiseTestError() =
+  raise newException(TestError, "Test exception!")
+
+block:
+  iterator it(): int {.closure.} =
+    var i = 5
+    while i != 0:
+      yield i
+      if i == 3:
+        yield 123
+      dec i
+
+  test(it, 5, 4, 3, 123, 2, 1)
+
+block:
+  iterator it(): int {.closure.} =
+    yield 0
+    try:
+      checkpoint(1)
+      raiseTestError()
+    except TestError:
+      checkpoint(2)
+      yield 3
+      checkpoint(4)
+    finally:
+      checkpoint(5)
+
+    checkpoint(6)
+
+  test(it, 0, 1, 2, 3, 4, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    yield 0
+    try:
+      yield 1
+      checkpoint(2)
+    finally:
+      checkpoint(3)
+      yield 4
+      checkpoint(5)
+      yield 6
+
+  test(it, 0, 1, 2, 3, 4, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    yield 0
+    try:
+      yield 1
+      raiseTestError()
+      yield 2
+    finally:
+      checkpoint(3)
+      yield 4
+      checkpoint(5)
+      yield 6
+
+  testExc(it, 0, 1, 3, 4, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      try:
+        raiseTestError()
+      except AnotherError:
+        yield 123
+      finally:
+        checkpoint(3)
+    finally:
+      checkpoint(4)
+
+  testExc(it, 3, 4)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      yield 1
+      raiseTestError()
+    except AnotherError:
+      checkpoint(123)
+    finally:
+      checkpoint(2)
+    checkpoint(3)
+
+  testExc(it, 1, 2)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      yield 0
+      try:
+        yield 1
+        try:
+          yield 2
+          raiseTestError()
+        except AnotherError:
+          yield 123
+        finally:
+          yield 3
+      except AnotherError:
+        yield 124
+      finally:
+        yield 4
+      checkpoint(1234)
+    except:
+      yield 5
+      checkpoint(6)
+    finally:
+      checkpoint(7)
+      yield 8
+    checkpoint(9)
+
+  test(it, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      yield 0
+      return 2
+    finally:
+      checkpoint(1)
+    checkpoint(123)
+
+  test(it, 0, 1)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      try:
+        yield 0
+        raiseTestError()
+      finally:
+        checkpoint(1)
+    except TestError:
+      yield 2
+      return
+    finally:
+      yield 3
+
+    checkpoint(123)
+
+  test(it, 0, 1, 2, 3)
+
+block:
+  iterator it(): int {.closure.} =
+    try:
+      try:
+        yield 0
+        raiseTestError()
+      finally:
+        return # Return in finally should stop exception propagation
+    except AnotherError:
+      yield 2
+      return
+    finally:
+      yield 3
+    checkpoint(123)
+
+  test(it, 0, 3)
+
+block: # Yield in yield
+  iterator it(): int {.closure.} =
+    template foo(): int =
+      yield 1
+      2
+
+    for i in 0 .. 2:
+      checkpoint(0)
+      yield foo()
+
+  test(it, 0, 1, 2, 0, 1, 2, 0, 1, 2)
+
+block:
+  iterator it(): int {.closure.} =
+    let i = if true:
+        yield 0
+        1
+      else:
+        2
+    yield i
+
+  test(it, 0, 1)
+
+block:
+  iterator it(): int {.closure.} =
+    var foo = 123
+    let i = try:
+        yield 0
+        raiseTestError()
+        1
+      except TestError as e:
+        assert(e.msg == "Test exception!")
+        case foo
+        of 1:
+          yield 123
+          2
+        of 123:
+          yield 5
+          6
+        else:
+          7
+    yield i
+
+  test(it, 0, 5, 6)
+
+block:
+  iterator it(): int {.closure.} =
+    proc voidFoo(i1, i2, i3: int) =
+      checkpoint(i1)
+      checkpoint(i2)
+      checkpoint(i3)
+
+    proc foo(i1, i2, i3: int): int =
+      voidFoo(i1, i2, i3)
+      i3
+
+    proc bar(i1: int): int =
+      checkpoint(i1)
+
+    template tryexcept: int =
+      try:
+        yield 1
+        raiseTestError()
+        123
+      except TestError:
+        yield 2
+        checkpoint(3)
+        4
+
+    let e1 = true
+
+    template ifelse1: int =
+      if e1:
+        yield 10
+        11
+      else:
+        12
+
+    template ifelse2: int =
+      if ifelse1() == 12:
+        yield 20
+        21
+      else:
+        yield 22
+        23
+
+    let i = foo(bar(0), tryexcept, ifelse2)
+    discard foo(bar(0), tryexcept, ifelse2)
+    voidFoo(bar(0), tryexcept, ifelse2)
+    yield i
+
+  test(it,
+
+    # let i = foo(bar(0), tryexcept, ifelse2)
+    0, # bar(0)
+    1, 2, 3, # tryexcept
+    10, # ifelse1
+    22, # ifelse22
+    0, 4, 23, # foo
+
+    # discard foo(bar(0), tryexcept, ifelse2)
+    0, # bar(0)
+    1, 2, 3, # tryexcept
+    10, # ifelse1
+    22, # ifelse22
+    0, 4, 23, # foo
+
+    # voidFoo(bar(0), tryexcept, ifelse2)
+    0, # bar(0)
+    1, 2, 3, # tryexcept
+    10, # ifelse1
+    22, # ifelse22
+    0, 4, 23, # foo
+
+    23 # i
+  )
+
+block:
+  iterator it(): int {.closure.} =
+    checkpoint(0)
+    for i in 0 .. 1:
+      try:
+        yield 1
+        raiseTestError()
+      except TestError as e:
+        doAssert(e.msg == "Test exception!")
+        yield 2
+      except AnotherError:
+        yield 123
+      except:
+        yield 1234
+      finally:
+        yield 3
+        checkpoint(4)
+        yield 5
+
+  test(it, 0, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5)
+
+block:
+  iterator it(): int {.closure.} =
+    var i = 5
+    template foo(): bool =
+      yield i
+      true
+
+    while foo():
+      dec i
+      if i == 0:
+        break
+
+  test(it, 5, 4, 3, 2, 1)
+
+block: # Short cirquits
+  iterator it(): int {.closure.} =
+    template trueYield: bool =
+      yield 1
+      true
+
+    template falseYield: bool =
+      yield 0
+      false
+
+    if trueYield or falseYield:
+      discard falseYield and trueYield
+
+    if falseYield and trueYield:
+      checkpoint(123)
+
+  test(it, 1, 0, 0)
+
+block: #7969
+  type
+    SomeObj = object
+      id: int
+
+  iterator it(): int {.closure.} =
+    template yieldAndSomeObj: SomeObj =
+      var s: SomeObj
+      s.id = 2
+      yield 1
+      s
+
+    checkpoint(yieldAndSomeObj().id)
+
+    var i = 5
+    case i
+    of 0:
+      checkpoint(123)
+    of 1, 2, 5:
+      checkpoint(3)
+    else:
+      checkpoint(123)
+
+  test(it, 1, 2, 3)
+
+block: # yield in blockexpr
+  iterator it(): int {.closure.} =
+    yield(block:
+      checkpoint(1)
+      yield 2
+      3
+    )
+
+  test(it, 1, 2, 3)
+
+block: #8851
+  type
+    Foo = ref object of RootObj
+  template someFoo(): Foo =
+    var f: Foo
+    yield 1
+    f
+  iterator it(): int {.closure.} =
+    var o: RootRef
+    o = someFoo()
+
+  test(it, 1)
+
+block: # 8243
+  iterator it(): int {.closure.} =
+    template yieldAndSeq: seq[int] =
+      yield 1
+      @[123, 5, 123]
+
+    checkpoint(yieldAndSeq[1])
+
+  test(it, 1, 5)
+
+block:
+  iterator it(): int {.closure.} =
+    template yieldAndSeq: seq[int] =
+      yield 1
+      @[123, 5, 123]
+
+    template yieldAndNum: int =
+      yield 2
+      1
+
+    checkpoint(yieldAndSeq[yieldAndNum])
+
+  test(it, 1, 2, 5)
+
+block: #9694 - yield in ObjConstr
+  type Foo = object
+    a, b: int
+
+  template yieldAndNum: int =
+    yield 1
+    2
+
+  iterator it(): int {.closure.} =
+    let a = Foo(a: 5, b: yieldAndNum())
+    checkpoint(a.b)
+
+  test(it, 1, 2)
+
+block: #9716
+  iterator it(): int {.closure.} =
+    var a = 0
+    for i in 1 .. 3:
+      var a: int # Make sure the "local" var is reset
+      var b: string # ditto
+      yield 1
+      a += 5
+      b &= "hello"
+      doAssert(a == 5)
+      doAssert(b == "hello")
+  test(it, 1, 1, 1)
+
+block: # nnkChckRange
+  type Foo = distinct uint64
+  template yieldDistinct: Foo =
+    yield 2
+    Foo(0)
+
+  iterator it(): int {.closure.} =
+    yield 1
+    var a: int
+    a = int(yieldDistinct())
+    yield 3
+
+  test(it, 1, 2, 3)
+
+block: #17849 - yield in case subject
+  template yieldInCase: int =
+    yield 2
+    3
+
+  iterator it(): int {.closure.} =
+    yield 1
+    case yieldInCase()
+    of 1: checkpoint(11)
+    of 3: checkpoint(13)
+    else: checkpoint(14)
+    yield 5
+
+  test(it, 1, 2, 13, 5)
+
+block: # void iterator
+  iterator it() {.closure.} =
+    try:
+      yield
+    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/ecmas.html b/tests/js.html
index 1cb56e72a..81baef784 100755..100644
--- a/tests/ecmas.html
+++ b/tests/js.html
@@ -2,18 +2,18 @@
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
-<!--  This has been written by hand. (c) 2008 Andreas Rumpf -->
+<!--  This has been written by hand. (c) 2010 Andreas Rumpf -->
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<title>Nimrod ECMAScript Generator Test</title>
+<title>Nimrod JavaScript Generator Test</title>
 <style type="text/css">
 span.DecNumber {color: blue}
 </style>
-<script src="nimrcache/ecmas.js" type="text/javascript"></script>
+<script src="nimcache/js.js" type="text/javascript"></script>
 </head>
 <body onload="OnLoad()">
-<form name="form1" action="ecmas.html">
-  <input type="text" name="input" size="3" />
+<form name="form1" action="js.html">
+  <input type="text" name="input1" size="10" />
   <input type="button" value="Calculate square" onclick="OnButtonClick()" />
 </form>
 
diff --git a/tests/js.nim b/tests/js.nim
new file mode 100644
index 000000000..92cb130bd
--- /dev/null
+++ b/tests/js.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: "nim js --hints:on $options $file"
+"""
+
+# This file tests the JavaScript generator
+
+import
+  dom, strutils
+
+# We need to declare the used elements here. This is annoying but
+# prevents any kind of typo:
+var
+  inputElement {.importc: "document.form1.input1", nodecl.}: ref TElement
+
+proc OnButtonClick() {.exportc.} =
+  let v = $inputElement.value
+  if v.allCharsInSet(whiteSpace):
+    echo "only whitespace, hu?"
+  else:
+    var x = parseInt(v)
+    echo x*x
+
+proc OnLoad() {.exportc.} =
+  echo "Welcome! Please take your time to fill in this formular!"
diff --git a/tests/js/readme.md b/tests/js/readme.md
new file mode 100644
index 000000000..7fcc722fa
--- /dev/null
+++ b/tests/js/readme.md
@@ -0,0 +1,5 @@
+## notes
+Prefer moving tests to a non-js directory so that they get tested across all backends automatically.
+Ideally, tests/js should be reserved to code that only makes sense in js.
+
+Note also that tests for a js specific module (e.g.: `std/jsbigints`) belong to `tests/stdlib`, (e.g.: `tests/stdlib/tjsbigints.nim`)
diff --git a/tests/js/t11166.nim b/tests/js/t11166.nim
new file mode 100644
index 000000000..e98ccda10
--- /dev/null
+++ b/tests/js/t11166.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''
+test1
+test2
+'''
+"""
+
+import jsffi
+
+type
+  C = object
+    props: int
+
+var c: C
+
+when compiles(c.props):
+  echo "test1"
+
+when not compiles(d.props):
+  echo "test2"
diff --git a/tests/js/t11353.nim b/tests/js/t11353.nim
new file mode 100644
index 000000000..c1bc0ad4b
--- /dev/null
+++ b/tests/js/t11353.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''
+{}
+{}
+'''
+"""
+
+proc foo() =
+  var bar: set[int16] = {}
+  echo bar
+  bar.incl(1)
+
+foo()
+foo()
diff --git a/tests/js/t11354.nim b/tests/js/t11354.nim
new file mode 100644
index 000000000..8dee90de0
--- /dev/null
+++ b/tests/js/t11354.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''
+0
+@[@[0, 1]]
+'''
+"""
+
+type
+  TrackySeq[T] = object
+    s: seq[T]
+    pos: int
+
+proc foobar(ls: var TrackySeq[seq[int]], i: int): var seq[int] =
+  echo ls.pos  # removing this, or making the return explicit works
+  ls.s[i]
+
+var foo: TrackySeq[seq[int]]
+foo.s.add(@[0])
+foo.foobar(0).add(1)
+echo foo.s
\ No newline at end of file
diff --git a/tests/js/t11697.nim b/tests/js/t11697.nim
new file mode 100644
index 000000000..967752586
--- /dev/null
+++ b/tests/js/t11697.nim
@@ -0,0 +1,5 @@
+import tables
+
+var xs: Table[int, Table[int, int]]
+
+doAssertRaises(KeyError): reset xs[0]
diff --git a/tests/js/t12223.nim b/tests/js/t12223.nim
new file mode 100644
index 000000000..c0e75fb44
--- /dev/null
+++ b/tests/js/t12223.nim
@@ -0,0 +1,20 @@
+discard """
+  action: "run"
+  output: '''
+caught
+index out of bounds, the container is empty
+'''
+"""
+
+proc fun() =
+  var z: seq[string]
+  discard z[4]
+
+proc main()=
+  try:
+    fun()
+  except Exception as e:
+    echo "caught"
+    echo getCurrentExceptionMsg()
+
+main()
\ No newline at end of file
diff --git a/tests/js/t12303.nim b/tests/js/t12303.nim
new file mode 100644
index 000000000..270d82ced
--- /dev/null
+++ b/tests/js/t12303.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "{ b: 2 }"
+"""
+
+import jsconsole, jsffi
+
+type
+  A = ref object
+   b: B
+
+  B = object
+    b: int
+
+var a = cast[A](js{})
+a.b = B(b: 2)
+console.log a.b
diff --git a/tests/js/t12672.nim b/tests/js/t12672.nim
new file mode 100644
index 000000000..a658fbcbe
--- /dev/null
+++ b/tests/js/t12672.nim
@@ -0,0 +1,12 @@
+discard """
+  output: ""
+"""
+
+proc foo =
+  var x: seq[seq[int]]
+  for row in x.mitems:
+    let i = 1
+    echo row
+    inc row[i-1]
+
+foo()
diff --git a/tests/js/t14153.nim b/tests/js/t14153.nim
new file mode 100644
index 000000000..350bbd83b
--- /dev/null
+++ b/tests/js/t14153.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''
+index 5 not in 0 .. 2
+index 5 not in 0 .. 2
+'''
+"""
+
+var x = @[1, 2, 3]
+
+try:
+  echo x[5]
+except IndexError:
+  echo getCurrentExceptionMsg()
+except:
+  doAssert false
+
+try:
+  x[5] = 8
+except IndexError:
+  echo getCurrentExceptionMsg()
+except:
+  doAssert false
diff --git a/tests/js/t14570.nim b/tests/js/t14570.nim
new file mode 100644
index 000000000..100c2651d
--- /dev/null
+++ b/tests/js/t14570.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''
+18
+'''
+"""
+
+type A = range[15 .. 30]
+
+let a: A = 18
+
+echo ord(a)
diff --git a/tests/js/t17177.nim b/tests/js/t17177.nim
new file mode 100644
index 000000000..fc362cec1
--- /dev/null
+++ b/tests/js/t17177.nim
@@ -0,0 +1,10 @@
+import std/asyncjs
+
+proc fn1(n: int): Future[int] {.async.} = return n
+proc main2() =
+  proc fn2(n: int): Future[int] {.async.} = return n
+proc main3(a: auto) =
+  proc fn3(n: int): Future[int] {.async.} = return n
+proc main4() {.async.} =
+  proc fn4(n: int): Future[int] {.async.} = return n
+  discard
diff --git a/tests/js/t20233.nim b/tests/js/t20233.nim
new file mode 100644
index 000000000..401d14122
--- /dev/null
+++ b/tests/js/t20233.nim
@@ -0,0 +1,7 @@
+discard """
+  output: "yes"
+"""
+case 1.0
+of 1.0..2.0, 4.0: echo "yes"
+of 3.0: discard
+else: echo "no"
\ No newline at end of file
diff --git a/tests/js/t20235.nim b/tests/js/t20235.nim
new file mode 100644
index 000000000..3a69c2bd6
--- /dev/null
+++ b/tests/js/t20235.nim
@@ -0,0 +1,11 @@
+discard """
+  action: "run"
+  output: "0 4"
+"""
+
+proc main =
+  var s = ""
+  s.setLen(4)
+  echo s[0].ord, " ", s.len
+
+main()
diff --git a/tests/js/t21209.nim b/tests/js/t21209.nim
new file mode 100644
index 000000000..4de34f035
--- /dev/null
+++ b/tests/js/t21209.nim
@@ -0,0 +1,6 @@
+discard """
+  action: "compile"
+  cmd: "nim check --warning[UnusedImport]:off $file"
+"""
+
+import std/times
diff --git a/tests/js/t21209.nims b/tests/js/t21209.nims
new file mode 100644
index 000000000..318e28f97
--- /dev/null
+++ b/tests/js/t21209.nims
@@ -0,0 +1 @@
+--b:js
\ No newline at end of file
diff --git a/tests/js/t21247.nim b/tests/js/t21247.nim
new file mode 100644
index 000000000..5b38787b3
--- /dev/null
+++ b/tests/js/t21247.nim
@@ -0,0 +1,15 @@
+import std/typetraits
+
+type
+  QueryParams* = distinct seq[(string, string)]
+
+converter toBase*(params: var QueryParams): var seq[(string, string)] =
+  params.distinctBase
+
+proc foo(): QueryParams =
+  # Issue was that the implicit converter call didn't say that it took the
+  # address of the parameter it was converting. This led to the parameter not being
+  # passed as a fat pointer which toBase expected
+  result.add(("hello", "world"))
+
+assert foo().distinctBase() == @[("hello", "world")]
diff --git a/tests/js/t21439.nim b/tests/js/t21439.nim
new file mode 100644
index 000000000..3caeb090a
--- /dev/null
+++ b/tests/js/t21439.nim
@@ -0,0 +1,11 @@
+proc test(a: openArray[string]): proc =
+  let a = @a
+  result = proc =
+    for i in a:
+      discard i
+
+
+const a = ["t1", "t2"]
+
+discard test(a)
+
diff --git a/tests/js/t6612.nim b/tests/js/t6612.nim
new file mode 100644
index 000000000..232711c16
--- /dev/null
+++ b/tests/js/t6612.nim
@@ -0,0 +1,24 @@
+discard """
+  action: "run"
+"""
+
+proc fillWith(sq: var seq[int], n: int, unused: string) =
+  sq = @[n]
+
+type
+  Object = object of RootObj
+    case hasNums: bool
+    of true:
+      numbers: seq[int]
+    of false:
+      discard
+    always: seq[int]
+
+var obj = Object(hasNums: true)
+
+obj.always.fillWith(5, "unused")
+doAssert obj.always == @[5]
+
+obj.numbers.fillWith(3, "unused")
+doAssert obj.numbers == @[3]
+doAssert obj.always == @[5]
diff --git a/tests/js/t7109.nim b/tests/js/t7109.nim
new file mode 100644
index 000000000..a1a3b718e
--- /dev/null
+++ b/tests/js/t7109.nim
@@ -0,0 +1,8 @@
+iterator iter*(): int {.closure.} =
+  yield 3
+
+var x = iter
+doAssert x() == 3
+
+let fIt = iterator(): int = yield 70
+doAssert fIt() == 70
diff --git a/tests/js/t7127.nim b/tests/js/t7127.nim
new file mode 100644
index 000000000..364aedd4a
--- /dev/null
+++ b/tests/js/t7127.nim
@@ -0,0 +1,2 @@
+doAssertRaises(DivByZeroDefect): discard 1 mod 0
+doAssertRaises(DivByZeroDefect): discard 1 div 0
\ No newline at end of file
diff --git a/tests/js/t7224.nim b/tests/js/t7224.nim
new file mode 100644
index 000000000..77fef10a7
--- /dev/null
+++ b/tests/js/t7224.nim
@@ -0,0 +1,28 @@
+discard """
+  cmd: "nim $target $options --stackTrace:on --lineTrace:on $file"
+  outputsub: '''
+t7224.nim(25) at module t7224
+t7224.nim(22) at t7224.aaa
+t7224.nim(19) at t7224.bbb
+t7224.nim(16) at t7224.ccc
+t7224.nim(13) at t7224.ddd
+'''
+"""
+
+proc ddd() =
+  raise newException(IOError, "didn't do stuff")
+
+proc ccc() =
+  ddd()
+
+proc bbb() =
+  ccc()
+
+proc aaa() =
+  bbb()
+
+try:
+  aaa()
+
+except IOError as e:
+  echo getStackTrace(e)
diff --git a/tests/js/t7249.nim b/tests/js/t7249.nim
new file mode 100644
index 000000000..52eee2f7c
--- /dev/null
+++ b/tests/js/t7249.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''
+a -> 2
+a <- 2
+'''
+"""
+
+import jsffi
+
+var a = JsAssoc[cstring, int]{a: 2}
+
+for z, b in a:
+  echo z, " -> ", b
+
+proc f =
+  var a = JsAssoc[cstring, int]{a: 2}
+
+  for z, b in a:
+    echo z, " <- ", b
+
+f()
diff --git a/tests/js/t7534.nim b/tests/js/t7534.nim
new file mode 100644
index 000000000..64aadb8d6
--- /dev/null
+++ b/tests/js/t7534.nim
@@ -0,0 +1,7 @@
+proc f(x: int): int =
+  result = case x
+    of 1: 2
+    elif x == 2: 3
+    else: 1
+
+doAssert 2 == f(f(f(f(1))))
diff --git a/tests/js/t8231.nim b/tests/js/t8231.nim
new file mode 100644
index 000000000..b0625a621
--- /dev/null
+++ b/tests/js/t8231.nim
@@ -0,0 +1,3 @@
+import strutils
+
+doAssert formatSize(2462056448, '.', bpIEC, false) == "2.293GiB"
\ No newline at end of file
diff --git a/tests/js/t8821.nim b/tests/js/t8821.nim
new file mode 100644
index 000000000..38c88efa8
--- /dev/null
+++ b/tests/js/t8821.nim
@@ -0,0 +1,9 @@
+
+proc isInt32(i: int): bool =
+  case i 
+  of 1 .. 70000:
+    return true
+  else:
+    return false
+
+doAssert isInt32(1) == true
\ No newline at end of file
diff --git a/tests/js/t8914.nim b/tests/js/t8914.nim
new file mode 100644
index 000000000..ff716b42a
--- /dev/null
+++ b/tests/js/t8914.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''
+@[42]
+@[24, 42]
+'''
+"""
+
+var x = @[42,4242]
+x.delete(1)
+echo x
+x.insert(24)
+echo x
diff --git a/tests/js/t9410.nim b/tests/js/t9410.nim
new file mode 100644
index 000000000..042520dc5
--- /dev/null
+++ b/tests/js/t9410.nim
@@ -0,0 +1,471 @@
+template tests =
+  block:
+    var i = 0
+    i = 2
+
+    var y: ptr int
+    doAssert y == nil
+    doAssert isNil(y)
+    y = i.addr
+    y[] = 3
+    doAssert i == 3
+    doAssert i == y[]
+
+    let z = i.addr
+    z[] = 4
+    doAssert i == 4
+    doAssert i == y[] and y[] == z[]
+
+    var hmm = (a: (b: z))
+    var hmmptr = hmm.a.b.addr
+    hmmptr[][] = 5
+
+    doAssert i == 5
+    doAssert y == z
+    doAssert z == hmmptr[]
+    doAssert 5 == y[] and 5 == z[] and 5 == hmmptr[][]
+
+  block:
+    var someint = 500
+
+    let p: ptr int = someint.addr
+    let tup = (f: p)
+    let tcopy = tup
+    var vtcopy = tcopy
+    p[] = 654
+    doAssert p[] == 654
+    doAssert tup.f[] == 654
+    doAssert tcopy.f[] == 654
+    doAssert vtcopy.f[] == 654
+
+  block:
+    var someint = 500
+
+    var p: ptr int = someint.addr
+    let arr = [p]
+    let arrc = arr
+    p[] = 256
+    doAssert someint == 256
+    doAssert p[] == 256
+    doAssert arr[0][] == 256
+    doAssert arrc[0][] == 256
+
+  block:
+    var someref: ref int
+    new(someref)
+    var someref2 = someref
+
+    var tup1 = (f: someref)
+    tup1.f = someref
+    let tup2 = tup1
+
+    someref[] = 543
+
+    proc passref(r: var ref int): var ref int = r
+    new(passref(someref))
+
+    doAssert someref[] == 0
+    doAssert tup1.f[] == 543
+    doAssert tup2.f[] == 543
+    doAssert someref2[] == 543
+
+  block:
+    type Whatever = object
+      i: ref int
+
+    var someref: ref int
+    new(someref)
+    someref[] = 10
+
+    let w = Whatever(i: someref)
+    var wcopy = w
+
+    someref[] = 20
+
+    doAssert w.i[] == 20
+    doAssert someref[] == 20
+    doAssert wcopy.i[] == 20
+    doAssert w.i == wcopy.i
+    #echo w.i[], " ", someref[], " ", wcopy.i[]
+
+  block:
+    var oneseq: ref seq[ref int]
+    new(oneseq)
+    var aref: ref int
+    new(aref)
+    aref[] = 123
+    let arefs = [aref]
+    oneseq[] &= arefs[0]
+    oneseq[] &= aref
+    aref[] = 222
+    new(aref)
+    doAssert oneseq[0] == oneseq[1]
+    doAssert oneseq[0][] == 222
+    doAssert oneseq[1][] == 222
+    doAssert aref[] == 0
+
+  block:
+    var seqs: ref seq[ref seq[ref int]]
+    new(seqs)
+    seqs[] = newSeq[ref seq[ref int]](1)
+    new(seqs[0])
+    seqs[0][] = newSeq[ref int](0)
+
+    var aref: ref int
+    new aref
+    aref[] = 654
+
+    let arefs = [aref]
+    doAssert arefs[0] == aref
+    seqs[0][] &= arefs[0]
+    seqs[0][] &= aref
+    seqs[0][1][] = 456
+    let seqs2 = seqs
+    let same = seqs2[0][0] == seqs2[0][1]
+    doAssert arefs[0] == aref
+    doAssert aref[] == 456
+    doAssert seqs[].len == 1
+    doAssert seqs[0][].len == 2
+    doAssert seqs[0][0][] == 456
+    doAssert seqs[0][1][] == 456
+    doAssert same
+
+  block:
+    type Obj = object
+      x, y: int
+
+    var objrefs: seq[ref Obj] = @[(ref Obj)(nil), nil, nil]
+    objrefs[2].new
+    objrefs[2][] = Obj(x: 123, y: 321)
+    objrefs[1] = objrefs[2]
+    doAssert objrefs[0] == nil
+    doAssert objrefs[1].y == 321
+    doAssert objrefs[2].y == 321
+    doAssert objrefs[1] == objrefs[2]
+
+  block:
+    var refs: seq[ref string] = @[(ref string)(nil), nil, nil]
+    refs[1].new
+    refs[1][] = "it's a ref!"
+    refs[0] = refs[1]
+    refs[2] = refs[1]
+    new(refs[0])
+    doAssert refs[0][] == ""
+    doAssert refs[1][] == "it's a ref!"
+    doAssert refs[2][] == "it's a ref!"
+    doAssert refs[1] == refs[2]
+
+  block:
+    var retaddr_calls = 0
+    proc retaddr(p: var int): var int =
+      retaddr_calls += 1
+      p
+
+    var tfoo_calls = 0
+    proc tfoo(x: var int) =
+      tfoo_calls += 1
+      x += 10
+      var y = x.addr
+      y[] += 20
+      retaddr(x) += 30
+      let z = retaddr(x).addr
+      z[] += 40
+
+    var ints = @[1, 2, 3]
+    tfoo(ints[1])
+    doAssert retaddr_calls == 2
+    doAssert tfoo_calls == 1
+    doAssert ints[1] == 102
+
+    var tbar_calls = 0
+    proc tbar(x: var int): var int =
+      tbar_calls += 1
+      x
+
+    tbar(ints[2]) += 10
+    tbar(ints[2]) *= 2
+    doAssert tbar_calls == 2
+
+    var tqux_calls = 0
+    proc tqux(x: var int): ptr int =
+      tqux_calls += 1
+      x.addr
+
+    discard tqux(ints[2]) == tqux(ints[2])
+    doAssert tqux_calls == 2
+    doAssert isNil(tqux(ints[2])) == false
+    doAssert tqux_calls == 3
+
+    var tseq_calls = 0
+    proc tseq(x: var seq[int]): var seq[int] =
+      tseq_calls += 1
+      x
+
+    tseq(ints) &= 999
+    doAssert tseq_calls == 1
+    doAssert ints == @[1, 102, 26, 999]
+
+    var rawints = @[555]
+    rawints &= 666
+    doAssert rawints == @[555, 666]
+
+    var resetints_calls = 0
+    proc resetInts(): int =
+      resetints_calls += 1
+      ints = @[0, 0, 0]
+      1
+
+    proc incr(x: var int; b: int): var int =
+      x = x + b
+      x
+
+    var q = 0
+    var qp = q.addr
+    qp[] += 123
+    doAssert q == 123
+    # check order of evaluation
+    doAssert (resetInts() + incr(q, tqux(ints[2])[])) == 124
+
+  block: # reset
+    var calls = 0
+    proc passsomething(x: var int): var int =
+      calls += 1
+      x
+
+    var
+      a = 123
+      b = 500
+      c = a.addr
+    reset(passsomething(a))
+    doAssert calls == 1
+    reset(b)
+    doAssert a == b
+    reset(c)
+    doAssert c == nil
+
+  block: # strings
+    var calls = 0
+    proc stringtest(s: var string): var string =
+      calls += 1
+      s
+
+    var somestr: string
+
+    stringtest(somestr) &= 'a'
+    stringtest(somestr) &= 'b'
+    doAssert calls == 2
+    doAssert somestr == "ab"
+    stringtest(somestr) &= "woot!"
+    doAssert somestr == "abwoot!"
+    doAssert calls == 3
+
+    doAssert stringtest(somestr).len == 7
+    doAssert calls == 4
+    doAssert high(stringtest(somestr)) == 6
+    doAssert calls == 5
+
+    var somestr2: string
+    stringtest(somestr2).setLen(stringtest(somestr).len)
+    doAssert calls == 7
+    doAssert somestr2.len == somestr.len
+
+    var somestr3: string
+    doAssert (somestr3 & "foo") == "foo"
+
+    block:
+      var a, b, c, d: string
+      d = a & b & c
+      doAssert d == ""
+      d = stringtest(a) & stringtest(b) & stringtest(c)
+      doAssert calls == 10
+      doAssert d == ""
+
+  block: # seqs
+    var calls = 0
+    proc seqtest(s: var seq[int]): var seq[int] =
+      calls += 1
+      s
+
+    var someseq: seq[int]
+
+    seqtest(someseq) &= 1
+    seqtest(someseq) &= 2
+    doAssert calls == 2
+    doAssert someseq == @[1, 2]
+    seqtest(someseq) &= @[3, 4, 5]
+    doAssert someseq == @[1, 2, 3, 4, 5]
+    doAssert calls == 3
+
+    doAssert seqtest(someseq).len == 5
+    doAssert calls == 4
+    doAssert high(seqtest(someseq)) == 4
+    doAssert calls == 5
+
+    # genArrayAddr
+    doAssert seqtest(someseq)[2] == 3
+    doAssert calls == 6
+
+    seqtest(someseq).setLen(seqtest(someseq).len)
+    doAssert calls == 8
+
+    var somenilseq: seq[int]
+    seqtest(somenilseq).setLen(3)
+    doAssert calls == 9
+    doAssert somenilseq[1] == 0
+
+    someseq = @[1, 2, 3]
+    doAssert (seqtest(someseq) & seqtest(someseq)) == @[1, 2, 3, 1, 2, 3]
+
+
+  block: # mInc, mDec
+    var calls = 0
+    proc someint(x: var int): var int =
+      calls += 1
+      x
+
+    var x = 10
+
+    inc(someint(x))
+    doAssert x == 11
+    doAssert calls == 1
+
+    dec(someint(x))
+    doAssert x == 10
+    doAssert calls == 2
+
+  block: # uints
+    var calls = 0
+    proc passuint(x: var uint32): var uint32 =
+      calls += 1
+      x
+
+    var u: uint32 = 5
+    passuint(u) += 1
+    doAssert u == 6
+    doAssert calls == 1
+
+    passuint(u) -= 1
+    doAssert u == 5
+    doAssert calls == 2
+
+    passuint(u) *= 2
+    doAssert u == 10
+    doAssert calls == 3
+
+  block: # objs
+    type Thing = ref object
+      x, y: int
+
+    var a, b: Thing
+    a = Thing()
+    b = a
+
+    doAssert a == b
+
+    var calls = 0
+    proc passobj(o: var Thing): var Thing =
+      calls += 1
+      o
+
+    passobj(b) = Thing(x: 123)
+    doAssert calls == 1
+    doAssert a != b
+    doAssert b.x == 123
+
+    var passobjptr_calls = 0
+    proc passobjptr(o: var Thing): ptr Thing =
+      passobjptr_calls += 1
+      o.addr
+
+    passobjptr(b)[] = Thing(x: 234)
+    doAssert passobjptr_calls == 1
+    doAssert a != b
+    doAssert b.x == 234
+    passobjptr(b)[].x = 500
+    doAssert b.x == 500
+
+    var pptr = passobjptr(b)
+    pptr.x += 100
+    doAssert b.x == 600
+
+    proc getuninitptr(): ptr int =
+      return
+
+    doAssert getuninitptr() == nil
+
+  block: # pointer casting
+    var obj = (x: 321, y: 543)
+    var x = 500
+
+    var objptr = obj.addr
+    var xptr = x.addr
+
+    var p1, p2: pointer
+    p1 = cast[pointer](objptr)
+    p2 = cast[pointer](xptr)
+    doAssert p1 != p2
+
+    p1 = cast[pointer](objptr)
+    p2 = cast[pointer](objptr)
+    doAssert p1 == p2
+
+    let objptr2 = cast[type(objptr)](p2)
+    doAssert objptr == objptr2
+
+    p1 = cast[pointer](xptr)
+    p2 = cast[pointer](xptr)
+    doAssert p1 == p2
+
+    let xptr2 = cast[type(xptr)](p2)
+    doAssert xptr == xptr2
+  
+  block: # var types
+    block t10202:
+      type Point = object
+        x: float
+        y: float
+
+      var points: seq[Point]
+
+      points.add(Point(x:1, y:2))
+
+      for i, p in points.mpairs:
+        p.x += 1
+
+      doAssert points[0].x == 2
+    
+    block:
+      var ints = @[1, 2, 3]
+      for i, val in mpairs ints:
+        val *= 10
+      doAssert ints == @[10, 20, 30]
+    
+    block:
+      var seqOfSeqs = @[@[1, 2], @[3, 4]]
+      for i, val in mpairs seqOfSeqs:
+        val[0] *= 10
+      doAssert seqOfSeqs == @[@[10, 2], @[30, 4]]
+
+  when false:
+    block: # openArray
+          # Error: internal error: genAddr: nkStmtListExpr
+      var calls = 0
+      proc getvarint(x: var openArray[int]): var int =
+        calls += 1
+        if true:
+          x[1]
+        else:
+          x[0]
+
+      var arr = [1, 2, 3]
+      getvarint(arr) += 5
+      doAssert calls == 1
+      doAssert arr[1] == 7
+
+proc tests_in_proc =
+  tests
+
+# since pointers are handled differently in global/local contexts
+# let's just run all of them twice
+tests_in_proc()
+tests
diff --git a/tests/js/tarrayboundscheck.nim b/tests/js/tarrayboundscheck.nim
new file mode 100644
index 000000000..d8bf8de97
--- /dev/null
+++ b/tests/js/tarrayboundscheck.nim
@@ -0,0 +1,50 @@
+discard """
+  output: '''idx out of bounds: -1
+month out of bounds: 0
+Jan
+Feb
+Mar
+Apr
+May
+Jun
+Jul
+Aug
+Sep
+Oct
+Nov
+Dec
+month out of bounds: 13
+idx out of bounds: 14
+'''
+"""
+
+{.push boundChecks:on.}
+
+# see issue #6532:
+# js backend 0.17.3: array bounds check for non zero based arrays is buggy
+
+proc test_arrayboundscheck() =
+  var months: array[1..12, string] =
+    ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
+     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+
+  var indices = [0,1,2,3,4,5,6,7,8,9,10,11,12,13]
+
+  for i in -1 .. 14:
+    try:
+      let idx = indices[i]
+      try:
+        echo months[idx]
+      except:
+        echo "month out of bounds: ", idx
+    except:
+      echo "idx out of bounds: ", i
+  
+  # #13966
+  var negativeIndexed: array[-2..2, int] = [0, 1, 2, 3, 4]
+  negativeIndexed[-1] = 2
+  negativeIndexed[1] = 2
+  doAssert negativeIndexed == [0, 2, 2, 2, 4]
+
+test_arrayboundscheck()
+{.pop.}
\ No newline at end of file
diff --git a/tests/js/tasyncjs.nim b/tests/js/tasyncjs.nim
new file mode 100644
index 000000000..f3b273c44
--- /dev/null
+++ b/tests/js/tasyncjs.nim
@@ -0,0 +1,107 @@
+discard """
+  output: '''
+x
+e
+done
+'''
+"""
+
+#[
+xxx move this to tests/stdlib/tasyncjs.nim
+]#
+
+import std/asyncjs
+
+block:
+  # demonstrate forward definition for js
+  proc y(e: int): Future[string] {.async.}
+
+  proc e: int {.discardable.} =
+    echo "e"
+    return 2
+
+  proc x(e: int): Future[void] {.async.} =
+    var s = await y(e)
+    if e > 2:
+      return
+    echo s
+    e()
+
+  proc y(e: int): Future[string] {.async.} =
+    if e > 0:
+      return await y(0)
+    else:
+      return "x"
+
+  discard x(2)
+
+import std/sugar
+from std/strutils import contains
+
+var witness: seq[string]
+
+proc fn(n: int): Future[int] {.async.} =
+  if n >= 7:
+    raise newException(ValueError, "foobar: " & $n)
+  if n > 0:
+    var ret = 1 + await fn(n-1)
+    witness.add $(n, ret)
+    return ret
+  else:
+    return 10
+
+proc asyncFact(n: int): Future[int] {.async.} =
+  if n > 0: result = n * await asyncFact(n-1)
+  else: result = 1
+
+proc asyncIdentity(n: int): Future[int] {.async.} =
+  if n > 0: result = 1 + await asyncIdentity(n-1)
+  else: result = 0
+
+proc main() {.async.} =
+  block: # then
+    let x = await fn(4)
+      .then((a: int) => a.float)
+      .then((a: float) => $a)
+    doAssert x == "14.0"
+    doAssert witness == @["(1, 11)", "(2, 12)", "(3, 13)", "(4, 14)"]
+
+    doAssert (await fn(2)) == 12
+
+    let x2 = await fn(4).then((a: int) => (discard)).then(() => 13)
+    doAssert x2 == 13
+
+    let x4 = await asyncFact(3).then(asyncIdentity).then(asyncIdentity).then((a:int) => a * 7).then(asyncIdentity)
+    doAssert x4 == 3 * 2 * 7
+
+    block: # bug #17177
+      proc asyncIdentityNested(n: int): Future[int] {.async.} = return n
+      let x5 = await asyncFact(3).then(asyncIdentityNested)
+      doAssert x5 == 3 * 2
+
+    when false: # xxx pending bug #17254
+      let x6 = await asyncFact(3).then((a:int) {.async.} => a * 11)
+      doAssert x6 == 3 * 2 * 11
+
+  block: # catch
+    var reason: Error
+    await fn(6).then((a: int) => (witness.add $a)).catch((r: Error) => (reason = r))
+    doAssert reason == nil
+
+    await fn(7).then((a: int) => (discard)).catch((r: Error) => (reason = r))
+    doAssert reason != nil
+    doAssert reason.name == "Error"
+    doAssert "foobar: 7" in $reason.message
+  echo "done" # justified here to make sure we're running this, since it's inside `async`
+
+block asyncPragmaInType:
+  type Handler = proc () {.async.}
+  proc foo() {.async.} = discard
+  var x: Handler = foo
+
+block: # 13341
+  proc f {.async.} =
+    proc g: int =
+      result = 123
+
+discard main()
diff --git a/tests/js/tasyncjs_bad.nim b/tests/js/tasyncjs_bad.nim
new file mode 100644
index 000000000..b1e5a7bc3
--- /dev/null
+++ b/tests/js/tasyncjs_bad.nim
@@ -0,0 +1,22 @@
+discard """
+  exitCode: 1
+ outputsub: "Error: unhandled exception: foobar: 13"
+"""
+
+# note: this needs `--unhandled-rejections=strict`, see D20210217T215950
+
+import std/asyncjs
+from std/sugar import `=>`
+
+proc fn(n: int): Future[int] {.async.} =
+  if n >= 7: raise newException(ValueError, "foobar: " & $n)
+  else: result = n
+
+proc main() {.async.} =
+  let x1 = await fn(6)
+  doAssert x1 == 6
+  await fn(7).catch((a: Error) => (discard))
+  let x3 = await fn(13)
+  doAssert false # shouldn't go here, should fail before
+
+discard main()
diff --git a/tests/js/tasyncjs_pragma.nim b/tests/js/tasyncjs_pragma.nim
new file mode 100644
index 000000000..2b6f32e92
--- /dev/null
+++ b/tests/js/tasyncjs_pragma.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''
+0
+t
+'''
+"""
+
+# xxx merge into tasyncjs.nim
+
+import asyncjs, macros
+
+macro f*(a: untyped): untyped =
+  assert a.kind == nnkProcDef
+  result = nnkProcDef.newTree(a.name, a[1], a[2], a.params, a.pragma, a[5], nnkStmtList.newTree())
+  let call = quote:
+    echo 0
+  result.body.add(call)
+  for child in a.body:
+    result.body.add(child)
+  #echo result.body.repr
+
+proc t* {.async, f.} =
+  echo "t"
+
+proc t0* {.async.} =
+  await t()
+
+discard t0()
+
diff --git a/tests/js/tbasics.nim b/tests/js/tbasics.nim
new file mode 100644
index 000000000..ef84f8bb5
--- /dev/null
+++ b/tests/js/tbasics.nim
@@ -0,0 +1,62 @@
+discard """
+  output: '''ABCDC
+1
+14
+ok
+1'''
+"""
+
+type
+  MyEnum = enum
+    A,B,C,D
+# trick the optimizer with an seq:
+var x = @[A,B,C,D]
+echo x[0],x[1],x[2],x[3],MyEnum(2)
+
+# bug #10651
+
+var xa: seq[int]
+var ya = @[1,2]
+xa &= ya
+echo xa[0]
+
+proc test =
+  var yup: seq[int]
+  try:
+    yup.add 14
+    echo yup.pop
+  finally:
+    discard
+
+test()
+
+when true:
+  var a: seq[int]
+
+  a.setLen(0)
+
+  echo "ok"
+
+# bug #10697
+proc test2 =
+  var val = uint16(0)
+  var i = 0
+  if i < 2:
+    val += uint16(1)
+  echo int(val)
+
+test2()
+
+
+var someGlobal = default(array[5, int])
+for x in someGlobal: doAssert(x == 0)
+
+proc tdefault =
+  var x = default(int)
+  doAssert(x == 0)
+  proc inner(v: openArray[string]) =
+    doAssert(v.len == 0)
+
+  inner(default(seq[string]))
+
+tdefault()
diff --git a/tests/js/tbigint_backend.nim b/tests/js/tbigint_backend.nim
new file mode 100644
index 000000000..8f2f6c4f4
--- /dev/null
+++ b/tests/js/tbigint_backend.nim
@@ -0,0 +1,57 @@
+import std/private/jsutils
+
+
+type JsBigIntImpl {.importc: "bigint".} = int
+type JsBigInt = distinct JsBigIntImpl
+
+doAssert JsBigInt isnot int
+func big*(integer: SomeInteger): JsBigInt {.importjs: "BigInt(#)".}
+func big*(integer: cstring): JsBigInt {.importjs: "BigInt(#)".}
+func `<=`*(x, y: JsBigInt): bool {.importjs: "(# $1 #)".}
+func `==`*(x, y: JsBigInt): bool {.importjs: "(# === #)".}
+func inc*(x: var JsBigInt) {.importjs: "[#][0][0]++".}
+func inc2*(x: var JsBigInt) {.importjs: "#++".}
+func toCstring*(this: JsBigInt): cstring {.importjs: "#.toString()".}
+func `$`*(this: JsBigInt): string =
+  $toCstring(this)
+
+block:
+  doAssert defined(nimHasJsBigIntBackend)
+  let z1 = big"10"
+  let z2 = big"15"
+  doAssert z1 == big"10"
+  doAssert z1 == z1
+  doAssert z1 != z2
+  var s: seq[cstring]
+  for i in z1 .. z2:
+    s.add $i
+  doAssert s == @["10".cstring, "11", "12", "13", "14", "15"]
+  block:
+    var a=big"3"
+    a.inc
+    doAssert a == big"4"
+  block:
+    var z: JsBigInt
+    doAssert $z == "0"
+    doAssert z.jsTypeOf == "bigint" # would fail without codegen change
+    doAssert z != big(1)
+    doAssert z == big"0" # ditto
+
+  # ditto below
+  block:
+    let z: JsBigInt = big"1"
+    doAssert $z == "1"
+    doAssert z.jsTypeOf == "bigint"
+    doAssert z == big"1"
+
+  block:
+    let z = JsBigInt.default
+    doAssert $z == "0"
+    doAssert z.jsTypeOf == "bigint"
+    doAssert z == big"0"
+
+  block:
+    var a: seq[JsBigInt]
+    a.setLen 3
+    doAssert a[^1].jsTypeOf == "bigint"
+    doAssert a[^1] == big"0"
diff --git a/tests/js/tbyvar.nim b/tests/js/tbyvar.nim
new file mode 100644
index 000000000..93724a2f1
--- /dev/null
+++ b/tests/js/tbyvar.nim
@@ -0,0 +1,123 @@
+discard """
+  output: '''
+foo 12
+bar 12
+2
+foo 12
+bar 12
+2
+12.5
+(nums: @[5.0, 5.0, 10.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+(nums: @[5.0, 5.0, 50.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+(nums: @[5.0, 5.0, 45.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+(nums: @[5.0, 5.0, 9.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0, 5.0])
+asd
+'''
+"""
+
+# bug #1489
+proc foo(x: int) = echo "foo ", x
+proc bar(y: var int) = echo "bar ", y
+
+var x = 12
+foo(x)
+bar(x)
+
+# bug #1490
+var y = 1
+y *= 2
+echo y
+
+proc main =
+  var x = 12
+  foo(x)
+  bar(x)
+
+  var y = 1
+  y *= 2
+  echo y
+
+main()
+
+# Test: pass var seq to var openArray
+var s = @[2, 1]
+proc foo(a: var openArray[int]) = a[0] = 123
+
+proc bar(s: var seq[int], a: int) =
+  doAssert(a == 5)
+  foo(s)
+s.bar(5)
+doAssert(s == @[123, 1])
+
+import tables
+block: # Test get addr of byvar return value
+  var t = initTable[string, int]()
+  t["hi"] = 5
+  let a = addr t["hi"]
+  a[] = 10
+  doAssert(t["hi"] == 10)
+
+block: # Test var arg inside case expression. #5244
+  proc foo(a: var string) =
+    a = case a
+    of "a": "error"
+    of "b": "error"
+    else: a
+  var a = "ok"
+  foo(a)
+  doAssert(a == "ok")
+
+
+proc mainowar =
+  var x = 9.0
+  x += 3.5
+  echo x
+
+mainowar()
+
+
+# bug #5608
+
+type Foo = object
+    nums : seq[float]
+
+proc newFoo(len : int, default = 0.0) : Foo =
+    result = Foo()
+    result.nums = newSeq[float](len)
+    for i in 0..(len - 1):
+        result.nums[i] = default
+
+proc `[]=`(f : var Foo, i : int, v : float) =
+    f.nums[i] = v
+
+proc `[]`(f : Foo, i : int) : float = f.nums[i]
+
+proc `[]`(f : var Foo, i : int) : var float = f.nums[i]
+
+var f = newFoo(10,5)
+
+f[2] += 5
+echo f
+f[2] *= 5
+echo f
+f[2] -= 5
+echo f
+f[2] /= 5
+echo f
+
+# regression for #5608
+import tables
+
+type
+  SomeObj = ref object
+    s: cstring
+
+var a = initTable[cstring, Table[cstring, SomeObj]]()
+
+var b = initTable[cstring, SomeObj]()
+
+b.add(cstring"b", SomeObj(s: cstring"asd"))
+
+a.add(cstring"a", b)
+
+echo a[cstring"a"][cstring"b"].s
diff --git a/tests/js/tclosures.nim b/tests/js/tclosures.nim
new file mode 100644
index 000000000..4f1c28de3
--- /dev/null
+++ b/tests/js/tclosures.nim
@@ -0,0 +1,95 @@
+discard """
+  action: run
+"""
+
+import random, strutils
+const consolePrefix = "jsCallbacks"
+
+asm """
+    var callback = []
+    function regCallback (fn) { callback.push (fn); }
+    function runCallbacks () {
+        var result = "\n"
+        var n = 0
+        for (var fn in callback) {
+            n += 1
+            result += "("+String (n)+")"
+            result += callback [fn] ()
+            result += "\n"
+        }
+        return result
+    }
+    function print (text) { console.log (text); }
+"""
+
+proc consoleprint (str:cstring): void {.importc: "print", nodecl.}
+proc print* (a: varargs[string, `$`]) = consoleprint "$1: $2" % [consolePrefix, join(a, " ")]
+
+type CallbackProc {.importc.} = proc () : cstring
+
+proc regCallback (fn:CallbackProc) {.importc.}
+proc runCallbacks ():cstring {.importc.}
+
+proc `*` (s:string, n:Natural) : string = s.repeat(n)
+
+proc outer (i:Natural) : (string, int) =
+    let c = $char(rand(93) + 33)
+    let n = rand(40)
+    let s = c * n
+    proc inner(): cstring = ("[$1]" % $n) & s & " <--"
+    regCallback(inner)
+    return (s, n)
+
+var expected = "\n"
+for i in 1 .. 10:
+    let (s, n) = outer(i)
+    expected &= ("($1)[$2]" % [$i, $n]) & s & " <--"
+    expected &= "\n"
+
+let results = runCallbacks()
+
+doAssert(expected == $results)
+
+block issue7048:
+  block:
+    proc foo(x: seq[int]): auto =
+      proc bar: int = x[1]
+      bar
+
+    var stuff = @[1, 2]
+    let f = foo(stuff)
+    stuff[1] = 321
+    doAssert f() == 2
+
+  block:
+    proc foo(x: tuple[things: string]; y: array[3, int]): auto =
+      proc very: auto = 
+        proc deeply: auto =
+          proc nested: (char, int) = (x.things[0], y[1])
+          nested
+        deeply
+      very()
+
+    var
+      stuff = (things: "NIM")
+      stuff2 = [32, 64, 96]
+    let f = foo(stuff, stuff2)
+    stuff.things = "VIM"
+    stuff2[1] *= 10
+    doAssert f()() == ('N', 64)
+    doAssert (stuff.things[0], stuff2[1]) == ('V', 640)
+
+  block:
+    proc foo(x: ptr string): auto =
+      proc bar(): int = len(x[])
+      bar
+    
+    var 
+      s1 = "xyz"
+      s2 = "stuff"
+      p = addr s1
+    
+    let f = foo(p)
+    p = addr s2
+    doAssert len(p[]) == 5
+    doAssert f() == 3
diff --git a/tests/js/tcodegendeclproc.nim b/tests/js/tcodegendeclproc.nim
new file mode 100644
index 000000000..33064bdf1
--- /dev/null
+++ b/tests/js/tcodegendeclproc.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''
+-1
+8
+'''
+  ccodecheck: "'console.log(-1); function fac__tcodegendeclproc_u1(n_p0)'"
+"""
+proc fac(n: int): int {.codegenDecl: "console.log(-1); function $2($3)".} =
+  return n
+
+echo fac(8)
diff --git a/tests/js/tcodegendeclvar.nim b/tests/js/tcodegendeclvar.nim
new file mode 100644
index 000000000..645443ef7
--- /dev/null
+++ b/tests/js/tcodegendeclvar.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''
+-1
+2
+'''
+  ccodecheck: "'console.log(-1); var v_' \\d+ ' = [2]'"
+"""
+
+var v {.codegenDecl: "console.log(-1); var $2".} = 2
+echo v
diff --git a/tests/js/tconsole.nim b/tests/js/tconsole.nim
new file mode 100644
index 000000000..88c71ea18
--- /dev/null
+++ b/tests/js/tconsole.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''
+Hello, console
+1 2 3
+'''
+"""
+
+# This file tests the JavaScript console
+
+import jsconsole
+
+console.log("Hello, console")
+console.log(1, 2, 3)
diff --git a/tests/js/tcopying.nim b/tests/js/tcopying.nim
new file mode 100644
index 000000000..306d25090
--- /dev/null
+++ b/tests/js/tcopying.nim
@@ -0,0 +1,80 @@
+discard """
+  output: '''123
+2 9
+2 9
+1 124
+true false
+100 300 100
+1
+1
+'''
+"""
+
+type MyArray = array[1, int]
+
+proc changeArray(a: var MyArray) =
+    a = [123]
+
+var a: MyArray
+changeArray(a)
+echo a[0]
+
+# bug #4703
+# Test 1
+block:
+    let ary1 = [1, 2, 3]
+    var ary2 = ary1
+
+    ary2[1] = 9
+
+    echo ary1[1], " ", ary2[1]
+
+# Test 2
+block:
+    type TestObj = ref object of RootObj
+        ary2: array[3, int]
+
+    let ary1 = [1, 2, 3]
+    var obj = TestObj(ary2: ary1)
+
+    obj.ary2[1] = 9
+
+    echo ary1[1], " ", obj.ary2[1]
+
+block:
+    type TestObj = object
+        x, y: int
+
+    let obj = TestObj(x: 1, y: 2)
+    var s = @[obj]
+    s[0].x += 123
+    echo obj.x, " ", s[0].x
+
+block:
+    var nums = {1, 2, 3, 4}
+    let obj = (n: nums)
+    nums.incl 5
+    echo (5 in nums), " ", (5 in obj.n)
+
+block:
+    let tup1 = (a: 100)
+    var tup2 = (t: (t2: tup1))
+    var tup3 = tup1
+    tup2.t.t2.a = 300
+    echo tup1.a, " ", tup2.t.t2.a, " ", tup3.a
+
+block:
+    proc foo(arr: array[2, int]) =
+        var s = @arr
+        s[0] = 500
+
+    var nums = [1, 2]
+    foo(nums)
+    echo nums[0]
+
+proc bug9674 =
+  var b = @[1,2,3]
+  var a = move(b)
+  echo a[0]
+
+bug9674()
diff --git a/tests/js/tcsymbol.nim b/tests/js/tcsymbol.nim
new file mode 100644
index 000000000..07e52b9b6
--- /dev/null
+++ b/tests/js/tcsymbol.nim
@@ -0,0 +1,6 @@
+discard """
+  matrix: "--cc:gcc; --cc:tcc"
+"""
+
+doAssert not defined(gcc)
+doAssert not defined(tcc)
\ No newline at end of file
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/tderef.nim b/tests/js/tderef.nim
new file mode 100644
index 000000000..ddb91bd42
--- /dev/null
+++ b/tests/js/tderef.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''true
+'''
+"""
+
+import tables
+
+type EventStore = Table[string, seq[proc ()]]
+
+proc newEventStore(): EventStore =
+  initTable[string, seq[proc ()]]()
+
+proc register(store: var EventStore, name: string, callback: proc ()) =
+  if not store.hasKey(name):
+    store[name] = @[]
+  store[name].add(callback)
+
+var store = newEventStore()
+store.register("test", proc () = echo "true")
+store["test"][0]()
diff --git a/tests/js/tdiscard.nim b/tests/js/tdiscard.nim
new file mode 100644
index 000000000..9aa6ea1b1
--- /dev/null
+++ b/tests/js/tdiscard.nim
@@ -0,0 +1,3 @@
+import dom
+
+discard Node()
\ No newline at end of file
diff --git a/tests/js/tdollar_float.nim b/tests/js/tdollar_float.nim
new file mode 100644
index 000000000..4fd8e3cba
--- /dev/null
+++ b/tests/js/tdollar_float.nim
@@ -0,0 +1,62 @@
+#[
+merge into tests/system/tdollars.nim once https://github.com/nim-lang/Nim/pull/14122
+is merged
+]#
+
+import unittest
+
+block: # https://github.com/timotheecour/Nim/issues/133
+  # simple test
+  var a: float = 2
+  check $a == "2.0"
+
+  # systematic tests
+  template fun(a2: static float) =
+    const a: float = a2 # needed pending https://github.com/timotheecour/Nim/issues/132
+    var b = a
+    check $b == $a
+
+  fun 2
+  fun 2.0
+  fun 2.1
+  fun 1_000
+  fun 1_000.1
+  fun 1_000_000_000.1
+  fun 1_000_000_000_000.1
+
+  # negatives
+  fun -2.0
+  fun -2.1
+
+  # 0
+  fun 0
+  fun -0
+  fun 0.0
+
+  block:
+    var a = -0.0
+    check $a in ["-0.0", "0.0"]
+
+  # exponents
+  block:
+    var a = 5e20
+    check $a in ["5e20", "500000000000000000000.0"]
+
+  fun 3.4e1'f32
+  fun 3.4e-1'f32
+  fun -3.4e-1'f32
+  fun 3.4e-1'f32
+  fun 3e-1'f32
+
+  block:
+    var a = 3.4e38'f32
+    check $a in ["3.4e+38", "3.4e+038"]
+      # on windows, printf (used in VM) prints as 3.4e+038
+      # but js prints as 3.4e+38
+      # on osx, both print as 3.4e+38
+      # see https://github.com/timotheecour/Nim/issues/138
+
+  when false: # edge cases
+    fun -0.0 # see https://github.com/timotheecour/Nim/issues/136
+    fun 5e20
+    fun 3.4e38'f32
diff --git a/tests/js/temptyseq.nim b/tests/js/temptyseq.nim
new file mode 100644
index 000000000..6489cf817
--- /dev/null
+++ b/tests/js/temptyseq.nim
@@ -0,0 +1,8 @@
+# #12671
+
+proc foo =
+  var x: seq[int]
+  doAssertRaises(IndexDefect):
+    inc x[0]
+
+foo()
diff --git a/tests/js/tenumhole.nim b/tests/js/tenumhole.nim
new file mode 100644
index 000000000..71a493e8c
--- /dev/null
+++ b/tests/js/tenumhole.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "first0second32third64"
+"""
+
+type Holed = enum
+  hFirst = (0,"first")
+  hSecond = (32,"second")
+  hThird = (64,"third")
+  
+var x = @[0,32,64] # This is just to avoid the compiler inlining the value of the enum
+
+echo Holed(x[0]),ord Holed(x[0]),Holed(x[1]),ord Holed(x[1]),Holed(x[2]),ord Holed(x[2])
diff --git a/tests/js/tenumnegkey.nim b/tests/js/tenumnegkey.nim
new file mode 100644
index 000000000..f96c554d4
--- /dev/null
+++ b/tests/js/tenumnegkey.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "first-12second32third64"
+"""
+
+type Holed = enum
+  hFirst = (-12,"first")
+  hSecond = (32,"second")
+  hThird = (64,"third")
+  
+var x = @[-12,32,64] # This is just to avoid the compiler inlining the value of the enum
+
+echo Holed(x[0]),ord Holed(x[0]),Holed(x[1]),ord Holed(x[1]),Holed(x[2]),ord Holed(x[2])
diff --git a/tests/js/tenumoffset.nim b/tests/js/tenumoffset.nim
new file mode 100644
index 000000000..5bdc4c105
--- /dev/null
+++ b/tests/js/tenumoffset.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "my value A1my value Bconc2valueCabc4abc"
+"""
+
+const
+  strValB = "my value B"
+
+type
+  TMyEnum = enum
+    valueA = (1, "my value A"),
+    valueB = strValB & "conc",
+    valueC,
+    valueD = (4, "abc")
+
+proc getValue(i:int): TMyEnum = TMyEnum(i)
+
+# trick the optimizer with a variable:
+var x = getValue(4)
+echo getValue(1), ord(valueA), getValue(2), ord(valueB), getValue(3), getValue(4), ord(valueD), x
diff --git a/tests/js/test1.nim b/tests/js/test1.nim
new file mode 100644
index 000000000..7ad3f85f6
--- /dev/null
+++ b/tests/js/test1.nim
@@ -0,0 +1,52 @@
+discard """
+  output: "1261129"
+"""
+
+# This file tests the JavaScript generator
+
+import strutils
+
+var
+  inputElement = "1123"
+
+proc onButtonClick(inputElement: string) {.exportc.} =
+  let v = $inputElement
+  if v.allCharsInSet(WhiteSpace):
+    echo "only whitespace, hu?"
+  else:
+    var x = parseInt(v)
+    echo x*x
+
+onButtonClick(inputElement)
+
+block:
+  var s: string
+  s.add("hi")
+  doAssert(s == "hi")
+
+block:
+  var s: string
+  s.insert("hi", 0)
+  doAssert(s == "hi")
+
+block:
+  var s: string
+  s.setLen(2)
+  s[0] = 'h'
+  s[1] = 'i'
+  doAssert(s == "hi")
+
+block:
+  var s: seq[int]
+  s.setLen(2)
+  doAssert(s == @[0, 0])
+
+block:
+  var s: seq[int]
+  s.insert(2, 0)
+  doAssert(s == @[2])
+
+block:
+  var s: seq[int]
+  s.add(2)
+  doAssert(s == @[2])
diff --git a/tests/js/test2.nim b/tests/js/test2.nim
new file mode 100644
index 000000000..fa857ccc5
--- /dev/null
+++ b/tests/js/test2.nim
@@ -0,0 +1,58 @@
+discard """
+  output: '''foo
+js 3.14
+7
+1
+-21550
+-21550'''
+"""
+
+# This file tests the JavaScript generator
+
+doAssert getCurrentException() == nil
+doAssert getCurrentExceptionMsg() == ""
+
+#  #335
+proc foo() =
+  var bar = "foo"
+  proc baz() =
+    echo bar
+  baz()
+foo()
+
+# #376
+when not defined(js):
+  proc foo(val: float): string = "no js " & $val
+else:
+  proc foo(val: float): string = "js " & $val
+
+echo foo(3.14)
+
+# #2495
+type C = concept x
+
+proc test(x: C, T: typedesc): T =
+  cast[T](x)
+
+echo 7.test(int8)
+
+# #4222
+const someConst = [ "1"]
+
+proc procThatRefersToConst() # Forward decl
+procThatRefersToConst() # Call bar before it is defined
+
+proc procThatRefersToConst() =
+  var i = 0 # Use a var index, otherwise nim will constfold foo[0]
+  echo someConst[i] # JS exception here: foo is still not initialized (undefined)
+
+# bug #6753
+let x = -1861876800
+const y = 86400
+echo (x - (y - 1)) div y # Now gives `-21550`
+
+proc foo09() =
+    let x = -1861876800
+    const y = 86400
+    echo (x - (y - 1)) div y # Still gives `-21551`
+foo09()
diff --git a/tests/js/testmagic.nim b/tests/js/testmagic.nim
new file mode 100644
index 000000000..8e06f1a9b
--- /dev/null
+++ b/tests/js/testmagic.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''true
+123
+'''
+"""
+
+# This file tests some magic
+
+var foo = cstring("foo")
+var bar = cstring("foo")
+echo(foo == bar)
+echo "01234"[1 .. ^2]
diff --git a/tests/js/testobjs.nim b/tests/js/testobjs.nim
new file mode 100644
index 000000000..b61d06471
--- /dev/null
+++ b/tests/js/testobjs.nim
@@ -0,0 +1,73 @@
+discard """
+  output: '''{"columns":[{"t":null},{"t":null}]}
+{"columns":[{"t":null},{"t":null}]}
+'''
+"""
+
+## Tests javascript object generation
+
+type
+  Kg = distinct float
+  Price = int
+  Item = object of RootObj
+    weight: Kg
+    price: Price
+    desc: cstring
+  Person = object of RootObj
+    name: cstring
+    age: int
+    item: Item
+  Test = object
+    name: cstring
+  Recurse[T] = object
+    data: T
+    next: ref Recurse[T]
+
+var
+  test = Test(name: "Jorden")
+  sword = Item(desc: "pointy", weight: Kg(10.0),
+                price: Price(50))
+  knight = Person(name: "robert", age: 19, item: sword)
+  recurse4 = (ref Recurse[int])(data: 4, next: nil)
+  recurse3 = (ref Recurse[int])(data: 3, next: recurse4)
+  recurse2 = (ref Recurse[int])(data: 2, next: recurse3)
+  recurse1 = Recurse[int](data: 1, next: recurse2)
+
+
+doAssert test.name == cstring"Jorden"
+doAssert knight.age == 19
+doAssert knight.item.price == 50
+doAssert recurse1.next.next.data == 3
+
+# bug #6035
+proc toJson*[T](data: T): cstring {.importc: "JSON.stringify".}
+
+type
+  Column = object
+    t: ref Column
+
+  Test2 = object
+    columns: seq[Column]
+
+var test1 = Test2(columns: @[Column(t: nil), Column(t: nil)])
+let test2 = test1
+
+echo toJSON(test1)
+echo toJSON(test2)
+
+block issue10005:
+  type
+    Player = ref object of RootObj
+      id*: string
+      nickname*: string
+      color*: string
+
+  proc newPlayer(nickname: string, color: string): Player =
+    let pl = Player(color: "#123", nickname: nickname)
+    return Player(
+        id: "foo",
+        nickname: nickname,
+        color: color,
+    )
+
+  doAssert newPlayer("foo", "#1232").nickname == "foo"
diff --git a/tests/js/testtojsstr.nim b/tests/js/testtojsstr.nim
new file mode 100644
index 000000000..03ac89e20
--- /dev/null
+++ b/tests/js/testtojsstr.nim
@@ -0,0 +1,8 @@
+discard """
+  output = "И\n"
+"""
+
+let s: string = "И\n"
+let cs = s.cstring
+
+echo $s
diff --git a/tests/js/tfieldchecks.nim b/tests/js/tfieldchecks.nim
new file mode 100644
index 000000000..a0679a349
--- /dev/null
+++ b/tests/js/tfieldchecks.nim
@@ -0,0 +1,48 @@
+discard """
+  output: '''
+foo
+C
+3.14
+foo
+3.14
+3.14
+'''
+"""
+
+type
+  V = enum
+    A, B, C
+  X = object
+    f0: string
+    case f1: V
+    of A: f2: string
+    of B: discard
+    of C: f3: float
+
+var obj = X(f0: "foo", f1: C, f3: 3.14)
+
+block:
+  echo obj.f0
+  echo obj.f1
+  doAssertRaises(FieldDefect): echo obj.f2
+  echo obj.f3
+
+block:
+  let a0 = addr(obj.f0)
+  echo a0[]
+  # let a1 = addr(obj.f1)
+  # echo a1[]
+  doAssertRaises(FieldDefect):
+    let a2 = addr(obj.f2)
+    echo a2[]
+  let a3 = addr(obj.f3)
+  echo a3[]
+
+# Prevent double evaluation of LHS
+block:
+  var flag = false
+  proc wrap(x: X): X =
+    doAssert flag == false
+    flag = true
+    result = x
+  echo wrap(obj).f3
diff --git a/tests/js/tfloatround.nim b/tests/js/tfloatround.nim
new file mode 100644
index 000000000..7bc5430e6
--- /dev/null
+++ b/tests/js/tfloatround.nim
@@ -0,0 +1,7 @@
+discard """
+  output: '''
+3
+'''
+"""
+
+echo int(22 / 7)
diff --git a/tests/js/tglobal.nim b/tests/js/tglobal.nim
new file mode 100644
index 000000000..38f5eec34
--- /dev/null
+++ b/tests/js/tglobal.nim
@@ -0,0 +1,30 @@
+block global:
+  proc getState(): int =
+    var state0 {.global.}: int
+    inc state0
+    result = state0
+
+  for i in 0 ..< 3:
+    doAssert getState() == i + 1
+
+  for i in 0 ..< 3:
+    once:
+      doAssert i == 0
+
+
+block threadvar:
+  proc getThreadState0(): int =
+    var state0 {.threadvar.}: int
+    inc state0
+    result = state0
+
+  for i in 0 ..< 3:
+    doAssert getThreadState0() == i + 1
+
+  proc getThreadState1(): int =
+    var state1 {.threadvar.}: int
+    inc state1
+    result = state1
+
+  for i in 0 ..< 3:
+    doAssert getThreadState1() == i + 1
diff --git a/tests/js/timplicit_nodecl.nim b/tests/js/timplicit_nodecl.nim
new file mode 100644
index 000000000..79a921815
--- /dev/null
+++ b/tests/js/timplicit_nodecl.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''22
+22'''
+"""
+
+# test implicit nodecl
+block:
+  {. emit: "var importMe = 22;" .}
+  var
+    a {. importc: "importMe" .}: int
+    importMe {. importc .}: int
+  echo a
+  echo importMe
diff --git a/tests/js/tindexdefect.nim b/tests/js/tindexdefect.nim
new file mode 100644
index 000000000..37994ec2e
--- /dev/null
+++ b/tests/js/tindexdefect.nim
@@ -0,0 +1,9 @@
+discard """
+  outputsub: "unhandled exception: index 10000 not in 0 .. 0 [IndexDefect]"
+  exitcode: 1
+  joinable: false
+"""
+
+var s = ['a']
+let z = s[10000] == 'a'
+echo z
\ No newline at end of file
diff --git a/tests/js/tjsffi.nim b/tests/js/tjsffi.nim
new file mode 100644
index 000000000..f27ea5546
--- /dev/null
+++ b/tests/js/tjsffi.nim
@@ -0,0 +1,274 @@
+discard """
+matrix: "--legacy:jsnolambdalifting;"
+output: '''
+3
+2
+12
+Event { name: 'click: test' }
+Event { name: 'reloaded: test' }
+Event { name: 'updates: test' }
+'''
+"""
+
+import jsffi, jsconsole
+
+# Tests for JsObject
+block: # Test JsObject []= and []
+  let obj = newJsObject()
+  obj["a"] = 11
+  obj["b"] = "test"
+  obj["c"] = "test".cstring
+  doAssert obj["a"].to(int) == 11
+  doAssert obj["c"].to(cstring) == "test".cstring
+
+block: # Test JsObject .= and .
+  let obj = newJsObject()
+  obj.a = 11
+  obj.b = "test"
+  obj.c = "test".cstring
+  obj.`$!&` = 42
+  obj.`while` = 99
+  doAssert obj.a.to(int) == 11
+  doAssert obj.b.to(string) == "test"
+  doAssert obj.c.to(cstring) == "test".cstring
+  doAssert obj.`$!&`.to(int) == 42
+  doAssert obj.`while`.to(int) == 99
+
+block: # Test JsObject .()
+  let obj = newJsObject()
+  obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
+  doAssert obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6"
+
+block: # Test JsObject []()
+  let obj = newJsObject()
+  obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z)
+  let call = obj["a"].to(proc(x, y, z: int, t: string): string)
+  doAssert call(1, 2, 3, "Result is: ") == "Result is: 6"
+
+# Test JsObject Iterators
+block: # testPairs
+  let obj = newJsObject()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for k, v in obj.pairs:
+    case $k
+    of "a":
+      doAssert v.to(int) == 10
+    of "b":
+      doAssert v.to(int) == 20
+    of "c":
+      doAssert v.to(int) == 30
+    else:
+      doAssert false
+block: # testItems
+  let obj = newJsObject()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.items:
+    doAssert v.to(int) in [10, 20, 30]
+block: # testKeys
+  let obj = newJsObject()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.keys:
+    doAssert $v in ["a", "b", "c"]
+
+block: # Test JsObject equality
+  {. emit: "var comparison = {a: 22, b: 'test'};" .}
+  var comparison {. importjs, nodecl .}: JsObject
+  let obj = newJsObject()
+  obj.a = 22
+  obj.b = "test".cstring
+  doAssert obj.a == comparison.a and obj.b == comparison.b
+
+block: # Test JsObject literal
+  {. emit: "var comparison = {a: 22, b: 'test'};" .}
+  var comparison {. importjs, nodecl .}: JsObject
+  let obj = JsObject{ a: 22, b: "test".cstring }
+  doAssert obj.a == comparison.a and obj.b == comparison.b
+
+# Tests for JsAssoc
+block: # Test JsAssoc []= and []
+  let obj = newJsAssoc[int, int]()
+  obj[1] = 11
+  doAssert not compiles(obj["a"] = 11)
+  doAssert not compiles(obj["a"])
+  doAssert not compiles(obj[2] = "test")
+  doAssert not compiles(obj[3] = "test".cstring)
+  doAssert obj[1] == 11
+
+block: # Test JsAssoc .= and .
+  let obj = newJsAssoc[cstring, int]()
+  var working = true
+  obj.a = 11
+  obj.`$!&` = 42
+  doAssert not compiles(obj.b = "test")
+  doAssert not compiles(obj.c = "test".cstring)
+  doAssert obj.a == 11
+  doAssert obj.`$!&` == 42
+
+block: # Test JsAssoc .()
+  let obj = newJsAssoc[cstring, proc(e: int): int]()
+  obj.a = proc(e: int): int = e * e
+  doAssert obj.a(10) == 100
+
+block: # Test JsAssoc []()
+  let obj = newJsAssoc[cstring, proc(e: int): int]()
+  obj.a = proc(e: int): int = e * e
+  let call = obj["a"]
+  doAssert call(10) == 100
+
+# Test JsAssoc Iterators
+block: # testPairs
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for k, v in obj.pairs:
+    case $k
+    of "a":
+      doAssert v == 10
+    of "b":
+      doAssert v == 20
+    of "c":
+      doAssert v == 30
+    else:
+      doAssert false
+block: # testItems
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.items:
+    doAssert v in [10, 20, 30]
+block: # testKeys
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 10
+  obj.b = 20
+  obj.c = 30
+  for v in obj.keys:
+    doAssert v in [cstring"a", cstring"b", cstring"c"]
+
+block: # Test JsAssoc equality
+  {. emit: "var comparison = {a: 22, b: 55};" .}
+  var comparison {. importjs, nodecl .}: JsAssoc[cstring, int]
+  let obj = newJsAssoc[cstring, int]()
+  obj.a = 22
+  obj.b = 55
+  doAssert obj.a == comparison.a and obj.b == comparison.b
+
+block: # Test JsAssoc literal
+  {. emit: "var comparison = {a: 22, b: 55};" .}
+  var comparison {. importjs, nodecl .}: JsAssoc[cstring, int]
+  let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
+  doAssert compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
+  doAssert comparison.a == obj.a and comparison.b == obj.b
+  doAssert not compiles(JsAssoc[cstring, int]{ a: "test" })
+
+# Tests for macros on non-JsRoot objects
+block: # Test lit
+  type TestObject = object
+    a: int
+    b: cstring
+  {. emit: "var comparison = {a: 1};" .}
+  var comparison {. importjs, nodecl .}: TestObject
+  let obj = TestObject{ a: 1 }
+  doAssert obj == comparison
+
+block: # Test bindMethod
+  type TestObject = object
+    a: int
+    onWhatever: proc(e: int): int {.nimcall.}
+  proc handleWhatever(this: TestObject, e: int): int =
+    e + this.a
+  block:
+    let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
+    doAssert obj.onWhatever(1) == 10
+
+block:
+  {.emit: "function jsProc(n) { return n; }" .}
+  proc jsProc(x: int32): JsObject {.importjs: "jsProc(#)".}
+  block:
+    var x = jsProc(1)
+    var y = jsProc(2)
+    console.log x + y
+    console.log ++x
+
+    x += jsProc(10)
+    console.log x
+
+block:
+  {.emit:
+  """
+  function Event(name) { this.name = name; }
+  function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); }
+  var jslib = { "on": on, "subscribe": on };
+  """
+  .}
+
+  type Event = object
+    name: cstring
+
+  proc on(event: cstring, handler: proc) {.importjs: "on(#,#)".}
+  var jslib {.importjs: "jslib", nodecl.}: JsObject
+
+  on("click") do (e: Event):
+    console.log e
+
+  jslib.on("reloaded") do ():
+    console.log jsarguments[0]
+
+  # this test case is different from the above, because
+  # `subscribe` is not overloaded in the current scope
+  jslib.subscribe("updates"):
+    console.log jsarguments[0]
+
+block:
+  doAssert jsUndefined == jsNull
+  doAssert jsUndefined == nil
+  doAssert jsNull == nil
+  doAssert jsUndefined.isNil
+  doAssert jsNull.isNil
+  doAssert jsNull.isNull
+  doAssert jsUndefined.isUndefined
+
+block: # test **
+  var a = toJs(0)
+  var b = toJs(0)
+  doAssert to(a ** b, int) == 1
+  a = toJs(1)
+  b = toJs(1)
+  doAssert to(a ** b, int) == 1
+  a = toJs(-1)
+  b = toJs(-1)
+  doAssert to(a ** b, int) == -1
+  a = toJs(6)
+  b = toJs(6)
+  doAssert to(a ** b, int) == 46656
+  a = toJs(5.5)
+  b = toJs(3)
+  doAssert to(a ** b, float) == 166.375
+  a = toJs(5)
+  b = toJs(3.0)
+  doAssert to(a ** b, float) == 125.0
+  a = toJs(7.0)
+  b = toJS(6.0)
+  doAssert to(a ** b, float) == 117649.0
+  a = toJs(8)
+  b = toJS(-2)
+  doAssert to(a ** b, float) == 0.015625
+
+  a = toJs(1)
+  b = toJs(1)
+  doAssert to(`**`(a + a, b), int) == 2
+
+  doAssert to(`**`(toJs(1) + toJs(1), toJs(2)), int) == 4
+
+block: # issue #21208
+  type MyEnum = enum baz
+  var obj: JsObject
+  {.emit: "`obj` = {bar: {baz: 123}};".}
+  discard obj.bar.baz
diff --git a/tests/js/tjsffi_old.nim b/tests/js/tjsffi_old.nim
new file mode 100644
index 000000000..378003f4e
--- /dev/null
+++ b/tests/js/tjsffi_old.nim
@@ -0,0 +1,340 @@
+discard """
+output: '''
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+3
+2
+12
+Event { name: 'click: test' }
+Event { name: 'reloaded: test' }
+Event { name: 'updates: test' }
+true
+true
+true
+true
+true
+true
+true
+'''
+"""
+
+## same as tjsffi, but this test uses the old names: importc and
+## importcpp. This test is for backwards compatibility.
+
+# xxx instead of maintaining this near-duplicate test file, just have tests
+# that check that importc, importcpp, importjs work and remove this file.
+
+import jsffi, jsconsole
+
+# Tests for JsObject
+# Test JsObject []= and []
+block:
+  proc test(): bool =
+    let obj = newJsObject()
+    var working = true
+    obj["a"] = 11
+    obj["b"] = "test"
+    obj["c"] = "test".cstring
+    working = working and obj["a"].to(int) == 11
+    working = working and obj["c"].to(cstring) == "test".cstring
+    working
+  echo test()
+
+# Test JsObject .= and .
+block:
+  proc test(): bool =
+    let obj = newJsObject()
+    var working = true
+    obj.a = 11
+    obj.b = "test"
+    obj.c = "test".cstring
+    obj.`$!&` = 42
+    obj.`while` = 99
+    working = working and obj.a.to(int) == 11
+    working = working and obj.b.to(string) == "test"
+    working = working and obj.c.to(cstring) == "test".cstring
+    working = working and obj.`$!&`.to(int) == 42
+    working = working and obj.`while`.to(int) == 99
+    working
+  echo test()
+
+# Test JsObject .()
+block:
+  proc test(): bool =
+    let obj = newJsObject()
+    obj.`?!$` = proc(x, y, z: int, t: cstring): cstring = t & $(x + y + z)
+    obj.`?!$`(1, 2, 3, "Result is: ").to(cstring) == cstring"Result is: 6"
+  echo test()
+
+# Test JsObject []()
+block:
+  proc test(): bool =
+    let obj = newJsObject()
+    obj.a = proc(x, y, z: int, t: string): string = t & $(x + y + z)
+    let call = obj["a"].to(proc(x, y, z: int, t: string): string)
+    call(1, 2, 3, "Result is: ") == "Result is: 6"
+  echo test()
+
+# Test JsObject Iterators
+block:
+  proc testPairs(): bool =
+    let obj = newJsObject()
+    var working = true
+    obj.a = 10
+    obj.b = 20
+    obj.c = 30
+    for k, v in obj.pairs:
+      case $k
+      of "a":
+        working = working and v.to(int) == 10
+      of "b":
+        working = working and v.to(int) == 20
+      of "c":
+        working = working and v.to(int) == 30
+      else:
+        return false
+    working
+  proc testItems(): bool =
+    let obj = newJsObject()
+    var working = true
+    obj.a = 10
+    obj.b = 20
+    obj.c = 30
+    for v in obj.items:
+      working = working and v.to(int) in [10, 20, 30]
+    working
+  proc testKeys(): bool =
+    let obj = newJsObject()
+    var working = true
+    obj.a = 10
+    obj.b = 20
+    obj.c = 30
+    for v in obj.keys:
+      working = working and $v in ["a", "b", "c"]
+    working
+  proc test(): bool = testPairs() and testItems() and testKeys()
+  echo test()
+
+# Test JsObject equality
+block:
+  proc test(): bool =
+    {. emit: "var comparison = {a: 22, b: 'test'};" .}
+    var comparison {. importc, nodecl .}: JsObject
+    let obj = newJsObject()
+    obj.a = 22
+    obj.b = "test".cstring
+    obj.a == comparison.a and obj.b == comparison.b
+  echo test()
+
+# Test JsObject literal
+block:
+  proc test(): bool =
+    {. emit: "var comparison = {a: 22, b: 'test'};" .}
+    var comparison {. importc, nodecl .}: JsObject
+    let obj = JsObject{ a: 22, b: "test".cstring }
+    obj.a == comparison.a and obj.b == comparison.b
+  echo test()
+
+# Tests for JsAssoc
+# Test JsAssoc []= and []
+block:
+  proc test(): bool =
+    let obj = newJsAssoc[int, int]()
+    var working = true
+    obj[1] = 11
+    working = working and not compiles(obj["a"] = 11)
+    working = working and not compiles(obj["a"])
+    working = working and not compiles(obj[2] = "test")
+    working = working and not compiles(obj[3] = "test".cstring)
+    working = working and obj[1] == 11
+    working
+  echo test()
+
+# Test JsAssoc .= and .
+block:
+  proc test(): bool =
+    let obj = newJsAssoc[cstring, int]()
+    var working = true
+    obj.a = 11
+    obj.`$!&` = 42
+    working = working and not compiles(obj.b = "test")
+    working = working and not compiles(obj.c = "test".cstring)
+    working = working and obj.a == 11
+    working = working and obj.`$!&` == 42
+    working
+  echo test()
+
+# Test JsAssoc .()
+block:
+  proc test(): bool =
+    let obj = newJsAssoc[cstring, proc(e: int): int]()
+    obj.a = proc(e: int): int = e * e
+    obj.a(10) == 100
+  echo test()
+
+# Test JsAssoc []()
+block:
+  proc test(): bool =
+    let obj = newJsAssoc[cstring, proc(e: int): int]()
+    obj.a = proc(e: int): int = e * e
+    let call = obj["a"]
+    call(10) == 100
+  echo test()
+
+# Test JsAssoc Iterators
+block:
+  proc testPairs(): bool =
+    let obj = newJsAssoc[cstring, int]()
+    var working = true
+    obj.a = 10
+    obj.b = 20
+    obj.c = 30
+    for k, v in obj.pairs:
+      case $k
+      of "a":
+        working = working and v == 10
+      of "b":
+        working = working and v == 20
+      of "c":
+        working = working and v == 30
+      else:
+        return false
+    working
+  proc testItems(): bool =
+    let obj = newJsAssoc[cstring, int]()
+    var working = true
+    obj.a = 10
+    obj.b = 20
+    obj.c = 30
+    for v in obj.items:
+      working = working and v in [10, 20, 30]
+    working
+  proc testKeys(): bool =
+    let obj = newJsAssoc[cstring, int]()
+    var working = true
+    obj.a = 10
+    obj.b = 20
+    obj.c = 30
+    for v in obj.keys:
+      working = working and v in [cstring"a", cstring"b", cstring"c"]
+    working
+  proc test(): bool = testPairs() and testItems() and testKeys()
+  echo test()
+
+# Test JsAssoc equality
+block:
+  proc test(): bool =
+    {. emit: "var comparison = {a: 22, b: 55};" .}
+    var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
+    let obj = newJsAssoc[cstring, int]()
+    obj.a = 22
+    obj.b = 55
+    obj.a == comparison.a and obj.b == comparison.b
+  echo test()
+
+# Test JsAssoc literal
+block:
+  proc test(): bool =
+    {. emit: "var comparison = {a: 22, b: 55};" .}
+    var comparison {. importcpp, nodecl .}: JsAssoc[cstring, int]
+    let obj = JsAssoc[cstring, int]{ a: 22, b: 55 }
+    var working = true
+    working = working and
+      compiles(JsAssoc[int, int]{ 1: 22, 2: 55 })
+    working = working and
+      comparison.a == obj.a and comparison.b == obj.b
+    working = working and
+      not compiles(JsAssoc[cstring, int]{ a: "test" })
+    working
+  echo test()
+
+# Tests for macros on non-JsRoot objects
+# Test lit
+block:
+  type TestObject = object
+    a: int
+    b: cstring
+  proc test(): bool =
+    {. emit: "var comparison = {a: 1};" .}
+    var comparison {. importc, nodecl .}: TestObject
+    let obj = TestObject{ a: 1 }
+    obj == comparison
+  echo test()
+
+# Test bindMethod
+block:
+  type TestObject = object
+    a: int
+    onWhatever: proc(e: int): int {.nimcall.}
+  proc handleWhatever(this: TestObject, e: int): int {.nimcall.} =
+    e + this.a
+  proc test(): bool =
+    let obj = TestObject(a: 9, onWhatever: bindMethod(handleWhatever))
+    obj.onWhatever(1) == 10
+  echo test()
+
+block:
+  {.emit: "function jsProc(n) { return n; }" .}
+  proc jsProc(x: int32): JsObject {.importc: "jsProc".}
+
+  proc test() =
+    var x = jsProc(1)
+    var y = jsProc(2)
+    console.log x + y
+    console.log ++x
+
+    x += jsProc(10)
+    console.log x
+
+  test()
+
+
+block:
+  {.emit:
+  """
+  function Event(name) { this.name = name; }
+  function on(eventName, eventHandler) { eventHandler(new Event(eventName + ": test")); }
+  var jslib = { "on": on, "subscribe": on };
+  """
+  .}
+
+  type Event = object
+    name: cstring
+
+  proc on(event: cstring, handler: proc) {.importc: "on".}
+  var jslib {.importc: "jslib", nodecl.}: JsObject
+
+  on("click") do (e: Event):
+    console.log e
+
+  jslib.on("reloaded") do ():
+    console.log jsarguments[0]
+
+  # this test case is different from the above, because
+  # `subscribe` is not overloaded in the current scope
+  jslib.subscribe("updates"):
+    console.log jsarguments[0]
+
+block:
+
+  echo jsUndefined == jsNull
+  echo jsUndefined == nil
+  echo jsNull == nil
+  echo jsUndefined.isNil
+  echo jsNull.isNil
+  echo jsNull.isNull
+  echo jsUndefined.isUndefined
diff --git a/tests/js/tjshello.nim b/tests/js/tjshello.nim
new file mode 100644
index 000000000..8e090b3d2
--- /dev/null
+++ b/tests/js/tjshello.nim
@@ -0,0 +1,10 @@
+discard """
+  cmd: "nim $target $options --stackTrace:off --lineTrace:off $file"
+  output: "Hello World"
+  maxcodesize: 1000
+  ccodecheck: "!@'function'"
+"""
+
+import jsconsole
+
+console.log "Hello World"
diff --git a/tests/js/tjshello_stacktrace.nim b/tests/js/tjshello_stacktrace.nim
new file mode 100644
index 000000000..d5e1c36eb
--- /dev/null
+++ b/tests/js/tjshello_stacktrace.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "Hello World"
+  maxcodesize: 4500
+  ccodecheck: "!@'function'"
+"""
+
+import jsconsole
+
+console.log "Hello World"
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/tlent.nim b/tests/js/tlent.nim
new file mode 100644
index 000000000..2546e5b1d
--- /dev/null
+++ b/tests/js/tlent.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''
+hmm
+100
+hmm
+100
+'''
+"""
+
+# #16800
+
+type A = object
+  b: int
+var t = A(b: 100)
+block:
+  proc getValues: lent int =
+    echo "hmm"
+    result = t.b
+  echo getValues()
+block:
+  proc getValues: lent int =
+    echo "hmm"
+    t.b
+  echo getValues()
+
+when false: # still an issue, #16908
+  template main =
+    iterator fn[T](a:T): lent T = yield a
+    let a = @[10]
+    for b in fn(a): echo b
+
+  static: main()
+  main()
diff --git a/tests/js/tmangle.nim b/tests/js/tmangle.nim
new file mode 100644
index 000000000..caaa15fa1
--- /dev/null
+++ b/tests/js/tmangle.nim
@@ -0,0 +1,106 @@
+discard """
+  output: '''true
+true
+true
+true
+true
+true
+true'''
+"""
+
+# Test not mangled:
+block:
+  type T = object
+    a: int
+    b: cstring
+  proc test(): bool =
+    let obj = T(a: 11, b: "foo")
+    {. emit: [result, " = (", obj, ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", obj, ".b == \"foo\");"] .}
+  echo test()
+
+# Test indirect (fields in genAddr):
+block:
+  type T = object
+    a: int
+    b: cstring
+  var global = T(a: 11, b: "foo")
+  proc test(): bool =
+    var obj = T(a: 11, b: "foo")
+    {. emit: [result, " = (", obj.addr[], ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", obj.addr[], ".b == \"foo\");"] .}
+    {. emit: [result, " = ", result, " && (", global, ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", global, ".b == \"foo\");"] .}
+  echo test()
+
+# Test addr of field:
+block:
+  type T = object
+    a: int
+    b: cstring
+  proc test(): bool =
+    var obj = T(a: 11, b: "foo")
+    result = obj.a.addr[] == 11
+    result = result and obj.b.addr[] == "foo".cstring
+  echo test()
+
+# Test reserved words:
+block:
+  type T = ref object
+    `if`: int
+    `for`: int
+    `==`: cstring
+    `&&`: cstring
+  proc test(): bool =
+    var
+      obj1 = T(`if`: 11, `for`: 22, `==`: "foo", `&&`: "bar")
+      obj2: T
+    new obj2 # Test behaviour for createRecordVarAux.
+    result = obj1.`if` == 11
+    result = result and obj1.addr[].`for` == 22
+    result = result and obj1.`==` == "foo".cstring
+    result = result and obj1.`&&`.addr[] == "bar".cstring
+    result = result and obj2.`if` == 0
+    result = result and obj2.`for` == 0
+    result = result and obj2.`==`.isNil
+    result = result and obj2.`&&`.isNil
+  echo test()
+
+# Test codegen for fields with uppercase letters:
+block:
+  type MyObj = object
+    mField: int
+  proc test(): bool =
+    var a: MyObj
+    var b = a
+    result = b.mField == 0
+  echo test()
+
+# Test tuples
+block:
+  type T = tuple
+    a: int
+    b: int
+  proc test(): bool =
+    var a: T = (a: 1, b: 1)
+    result = a.a == 1
+    result = result and a.b == 1
+  echo test()
+
+# Test importc / exportc fields:
+block:
+  type T = object
+    a: int
+    b {. importc: "notB" .}: cstring
+  type U = object
+    a: int
+    b {. exportc: "notB" .}: cstring
+  proc test(): bool =
+    var
+      obj1 = T(a: 11, b: "foo")
+      obj2 = U(a: 11, b: "foo")
+    {. emit: [result, " = (", obj1, ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", obj1, ".notB == \"foo\");"] .}
+    {. emit: [result, " = (", obj2, ".a == 11);"] .}
+    {. emit: [result, " = ", result, " && (", obj2, ".notB == \"foo\");"] .}
+  echo test()
diff --git a/tests/js/tmodify_cstring.nim b/tests/js/tmodify_cstring.nim
new file mode 100644
index 000000000..82f8ccb23
--- /dev/null
+++ b/tests/js/tmodify_cstring.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "cstring doesn't support `[]=` operator"
+"""
+
+var x = cstring"abcd"
+x[0] = 'x'
diff --git a/tests/js/tnativeexc.nim b/tests/js/tnativeexc.nim
new file mode 100644
index 000000000..8b2b43e8f
--- /dev/null
+++ b/tests/js/tnativeexc.nim
@@ -0,0 +1,31 @@
+discard """
+  action: "run"
+"""
+
+import jsffi
+
+# Can catch JS exceptions
+try:
+  asm """throw new Error('a new error');"""
+except JsError as e:
+  doAssert e.message == "a new error"
+except:
+  doAssert false
+
+# Can distinguish different exceptions
+try:
+  asm """JSON.parse(';;');"""
+except JsEvalError:
+  doAssert false
+except JsSyntaxError as se:
+  doAssert se.message == "Unexpected token ';', \";;\" is not valid JSON"
+except JsError as e:
+  doAssert false
+
+# Can catch parent exception
+try:
+  asm """throw new SyntaxError();"""
+except JsError as e:
+  discard
+except:
+  doAssert false
diff --git a/tests/js/tneginthash.nim b/tests/js/tneginthash.nim
new file mode 100644
index 000000000..c082405c9
--- /dev/null
+++ b/tests/js/tneginthash.nim
@@ -0,0 +1,21 @@
+# issue #19929
+
+import std/[tables, hashes]
+
+type Foo = object
+  a: int
+
+proc hash(f: Foo): Hash =
+  var h: Hash = 0
+  h = h !& hash(f.a)
+  result = !$h
+
+proc transpose[T, S](data: array[T, S]): Table[S, T] =
+  for i, x in data:
+    result[x] = i
+
+const xs = [Foo(a: 5), Foo(a: -5)]
+const x = transpose(xs)
+
+doAssert x[Foo(a: -5)] == 1
+doAssert x[Foo(a: 5)] == 0
diff --git a/tests/js/tnilstrs.nim b/tests/js/tnilstrs.nim
new file mode 100644
index 000000000..6c1e4e401
--- /dev/null
+++ b/tests/js/tnilstrs.nim
@@ -0,0 +1,25 @@
+block:
+  var x: string
+  var y = "foo"
+
+  echo x
+  doAssert x == ""
+  doAssert "" == x
+
+  add(x, y)
+  y[0] = 'm'
+  doAssert y == "moo" and x == "foo"
+
+block:
+  var x = "foo".cstring
+  var y: string
+  add(y, x)
+  doAssert y == "foo"
+
+block:
+  type Foo = object
+    a: string
+  var foo = Foo(a: "foo")
+  var y = move foo.a
+  doAssert foo.a.len == 0
+  doAssert y == "foo"
diff --git a/tests/js/tobjfieldbyvar.nim b/tests/js/tobjfieldbyvar.nim
new file mode 100644
index 000000000..91a3c1315
--- /dev/null
+++ b/tests/js/tobjfieldbyvar.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''5
+'''
+"""
+
+# bug #2798
+
+type Inner = object
+  value: int
+
+type Outer = object
+  i: Inner
+
+proc test(i: var Inner) =
+  i.value += 5
+
+var o: Outer
+test(o.i)
+
+echo o.i.value
diff --git a/tests/js/tos.nim b/tests/js/tos.nim
new file mode 100644
index 000000000..40fb52bcf
--- /dev/null
+++ b/tests/js/tos.nim
@@ -0,0 +1,21 @@
+# xxx consider merging this in tests/stdlib/tos.nim for increased coverage (with selecting disabling)
+
+static: doAssert defined(nodejs)
+
+import os
+
+block:
+  doAssert "./foo//./bar/".normalizedPath == "foo/bar"
+  doAssert relativePath(".//foo/bar", "foo") == "bar"
+  doAssert "/".isAbsolute
+  doAssert not "".isAbsolute
+  doAssert not ".".isAbsolute
+  doAssert not "foo".isAbsolute
+  doAssert relativePath("", "bar") == ""
+  doAssert normalizedPath(".///foo//./") == "foo"
+
+  when nimvm: discard
+  else:
+    let cwd = getCurrentDir()
+    doAssert cwd.isAbsolute
+    doAssert relativePath(getCurrentDir() / "foo", "bar") == ".." / "foo"
diff --git a/tests/js/trefbyvar.nim b/tests/js/trefbyvar.nim
new file mode 100644
index 000000000..5b168044e
--- /dev/null
+++ b/tests/js/trefbyvar.nim
@@ -0,0 +1,69 @@
+discard """
+  output: '''0
+5
+0
+5
+@[1, 2]
+~'''
+"""
+
+# bug #2476
+
+type A = ref object
+    m: int
+
+proc f(a: var A) =
+    var b: A
+    b.new()
+    b.m = 5
+    a = b
+
+var t: A
+t.new()
+
+echo t.m
+t.f()
+echo t.m
+
+proc main =
+  # now test the same for locals
+  var t: A
+  t.new()
+
+  echo t.m
+  t.f()
+  echo t.m
+
+main()
+
+# bug #5974
+type
+  View* = object
+    data: ref seq[int]
+
+let a = View(data: new(seq[int]))
+a.data[] = @[1, 2]
+
+echo a.data[]
+
+# bug #5379
+var input = newSeq[ref string]()
+input.add(nil)
+input.add(new string)
+input[1][] = "~"
+echo input[1][]
+
+# bug #5517
+type
+  TypeA1 = object of RootObj
+    a_impl: int
+    b_impl: string
+    c_impl: pointer
+
+proc initTypeA1(a: int; b: string; c: pointer = nil): TypeA1 =
+  result.a_impl = a
+  result.b_impl = b
+  result.c_impl = c
+
+let x = initTypeA1(1, "a")
+doAssert($x == "(a_impl: 1, b_impl: \"a\", c_impl: ...)")
diff --git a/tests/js/trepr.nim b/tests/js/trepr.nim
new file mode 100644
index 000000000..a562ad63b
--- /dev/null
+++ b/tests/js/trepr.nim
@@ -0,0 +1,413 @@
+# xxx consider merging with `tests/stdlib/trepr.nim` to increase overall test coverage
+
+block ints:
+  let
+    na: int8 = -120'i8
+    nb: int16 = -32700'i16
+    nc: int32 = -2147483000'i32
+    nd: int64 = -9223372036854775000'i64
+    ne: int = -1234567
+    pa: int8 = 120'i8
+    pb: int16 = 32700'i16
+    pc: int32 = 2147483000'i32
+    pd: int64 = 9223372036854775000'i64
+    pe: int = 1234567
+
+  doAssert(repr(na) == "-120")
+  doAssert(repr(nb) == "-32700")
+  doAssert(repr(nc) == "-2147483000")
+  doAssert(repr(nd) == "-9223372036854775000")
+  doAssert(repr(ne) == "-1234567")
+  doAssert(repr(pa) == "120")
+  doAssert(repr(pb) == "32700")
+  doAssert(repr(pc) == "2147483000")
+  doAssert(repr(pd) == "9223372036854775000")
+  doAssert(repr(pe) == "1234567")
+
+block uints:
+  let
+    a: uint8 = 254'u8
+    b: uint16 = 65300'u16
+    c: uint32 = 4294967290'u32
+    # d: uint64 = 18446744073709551610'u64  -> unknown node type
+    e: uint = 1234567
+
+  doAssert(repr(a) == "254")
+  doAssert(repr(b) == "65300")
+  doAssert(repr(c) == "4294967290")
+  # doAssert(repr(d) == "18446744073709551610")
+  doAssert(repr(e) == "1234567")
+
+block floats:
+  let
+    a: float32 = 3.4e38'f32
+    b: float64 = 1.7976931348623157e308'f64
+    c: float = 1234.567e89
+
+  when defined js:
+    doAssert(repr(a) == "3.4e+38") # in C: 3.399999952144364e+038
+    doAssert(repr(b) == "1.7976931348623157e+308") # in C: 1.797693134862316e+308
+    doAssert(repr(c) == "1.234567e+92") # in C: 1.234567e+092
+
+block bools:
+  let
+    a: bool = true
+    b: bool = false
+
+  doAssert(repr(a) == "true")
+  doAssert(repr(b) == "false")
+
+block enums:
+  type
+    AnEnum = enum
+      aeA
+      aeB
+      aeC
+    HoledEnum = enum
+      heA = -12
+      heB = 15
+      heC = 123
+
+  doAssert(repr(aeA) == "aeA")
+  doAssert(repr(aeB) == "aeB")
+  doAssert(repr(aeC) == "aeC")
+  doAssert(repr(heA) == "heA")
+  doAssert(repr(heB) == "heB")
+  doAssert(repr(heC) == "heC")
+
+block emums_and_unicode: #6741
+  type K = enum Kanji = "漢字"
+  let kanji = Kanji
+  doAssert(kanji == Kanji, "Enum values are not equal")
+  doAssert($kanji == $Kanji, "Enum string values are not equal")
+
+block chars:
+  let
+    a = 'a'
+    b = 'z'
+    one = '1'
+    nl = '\x0A'
+
+  doAssert(repr(a) == "'a'")
+  doAssert(repr(b) == "'z'")
+  doAssert(repr(one) == "'1'")
+  doAssert(repr(nl) == "'\\10'")
+
+block strings:
+  let
+    a: string = "12345"
+    b: string = "hello,repr"
+    c: string = "hi\nthere"
+  when defined js: # C prepends the pointer, JS does not.
+    doAssert(repr(a) == "\"12345\"")
+    doAssert(repr(b) == "\"hello,repr\"")
+    doAssert(repr(c) == "\"hi\\10there\"")
+
+block sets:
+  let
+    a: set[int16] = {1'i16, 2'i16, 3'i16}
+    b: set[char] = {'A', 'k'}
+
+  doAssert(repr(a) == "{1, 2, 3}")
+  doAssert(repr(b) == "{'A', 'k'}")
+
+block ranges:
+  let
+    a: range[0..12] = 6
+    b: range[-12..0] = -6
+  doAssert(repr(a) == "6")
+  doAssert(repr(b) == "-6")
+
+block tuples:
+  type
+    ATuple = tuple
+      a: int
+      b: float
+      c: string
+      d: OtherTuple
+    OtherTuple = tuple
+      a: bool
+      b: int8
+
+  let
+    ot: OtherTuple = (a: true, b: 120'i8)
+    t: ATuple = (a: 42, b: 12.34, c: "tuple", d: ot)
+  when defined js:
+    doAssert(repr(ot) == """
+[Field0 = true,
+Field1 = 120]""")
+    doAssert(repr(t) == """
+[Field0 = 42,
+Field1 = 12.34,
+Field2 = "tuple",
+Field3 = [Field0 = true,
+Field1 = 120]]""")
+
+block objects:
+  type
+    AnObj = object
+      a: int
+      b: float
+      c: OtherObj
+    OtherObj = object
+      a: bool
+      b: int8
+  let
+    oo: OtherObj = OtherObj(a: true, b: 120'i8)
+    o: AnObj = AnObj(a: 42, b: 12.34, c: oo)
+
+  doAssert(repr(oo) == """
+[a = true,
+b = 120]""")
+  doAssert(repr(o) == """
+[a = 42,
+b = 12.34,
+c = [a = true,
+b = 120]]""")
+
+block arrays:
+  type
+    AObj = object
+      x: int
+      y: array[3,float]
+  let
+    a = [0.0, 1, 2]
+    b = [a, a, a]
+    o = AObj(x: 42, y: a)
+    c = [o, o, o]
+    d = ["hi", "array", "!"]
+
+  doAssert(repr(a) == "[0.0, 1.0, 2.0]")
+  doAssert(repr(b) == "[[0.0, 1.0, 2.0], [0.0, 1.0, 2.0], [0.0, 1.0, 2.0]]")
+  doAssert(repr(c) == """
+[[x = 42,
+y = [0.0, 1.0, 2.0]], [x = 42,
+y = [0.0, 1.0, 2.0]], [x = 42,
+y = [0.0, 1.0, 2.0]]]""")
+  doAssert(repr(d) == "[\"hi\", \"array\", \"!\"]")
+
+block seqs:
+  type
+    AObj = object
+      x: int
+      y: seq[float]
+  let
+    a = @[0.0, 1, 2]
+    b = @[a, a, a]
+    o = AObj(x: 42, y: a)
+    c = @[o, o, o]
+    d = @["hi", "array", "!"]
+
+  doAssert(repr(a) == "@[0.0, 1.0, 2.0]")
+  doAssert(repr(b) == "@[@[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0], @[0.0, 1.0, 2.0]]")
+  doAssert(repr(c) == """
+@[[x = 42,
+y = @[0.0, 1.0, 2.0]], [x = 42,
+y = @[0.0, 1.0, 2.0]], [x = 42,
+y = @[0.0, 1.0, 2.0]]]""")
+  doAssert(repr(d) == "@[\"hi\", \"array\", \"!\"]")
+
+block ptrs:
+  type
+    AObj = object
+      x: ptr array[2, AObj]
+      y: int
+  var
+    a = [12.0, 13.0, 14.0]
+    b = addr a[0]
+    c = addr a[2]
+    d = AObj()
+
+  doAssert(repr(a) == "[12.0, 13.0, 14.0]")
+  doAssert(repr(b) == "ref 0 --> 12.0")
+  doAssert(repr(c) == "ref 2 --> 14.0")
+  doAssert(repr(d) == """
+[x = nil,
+y = 0]""")
+
+block ptrs:
+  type
+    AObj = object
+      x: ref array[2, AObj]
+      y: int
+  var
+    a = AObj()
+
+  new(a.x)
+
+  doAssert(repr(a) == """
+[x = ref 0 --> [[x = nil,
+y = 0], [x = nil,
+y = 0]],
+y = 0]""")
+
+block procs:
+  proc test(): int =
+    echo "hello"
+  var
+    ptest = test
+    nilproc: proc(): int
+
+  doAssert(repr(test) == "0")
+  doAssert(repr(ptest) == "0")
+  doAssert(repr(nilproc) == "nil")
+
+block bunch:
+  type
+    AnEnum = enum
+      eA, eB, eC
+    B = object
+      a: string
+      b: seq[char]
+    A = object
+      a: uint32
+      b: int
+      c: float
+      d: char
+      e: AnEnum
+      f: string
+      g: set[char]
+      h: set[int16]
+      i: array[3,string]
+      j: seq[string]
+      k: range[-12..12]
+      l: B
+      m: ref B
+      n: ptr B
+      o: tuple[x: B, y: string]
+      p: proc(b: B): ref B
+      q: cstring
+
+  proc refB(b:B):ref B =
+    new result
+    result[] = b
+
+  var
+    aa = default(A)
+    bb: B = B(a: "inner", b: @['o', 'b', 'j'])
+    cc: A = A(a: 12, b: 1, c: 1.2, d: '\0', e: eC,
+                f: "hello", g: {'A'}, h: {2'i16},
+                i: ["hello", "world", "array"],
+                j: @["hello", "world", "seq"], k: -1,
+                l: bb, m: refB(bb), n: addr bb,
+                o: (bb, "tuple!"), p: refB, q: "cstringtest" )
+
+  doAssert(repr(aa) == """
+[a = 0,
+b = 0,
+c = 0.0,
+d = '\0',
+e = eA,
+f = "",
+g = {},
+h = {},
+i = ["", "", ""],
+j = @[],
+k = -12,
+l = [a = "",
+b = @[]],
+m = nil,
+n = nil,
+o = [Field0 = [a = "",
+b = @[]],
+Field1 = ""],
+p = nil,
+q = nil]""")
+  doAssert(repr(cc) == """
+[a = 12,
+b = 1,
+c = 1.2,
+d = '\0',
+e = eC,
+f = "hello",
+g = {'A'},
+h = {2},
+i = ["hello", "world", "array"],
+j = @["hello", "world", "seq"],
+k = -1,
+l = [a = "inner",
+b = @['o', 'b', 'j']],
+m = ref 0 --> [a = "inner",
+b = @['o', 'b', 'j']],
+n = ref 0 --> [a = "inner",
+b = @['o', 'b', 'j']],
+o = [Field0 = [a = "inner",
+b = @['o', 'b', 'j']],
+Field1 = "tuple!"],
+p = 0,
+q = "cstringtest"]""")
+
+block another:
+  type
+    Size1 = enum
+      s1a, s1b
+    Size2 = enum
+      s2c=0, s2d=20000
+    Size3 = enum
+      s3e=0, s3f=2000000000
+
+  doAssert(repr([s1a, s1b]) == "[s1a, s1b]")
+  doAssert(repr([s2c, s2d]) == "[s2c, s2d]")
+  doAssert(repr([s3e, s3f]) == "[s3e, s3f]")
+
+block another2:
+
+  type
+    AnEnum = enum
+      en1, en2, en3, en4, en5, en6
+
+    Point {.final.} = object
+      x, y, z: int
+      s: array[0..1, string]
+      e: AnEnum
+
+  var
+    p: Point
+    q: ref Point
+    s: seq[ref Point]
+
+  p.x = 0
+  p.y = 13
+  p.z = 45
+  p.s[0] = "abc"
+  p.s[1] = "xyz"
+  p.e = en6
+
+  new(q)
+  q[] = p
+
+  s = @[q, q, q, q]
+
+  doAssert(repr(p) == """
+[x = 0,
+y = 13,
+z = 45,
+s = ["abc", "xyz"],
+e = en6]""")
+  doAssert(repr(q) == """
+ref 0 --> [x = 0,
+y = 13,
+z = 45,
+s = ["abc", "xyz"],
+e = en6]""")
+  doAssert(repr(s) == """
+@[ref 0 --> [x = 0,
+y = 13,
+z = 45,
+s = ["abc", "xyz"],
+e = en6], ref 1 --> [x = 0,
+y = 13,
+z = 45,
+s = ["abc", "xyz"],
+e = en6], ref 2 --> [x = 0,
+y = 13,
+z = 45,
+s = ["abc", "xyz"],
+e = en6], ref 3 --> [x = 0,
+y = 13,
+z = 45,
+s = ["abc", "xyz"],
+e = en6]]""")
+  doAssert(repr(en4) == "en4")
+
+  doAssert(repr({'a'..'p'}) == "{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p'}")
diff --git a/tests/js/treprinifexpr.nim b/tests/js/treprinifexpr.nim
new file mode 100644
index 000000000..09ded18b9
--- /dev/null
+++ b/tests/js/treprinifexpr.nim
@@ -0,0 +1,18 @@
+type
+  Enum = enum A
+
+let
+  enumVal = A
+  tmp = if true: $enumVal else: $enumVal
+
+let
+  intVal = 12
+  tmp2 = if true: repr(intVal) else: $enumVal
+
+let
+  strVal = "123"
+  tmp3 = if true: repr(strVal) else: $strVal
+
+let
+  floatVal = 12.4
+  tmp4 = if true: repr(floatVal) else: $floatVal
\ No newline at end of file
diff --git a/tests/js/tseqops.nim b/tests/js/tseqops.nim
new file mode 100644
index 000000000..8cfb50886
--- /dev/null
+++ b/tests/js/tseqops.nim
@@ -0,0 +1,48 @@
+# bug #4139
+
+type
+  TestO = object
+    x, y: int
+
+proc onLoad() =
+  var test: seq[TestO] = @[]
+  var foo = TestO(x: 0, y: 0)
+  test.add(foo)
+  foo.x = 5
+  doAssert $test[0] == "(x: 0, y: 0)"
+  doAssert $foo == "(x: 5, y: 0)"
+
+onLoad()
+
+# 'setLen' bug (part of bug #5933)
+type MyObj = object
+  x: cstring
+  y: int
+
+proc foo(x: var seq[MyObj]) =
+  let L = x.len
+  x.setLen L + 1
+  x[L] = x[1]
+
+var s = @[MyObj(x: "2", y: 4), MyObj(x: "4", y: 5)]
+foo(s)
+doAssert $s == """@[(x: "2", y: 4), (x: "4", y: 5), (x: "4", y: 5)]"""
+
+# bug  #5933
+import sequtils
+
+type
+  Test = object
+    a: cstring
+    b: int
+
+var test = @[Test(a: "1", b: 1), Test(a: "2", b: 2)]
+
+test.insert(@[Test(a: "3", b: 3)], 0)
+
+doAssert $test == """@[(a: "3", b: 3), (a: "1", b: 1), (a: "2", b: 2)]"""
+
+proc hello(): array[5, int] = discard
+var x = @(hello())
+x.add(2)
+doAssert x == @[0, 0, 0, 0, 0, 2]
diff --git a/tests/js/tsourcemap.nim b/tests/js/tsourcemap.nim
new file mode 100644
index 000000000..d358e4a57
--- /dev/null
+++ b/tests/js/tsourcemap.nim
@@ -0,0 +1,96 @@
+discard """
+  action: "run"
+  targets: "js"
+  cmd: "nim js -r -d:nodejs $options --sourceMap:on $file"
+"""
+import std/[os, json, strutils, sequtils, algorithm, assertions, paths, compilesettings]
+
+# Implements a very basic sourcemap parser and then runs it on itself.
+# Allows to check for basic problems such as bad counts and lines missing (e.g. issue #21052)
+
+type
+  SourceMap = object
+    version:   int
+    sources:   seq[string]
+    names:     seq[string]
+    mappings:  string
+    file:      string
+
+  Line = object
+    line, column: int
+    file: string
+
+const
+  flag = 1 shl 5
+  signBit = 0b1
+  fourBits = 0b1111
+  fiveBits = 0b11111
+  mask = (1 shl 5) - 1
+  alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+
+var b64Table: seq[int] = 0.repeat(max(alphabet.mapIt(it.ord)) + 1)
+for i, b in alphabet.pairs:
+  b64Table[b.ord] = i
+
+# From https://github.com/juancarlospaco/nodejs/blob/main/src/nodejs/jsfs.nim
+proc importFs*() {.importjs: "var fs = require(\"fs\");".}
+proc readFileSync*(path: cstring): cstring {.importjs: "(fs.$1(#).toString())".}
+importFS()
+# Read in needed files
+let
+  jsFileName = string(querySetting(outDir).Path / "tsourcemap.js".Path)
+  mapFileName = jsFileName & ".map"
+
+  data = parseJson($mapFileName.cstring.readFileSync()).to(SourceMap)
+  jsFile = $readFileSync(jsFileName.cstring)
+
+proc decodeVLQ(inp: string): seq[int] =
+  var
+    shift, value: int
+  for v in inp.mapIt(b64Table[it.ord]):
+    value += (v and mask) shl shift
+    if (v and flag) > 0:
+      shift += 5
+      continue
+    result &= (value shr 1) * (if (value and 1) > 0: -1 else: 1)
+    shift = 0
+    value = 0
+
+
+# Keep track of state
+var
+  line = 0
+  source = 0
+  name = 0
+  column = 0
+  jsLine = 1
+  lines: seq[Line]
+
+for gline in data.mappings.split(';'):
+  jsLine += 1
+  var jsColumn = 0
+  for item in gline.strip().split(','):
+    let value = item.decodeVLQ()
+    doAssert value.len in [0, 1, 4, 5]
+    if value.len == 0:
+      continue
+    jsColumn += value[0]
+    if value.len >= 4:
+      source += value[1]
+      line += value[2]
+      column += value[3]
+      lines &= Line(line: line, column: column, file: data.sources[source])
+
+let jsLines = jsFile.splitLines().len
+# There needs to be a mapping for every line in the JS
+# If there isn't then the JS lines wont match up with Nim lines.
+# Except we don't care about the final line since that doesn't need to line up
+doAssert data.mappings.count(';') == jsLines - 1
+
+# Check we can find this file somewhere in the source map
+var foundSelf = false
+for line in lines:
+  if "tsourcemap.nim" in line.file:
+    foundSelf = true
+    doAssert line.line in 0..<jsLines, "Lines is out of bounds for file"
+doAssert foundSelf, "Couldn't find tsourcemap.nim in source map"
diff --git a/tests/js/tstdlib_imports.nim b/tests/js/tstdlib_imports.nim
new file mode 100644
index 000000000..db851ba28
--- /dev/null
+++ b/tests/js/tstdlib_imports.nim
@@ -0,0 +1,80 @@
+discard """
+  action: compile
+"""
+
+{.warning[UnusedImport]: off.}
+
+when defined(nimPreviewSlimSystem):
+  import std/[
+    syncio, assertions, formatfloat, objectdollar, widestrs
+  ]
+
+import std/[
+  # Core:
+  bitops, typetraits, lenientops, macros, volatile, typeinfo,
+  # fails due to FFI: rlocks
+  # fails due to cstring cast/copyMem: endians
+  # works but uses FFI: cpuinfo, locks
+
+  # Algorithms:
+  algorithm, enumutils, sequtils, setutils,
+  
+  # Collections:
+  critbits, deques, heapqueue, intsets, lists, options, sets,
+  tables, packedsets,
+
+  # Strings:
+  cstrutils, editdistance, wordwrap, parseutils, ropes,
+  pegs, strformat, strmisc, strscans, strtabs,
+  strutils, unicode, unidecode,
+  # fails due to FFI: encodings
+
+  # Time handling:
+  monotimes, times,
+
+  # Generic operator system services:
+  os, streams,
+  # fails intentionally: dynlib, marshal, memfiles
+  # fails due to FFI: osproc, terminal
+  # fails due to osproc import: distros
+
+  # Math libraries:
+  complex, math, random, rationals, stats, sums, sysrand,
+  # works but uses FFI: fenv
+
+  # Internet protocols:
+  cookies, httpcore, mimetypes, uri,
+  # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver,
+  # asyncnet, cgi, httpclient, nativesockets, net, selectors
+  # works but no need to test: asyncstreams, asyncfutures
+  
+  # Threading:
+  # fails due to FFI: threadpool
+
+  # Parsers:
+  htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
+  parseopt, jsonutils,
+
+  # XML processing:
+  xmltree, xmlparser,
+
+  # Generators:
+  htmlgen,
+
+  # Hashing:
+  base64, hashes,
+  # fails due to cstring cast/endians import: oids
+  # fails due to copyMem/endians import: sha1
+
+  # Miscellaneous:
+  colors, logging, sugar, unittest, varints, enumerate, with,
+  # fails due to FFI: browsers, coro
+  # works but uses FFI: segfaults
+
+  # Modules for JS backend:
+  asyncjs, dom, jsconsole, jscore, jsffi, jsbigints,
+
+  # Unlisted in lib.html:
+  decls, compilesettings, wrapnils, exitprocs, effecttraits,
+  genasts, importutils, isolation, jsfetch, jsformdata, jsheaders
+]
diff --git a/tests/js/tstdlib_various.nim b/tests/js/tstdlib_various.nim
new file mode 100644
index 000000000..1e584f735
--- /dev/null
+++ b/tests/js/tstdlib_various.nim
@@ -0,0 +1,174 @@
+discard """
+output: '''
+abc
+def
+definition
+prefix
+xyz
+def
+definition
+Hi Andreas! How do you feel, Rumpf?
+
+@[0, 2, 1]
+@[1, 0, 2]
+@[1, 2, 0]
+@[2, 0, 1]
+@[2, 1, 0]
+@[2, 0, 1]
+@[1, 2, 0]
+@[1, 0, 2]
+@[0, 2, 1]
+@[0, 1, 2]
+[5]
+[4, 5]
+[3, 4, 5]
+[2, 3, 4, 5]
+[2, 3, 4, 5, 6]
+[1, 2, 3, 4, 5, 6]
+'''
+"""
+
+import
+  critbits, sets, strutils, tables, random, algorithm, ropes,
+  lists, htmlgen, xmltree, strtabs
+
+
+block tcritbits:
+  var r: CritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+  doAssert r.contains"def"
+  #r.del "def"
+
+  for w in r.items:
+    echo w
+  for w in r.itemsWithPrefix("de"):
+    echo w
+
+
+
+block testequivalence:
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset")
+  doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==")
+  doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==")
+
+
+
+block tformat:
+  echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])
+
+
+
+block tnilecho:
+  var x = @["1", "", "3"]
+  doAssert $x == """@["1", "", "3"]"""
+
+
+
+block torderedtable:
+  var t = initOrderedTable[int,string]()
+
+  # this tests issue #5917
+  var data = newSeq[int]()
+  for i in 0..<1000:
+    var x = rand(1000)
+    if x notin t: data.add(x)
+    t[x] = "meh"
+
+  # this checks that keys are re-inserted
+  # in order when table is enlarged.
+  var i = 0
+  for k, v in t:
+    doAssert(k == data[i])
+    doAssert(v == "meh")
+    inc(i)
+
+
+
+block tpermutations:
+  var v = @[0, 1, 2]
+  while v.nextPermutation():
+    echo v
+  while v.prevPermutation():
+    echo v
+
+
+block tropes:
+  var
+    r1 = rope("")
+    r2 = rope("123")
+  doAssert r1.len == 0
+  doAssert r2.len == 3
+  doAssert $r1 == ""
+  doAssert $r2 == "123"
+
+  r1.add("123")
+  r2.add("456")
+  doAssert r1.len == 3
+  doAssert r2.len == 6
+  doAssert $r1 == "123"
+  doAssert $r2 == "123456"
+  doAssert $r1[1] == "2"
+  doAssert $r2[2] == "3"
+
+
+block tsinglylinkedring:
+  var r = initSinglyLinkedRing[int]()
+  r.prepend(5)
+  echo r
+  r.prepend(4)
+  echo r
+  r.prepend(3)
+  echo r
+  r.prepend(2)
+  echo r
+  r.append(6)
+  echo r
+  r.prepend(1)
+  echo r
+
+block tsplit:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert s == "##abc#xy#z"
+
+block tsplit2:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert "true".split("") == @["true"]
+
+block txmlgen:
+  var nim = "Nim"
+  doAssert h1(a(href="http://force7.de/nim", nim)) ==
+    "<h1><a href=\"http://force7.de/nim\">Nim</a></h1>"
+
+block txmltree:
+  var x = <>a(href="nim.de", newText("www.nim-test.de"))
+
+  doAssert($x == "<a href=\"nim.de\">www.nim-test.de</a>")
+  doAssert(newText("foo").innerText == "foo")
+  doAssert(newEntity("bar").innerText == "bar")
+  doAssert(newComment("baz").innerText == "")
+
+  let y = newXmlTree("x", [
+    newText("foo"),
+    newXmlTree("y", [
+      newText("bar")
+    ])
+  ])
+  doAssert(y.innerText == "foobar")
diff --git a/tests/js/tstreams.nim b/tests/js/tstreams.nim
new file mode 100644
index 000000000..43c26e01a
--- /dev/null
+++ b/tests/js/tstreams.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''
+I
+AM
+GROOT
+'''
+"""
+
+import streams
+
+var s = newStringStream("I\nAM\nGROOT")
+doAssert s.peekStr(1) == "I"
+doAssert s.peekChar() == 'I'
+for line in s.lines:
+  echo line
+s.close
+
+var s2 = newStringStream("abc")
+doAssert s2.readAll == "abc"
+s2.write("def")
+doAssert s2.data == "abcdef"
+s2.close
diff --git a/tests/js/tstring_assignment.nim b/tests/js/tstring_assignment.nim
new file mode 100644
index 000000000..97ffa748f
--- /dev/null
+++ b/tests/js/tstring_assignment.nim
@@ -0,0 +1,21 @@
+discard """
+  output: '''true
+asdfasekjkler'''
+"""
+
+# bug #4471
+when true:
+  let s1 = "123"
+  var s2 = s1
+  s2.setLen(0)
+  # fails - s1.len == 0
+  echo s1.len == 3
+
+# bug #4470
+proc main(s: cstring): string =
+  result = newString(0)
+  for i in 0..<s.len:
+    if s[i] >= 'a' and s[i] <= 'z':
+      result.add s[i]
+
+echo main("asdfasekjkleräöü")
diff --git a/tests/js/tstringitems.nim b/tests/js/tstringitems.nim
new file mode 100644
index 000000000..16df04149
--- /dev/null
+++ b/tests/js/tstringitems.nim
@@ -0,0 +1,95 @@
+discard """
+  output: '''Hello
+Hello
+c
+d
+e'''
+"""
+
+block: # bug #2581
+  const someVars = [ "Hello" ]
+  var someVars2 = [ "Hello" ]
+
+  proc getSomeVar: string =
+      for i in someVars:
+          if i == "Hello":
+              result = i
+              break
+
+  proc getSomeVar2: string =
+      for i in someVars2:
+          if i == "Hello":
+              result = i
+              break
+
+  echo getSomeVar()
+  echo getSomeVar2()
+
+block: # Test compile-time binary data generation, invalid unicode
+  proc signatureMaker(): string {. compiletime .} =
+    const signatureBytes = [137, 80, 78, 71, 13, 10, 26, 10]
+    result = ""
+    for c in signatureBytes: result.add chr(c)
+
+  const cSig = signatureMaker()
+
+  var rSig = newString(8)
+  rSig[0] = chr(137)
+  rSig[1] = chr(80)
+  rSig[2] = chr(78)
+  rSig[3] = chr(71)
+  rSig[4] = chr(13)
+  rSig[5] = chr(10)
+  rSig[6] = chr(26)
+  rSig[7] = chr(10)
+
+  doAssert(rSig == cSig)
+
+block: # Test unicode strings
+  const constStr = "Привет!"
+  var jsStr : cstring
+  {.emit: """`jsStr` = "Привет!";""".}
+
+  doAssert($jsStr == constStr)
+  var runtimeStr = "При"
+  runtimeStr &= "вет!"
+
+  doAssert(runtimeStr == constStr)
+
+block: # Conversions from/to cstring
+  proc stringSaysHelloInRussian(s: cstring): bool =
+    {.emit: """`result` = (`s` === "Привет!");""".}
+
+  doAssert(stringSaysHelloInRussian("Привет!"))
+
+  const constStr = "Привет!"
+  doAssert(stringSaysHelloInRussian(constStr))
+
+  var rtStr = "Привет!"
+  doAssert(stringSaysHelloInRussian(rtStr))
+
+block: # String case of
+  const constStr = "Привет!"
+  var s = "Привет!"
+
+  case s
+  of constStr: discard
+  else: doAssert(false)
+
+  case s
+  of "Привет!": discard
+  else: doAssert(false)
+
+block: # String cmp
+  var a, b: string
+  doAssert(cmp(a, b) == 0)
+  doAssert(cmp("foo", "foo") == 0)
+  doAssert(cmp("foobar", "foo") == 3)
+  doAssert(cmp("foo", "foobar") == -3)
+  doAssert(cmp("fooz", "foog") == 19)
+  doAssert(cmp("foog", "fooz") == -19)
+
+proc main(x: openArray[char]) =
+  for c in x: echo c
+
+main(toOpenArray(['a', 'b', 'c', 'd', 'e'], 2, 4))
diff --git a/tests/js/ttempgen.nim b/tests/js/ttempgen.nim
new file mode 100644
index 000000000..badc66c1b
--- /dev/null
+++ b/tests/js/ttempgen.nim
@@ -0,0 +1,79 @@
+discard """
+  output: '''
+foo
+'''
+"""
+
+block: # #12672
+  var a = @[1]
+  let i = 1
+  inc a[i-1]
+
+  var b: seq[int]
+  doAssertRaises(IndexDefect): inc b[0]
+  doAssertRaises(IndexDefect): inc b[i-1]
+
+  var x: seq[seq[int]]
+  doAssertRaises(IndexDefect): # not TypeError
+    inc x[0][i-1]
+
+block: # #14087
+  type Obj = object
+    str: string
+
+  var s = @[Obj(str: "abc"), Obj(str: "def")]
+  s[1].str.add("ghi")
+  s[s.len - 1].str.add("jkl")
+  s[^1].str.add("mno")
+  s[s.high].str.add("pqr")
+
+  let slen = s.len
+  s[slen - 1].str.add("stu")
+
+  let shigh = s.high
+  s[shigh].str.add("vwx")
+
+  proc foo(): int =
+    echo "foo"
+    shigh
+  s[foo()].str.add("yz")
+  doAssert s[1].str == "defghijklmnopqrstuvwxyz"
+
+block: # #14117
+  type
+    A = object
+      case kind: bool
+      of true:
+        sons: seq[int]
+      else: discard
+
+  var a = A(kind: true)
+  doAssert a.sons.len == 0
+  a.sons.add(1)
+  doAssert a.sons.len == 1
+
+import tables
+
+block: # #13966
+  var t: Table[int8, array[int8, seq[tuple[]]]]
+
+  t[0] = default(array[int8, seq[tuple[]]])
+  t[0][0].add ()
+
+block: # #11783
+  proc fun(): string =
+    discard
+
+  var ret: string
+  ret.add fun()
+  doAssert ret == ""
+
+block: # #12256
+  var x: bool
+
+  doAssert x == false
+
+  reset x
+
+  doAssert x == false
+  doAssert x != true
diff --git a/tests/js/tthismangle.nim b/tests/js/tthismangle.nim
new file mode 100644
index 000000000..880abcc83
--- /dev/null
+++ b/tests/js/tthismangle.nim
@@ -0,0 +1,23 @@
+proc moo1(this: int) =
+  doAssert this == 42
+
+proc moo2(x: int) =
+  var this = x
+  doAssert this == 42
+
+proc moo3() =
+  for this in [1,1,1]:
+    doAssert this == 1
+
+proc moo4() =
+  type
+    X = object
+      this: int
+
+  var q = X(this: 42)
+  doAssert q.this == 42
+
+moo1(42)
+moo2(42)
+moo3()
+moo4()
diff --git a/tests/js/ttryexceptnewsyntax.nim b/tests/js/ttryexceptnewsyntax.nim
new file mode 100644
index 000000000..2573c3727
--- /dev/null
+++ b/tests/js/ttryexceptnewsyntax.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''hello'''
+"""
+
+type
+  MyException = ref Exception
+
+#bug #5986
+
+try:
+  raise MyException(msg: "hello")
+except MyException as e:
+  echo e.msg
diff --git a/tests/js/ttypedarray.nim b/tests/js/ttypedarray.nim
new file mode 100644
index 000000000..4807cb103
--- /dev/null
+++ b/tests/js/ttypedarray.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--jsbigint64:off -d:nimStringHash2; --jsbigint64:on"
+"""
+
+import std/private/jsutils
+
+proc main()=
+  template fn(a): untyped = jsConstructorName(a)
+  doAssert fn(array[2, int8].default) == "Int8Array"
+  doAssert fn(array[2, uint8].default) == "Uint8Array"
+  doAssert fn(array[2, byte].default) == "Uint8Array"
+  doAssert fn(array[2, char].default) == "Uint8Array"
+  whenJsNoBigInt64: discard
+  do:
+    doAssert fn(array[2, uint64].default) == "BigUint64Array"
+  doAssert fn([1'u8]) == "Uint8Array"
+  doAssert fn([1'u16]) == "Uint16Array"
+  doAssert fn([byte(1)]) == "Uint8Array"
+  doAssert fn([1.0'f32]) == "Float32Array"
+  doAssert fn(array[2, float32].default) == "Float32Array"
+  doAssert fn(array[2, float].default) == "Float64Array"
+  doAssert fn(array[2, float64].default) == "Float64Array"
+  doAssert fn([1.0]) == "Float64Array"
+  doAssert fn([1.0'f64]) == "Float64Array"
+
+main()
diff --git a/tests/js/tunion.nim b/tests/js/tunion.nim
new file mode 100644
index 000000000..e185495ad
--- /dev/null
+++ b/tests/js/tunion.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "`{.union.}` is not implemented for js backend."
+"""
+
+type Foo {.union.} = object
+  as_bytes: array[8, int8]
+  data: int64
diff --git a/tests/js/tunittest_error.nim b/tests/js/tunittest_error.nim
new file mode 100644
index 000000000..781e34338
--- /dev/null
+++ b/tests/js/tunittest_error.nim
@@ -0,0 +1,24 @@
+discard """
+  exitcode: 1
+  outputsub: "[FAILED] with exception"
+"""
+
+# see also: `tests/stdlib/tunittest_error.nim`
+
+import unittest
+
+proc ddd() =
+  raise newException(IOError, "didn't do stuff")
+
+proc ccc() =
+  ddd()
+
+proc bbb() =
+  ccc()
+
+proc aaa() =
+  bbb()
+
+test "with exception":
+  check 3 == 3
+  aaa()
diff --git a/tests/js/tunittest_error2.nim b/tests/js/tunittest_error2.nim
new file mode 100644
index 000000000..9c5af7529
--- /dev/null
+++ b/tests/js/tunittest_error2.nim
@@ -0,0 +1,16 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+[<foreign exception>]
+[FAILED] Bad test
+  '''
+  matrix: "-d:nodejs"
+  targets: "js"
+  joinable: false
+"""
+
+# bug #16978
+import unittest
+test "Bad test":
+  var x: cstring = nil
+  let y = x[0]
diff --git a/tests/js/tvarargs.nim b/tests/js/tvarargs.nim
new file mode 100644
index 000000000..8d57af58d
--- /dev/null
+++ b/tests/js/tvarargs.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "Hello, world"
+"""
+
+# bug #3584
+
+type
+  ConsoleObj {.importc.} = object of RootObj
+    log*: proc() {.nimcall varargs.}
+  Console = ref ConsoleObj
+
+var console* {.importc.}: Console
+
+when true:
+  console.log "Hello, world"
diff --git a/tests/js/twritestacktrace.nim b/tests/js/twritestacktrace.nim
new file mode 100644
index 000000000..2fe2b1987
--- /dev/null
+++ b/tests/js/twritestacktrace.nim
@@ -0,0 +1,12 @@
+discard """
+  cmd: "nim js --panics:on $file"
+  output: '''Traceback (most recent call last)
+twritestacktrace.nim(12) at module twritestacktrace
+twritestacktrace.nim(10) at twritestacktrace.hello
+'''
+"""
+
+proc hello() =
+  writeStackTrace()
+
+hello()
diff --git a/tests/jsontest.json b/tests/jsontest.json
deleted file mode 100755
index 27b5ba1d1..000000000
--- a/tests/jsontest.json
+++ /dev/null
@@ -1,22 +0,0 @@
-// Simple JSON test file
-// (c) 2009 Andreas Rumpf
-
-/* a long comment */
-
-{
-  "key1": null,
-  "key2": [
-    {},
-    {   },
-    [],
-    
-    [ /* empty array */ ],
-    
-    -1e10 // another comment
-    
-  
-  ]        ,
-  "key3": false
-}
-
-
diff --git a/tests/lent/t16898.nim b/tests/lent/t16898.nim
new file mode 100644
index 000000000..a69c6d244
--- /dev/null
+++ b/tests/lent/t16898.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "invalid type: 'lent QuadraticExt' in this context: 'proc (r: var QuadraticExt, a: lent QuadraticExt, b: lent QuadraticExt){.noSideEffect, gcsafe.}' for proc"
+"""
+
+# bug #16898
+type
+  Fp[N: static int, T] = object
+    big: array[N, T]
+
+type
+  QuadraticExt* = concept x
+    ## Quadratic Extension concept (like complex)
+    type BaseField = auto
+    x.c0 is BaseField
+    x.c1 is BaseField
+
+{.experimental:"views".}
+
+func prod(r: var QuadraticExt, a, b: lent QuadraticExt) =
+  discard
+
+type
+  Fp2[N: static int, T] = object
+    c0, c1: Fp[N, T]
+
+# This should be passed by reference,
+# but concepts do not respect the 24 bytes rule
+# or `byref` pragma.
+var r, a, b: Fp2[6, uint64]
+
+prod(r, a, b)
diff --git a/tests/lent/t17621.nim b/tests/lent/t17621.nim
new file mode 100644
index 000000000..e324a963e
--- /dev/null
+++ b/tests/lent/t17621.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "invalid type: 'lent Test' in this context: 'proc (self: lent Test)' for proc"
+"""
+
+# bug #17621
+{.experimental: "views".}
+
+type Test = ref object
+  foo: int
+
+proc modify(self: lent Test) =
+  self.foo += 1
+
+let test = Test(foo: 12)
+modify(test)
diff --git a/tests/lent/tbasic_lent_check.nim b/tests/lent/tbasic_lent_check.nim
new file mode 100644
index 000000000..ce9b89adf
--- /dev/null
+++ b/tests/lent/tbasic_lent_check.nim
@@ -0,0 +1,62 @@
+discard """
+  targets: "c cpp js"
+  output: "1"
+"""
+
+proc viewInto(a: array[4, string]): lent string =
+  result = a[0]
+
+proc passToVar(x: var string) =
+  discard
+
+proc main =
+  let x = ["1", "2", "3", "4"]
+  echo viewInto(x)
+  doAssert(not compiles(passToVar(viewInto(x))))
+
+main()
+
+template main2 = # bug #15958
+  when defined(js):
+    proc sameAddress[T](a, b: T): bool {.importjs: "(# === #)".}
+  else:
+    template sameAddress(a, b): bool = a.unsafeAddr == b.unsafeAddr
+  proc byLent[T](a: T): lent T = a
+  let a = [11,12]
+  let b = @[21,23]
+  let ss = {1, 2, 3, 5}
+  doAssert byLent(a) == [11,12]
+  doAssert sameAddress(byLent(a), a)
+  doAssert byLent(b) == @[21,23]
+  # bug #16073
+  doAssert sameAddress(byLent(b), b)
+  doAssert byLent(ss) == {1, 2, 3, 5}
+  doAssert sameAddress(byLent(ss), ss)
+
+  let r = new(float)
+  r[] = 10.0
+  # bug #16073
+  doAssert byLent(r)[] == 10.0
+
+  when not defined(js): # pending bug https://github.com/timotheecour/Nim/issues/372
+    let p = create(float)
+    p[] = 20.0
+    doAssert byLent(p)[] == 20.0
+
+  proc byLent2[T](a: openArray[T]): lent T = a[0]
+  doAssert byLent2(a) == 11
+  doAssert sameAddress(byLent2(a), a[0])
+  doAssert byLent2(b) == 21
+  doAssert sameAddress(byLent2(b), b[0])
+
+  proc byLent3[T](a: varargs[T]): lent T = a[1]
+  let 
+    x = 10
+    y = 20
+    z = 30
+  doAssert byLent3(x, y, z) == 20
+
+main2()
+when false:
+  # bug: Error: unhandled exception: 'node' is not accessible using discriminant 'kind' of type 'TFullReg' [FieldDefect]
+  static: main2()
diff --git a/tests/lent/tlent_from_var.nim b/tests/lent/tlent_from_var.nim
new file mode 100644
index 000000000..1fb3d0c17
--- /dev/null
+++ b/tests/lent/tlent_from_var.nim
@@ -0,0 +1,107 @@
+discard """
+  output: '''x
+[10, 11, 12, 13]'''
+"""
+
+# bug #14805
+
+type Foo = object
+  a: string
+
+proc bar(f: var Foo): lent string =
+  result = f.a
+
+var foo = Foo(a: "x")
+echo bar(foo)
+
+
+# bug #14878
+
+# proc byLentImpl[T](a: T): lent T = a
+proc byLentVar[T](a: var T): lent T =
+  result = a
+  # result = a.byLentImpl # this doesn't help
+
+var x = 3 # error: cannot take the address of an rvalue of type 'NI *'
+
+var xs = [10,11,12,13] # SIGSEGV
+
+let x2 = x.byLentVar
+
+let xs2 = xs.byLentVar
+echo xs2
+
+# bug #22138
+
+type Xxx = object
+
+type
+  Opt[T] = object
+    case oResultPrivate*: bool
+    of false:
+      discard
+    of true:
+      vResultPrivate*: T
+
+func value*[T: not void](self: Opt[T]): lent T {.inline.} =
+  self.vResultPrivate
+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/tnot_allowed_lent.nim b/tests/lent/tnot_allowed_lent.nim
new file mode 100644
index 000000000..a1db6d184
--- /dev/null
+++ b/tests/lent/tnot_allowed_lent.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "expression has no address"
+"""
+type
+  MyObject = object
+    x: seq[string]
+
+proc mytest1(s: MyObject, i: int): lent string =
+  ## works fine
+  if i < s.x.len - 1 and s.x[i] != "":
+    result = s.x[i]
+  else: raise newException(KeyError, "err1")
+
+proc mytest2(s: MyObject, i: int): lent string =
+  ## reject due to if expr
+  if i < s.x.len - 1 and s.x[i] != "": s.x[i]
+  else: raise newException(KeyError, "err1")
+
+for i in 1..5:
+  var x = MyObject(x: @["1", "2", "3"])
+  echo mytest1(x, 1)
+  echo mytest2(x, 1)
+
+
diff --git a/tests/lent/tnot_allowed_lent2.nim b/tests/lent/tnot_allowed_lent2.nim
new file mode 100644
index 000000000..d0c958df3
--- /dev/null
+++ b/tests/lent/tnot_allowed_lent2.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "'x' cannot be assigned to"
+  line: 10
+"""
+
+proc bug14498 =
+  var a = @['a', 'b', 'c', 'd', 'e', 'f']
+
+  for x in a:
+    x = 'c'
+
+  echo a
+
+bug14498()
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/let/t7936.nim b/tests/let/t7936.nim
new file mode 100644
index 000000000..3819dfc02
--- /dev/null
+++ b/tests/let/t7936.nim
@@ -0,0 +1,27 @@
+discard """
+  action: "run"
+"""
+
+import
+  tables, deques, sequtils
+
+const
+  lookupTable = {'(': ')', '{': '}', '[': ']'}.toTable
+
+proc isPaired*(value: string): bool =
+  var stack = initDeque[char]() 
+
+  for item in value:
+    # echo "Looking at " & item
+    if item in lookupTable:
+      stack.addLast(item)
+    if item in toSeq(lookupTable.values):
+      if stack.len == 0:
+        return false
+      if lookupTable[stack.popLast()] != item:
+        return false
+
+  return stack.len == 0
+
+doAssert isPaired("{[()]}") == true
+doAssert isPaired("a)b(c") == false
diff --git a/tests/let/timportc.nim b/tests/let/timportc.nim
new file mode 100644
index 000000000..85244da9f
--- /dev/null
+++ b/tests/let/timportc.nim
@@ -0,0 +1,24 @@
+discard """
+targets: "c cpp js"
+"""
+
+when defined(c) or defined(cpp):
+  {.emit:"""
+  const int TEST1 = 123;
+  #define TEST2 321
+  """.}
+
+when defined(js):
+  {.emit:"""
+  const TEST1 = 123;
+  const TEST2 = 321; // JS doesn't have macros, so we just duplicate
+  """.}
+
+let
+  TEST0 = 1
+  TEST1 {.importc, nodecl.}: cint
+  TEST2 {.importc, nodecl.}: cint
+
+doAssert TEST0 == 1
+doAssert TEST1 == 123
+doAssert TEST2 == 321
diff --git a/tests/let/timportc2.nim b/tests/let/timportc2.nim
new file mode 100644
index 000000000..964305923
--- /dev/null
+++ b/tests/let/timportc2.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "'let' symbol requires an initialization"
+  line: "7"
+"""
+
+# Test that this still works when not annotated with importc
+let test: cint
+echo test
diff --git a/tests/let/tlet.nim b/tests/let/tlet.nim
new file mode 100644
index 000000000..25d7b9bf7
--- /dev/null
+++ b/tests/let/tlet.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "'name' cannot be assigned to"
+  line: "10"
+"""
+
+echo("What's your name? ")
+let name = readLine(stdin)
+while name == "":
+  echo("Please tell me your name: ")
+  name = readLine(stdin)
diff --git a/tests/let/tlet2.nim b/tests/let/tlet2.nim
new file mode 100644
index 000000000..63e7d6128
--- /dev/null
+++ b/tests/let/tlet2.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "type mismatch: got <int literal(8), int literal(5), int, int>"
+  line: "13"
+"""
+
+proc divmod(a, b: int, res, remainder: var int) =
+  res = a div b        # integer division
+  remainder = a mod b  # integer modulo operation
+
+let
+  x = 9
+  y = 3
+divmod(8, 5, x, y) # modifies x and y
+echo(x)
+echo(y)
diff --git a/tests/lexer/mlexerutils.nim b/tests/lexer/mlexerutils.nim
new file mode 100644
index 000000000..eae7a0006
--- /dev/null
+++ b/tests/lexer/mlexerutils.nim
@@ -0,0 +1,9 @@
+import macros
+
+macro lispReprStr*(a: untyped): untyped = newLit(a.lispRepr)
+
+macro assertAST*(expected: string, struct: untyped): untyped =
+  var ast = newLit(struct.treeRepr)
+  result = quote do:
+    if `ast` != `expected`:
+      doAssert false, "\nGot:\n" & `ast`.indent(2) & "\nExpected:\n" & `expected`.indent(2)
\ No newline at end of file
diff --git a/tests/lexer/tcustom_numeric_literals.nim b/tests/lexer/tcustom_numeric_literals.nim
new file mode 100644
index 000000000..35b4803d3
--- /dev/null
+++ b/tests/lexer/tcustom_numeric_literals.nim
@@ -0,0 +1,177 @@
+discard """
+  targets: "c cpp js"
+"""
+
+# Test tkStrNumLit
+
+import std/[macros, strutils]
+import mlexerutils
+
+# AST checks
+
+assertAST dedent """
+  StmtList
+    ProcDef
+      AccQuoted
+        Ident "\'"
+        Ident "wrap"
+      Empty
+      Empty
+      FormalParams
+        Ident "string"
+        IdentDefs
+          Ident "number"
+          Ident "string"
+          Empty
+      Empty
+      Empty
+      StmtList
+        Asgn
+          Ident "result"
+          Infix
+            Ident "&"
+            Infix
+              Ident "&"
+              StrLit "[["
+              Ident "number"
+            StrLit "]]"""":
+  proc `'wrap`(number: string): string =
+    result = "[[" & number & "]]"
+
+assertAST dedent """
+  StmtList
+    DotExpr
+      RStrLit "-38383839292839283928392839283928392839283.928493849385935898243e-50000"
+      Ident "\'wrap"""":
+  -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap
+
+proc `'wrap`(number: string): string = "[[" & number & "]]"
+proc wrap2(number: string): string = "[[" & number & "]]"
+doAssert lispReprStr(-1'wrap) == """(DotExpr (RStrLit "-1") (Ident "\'wrap"))"""
+
+template main =
+  block: # basic suffix usage
+    template `'twrap`(number: string): untyped =
+      number.`'wrap`
+    proc extraContext(): string =
+      22.40'wrap
+    proc `*`(left, right: string): string =
+      result = left & "times" & right
+    proc `+`(left, right: string): string =
+      result = left & "plus" & right
+
+    doAssert 1'wrap == "[[1]]"
+    doAssert -1'wrap == "[[-1]]":
+      "unable to resolve a negative integer-suffix pattern"
+    doAssert 12345.67890'wrap == "[[12345.67890]]"
+    doAssert 1'wrap*1'wrap == "[[1]]times[[1]]":
+      "unable to resolve an operator between two suffixed numeric literals"
+    doAssert 1'wrap+ -1'wrap == "[[1]]plus[[-1]]":  # will generate a compiler warning about inconsistent spacing
+      "unable to resolve a negative suffixed numeric literal following an operator"
+    doAssert 1'wrap + -1'wrap == "[[1]]plus[[-1]]"
+    doAssert 1'twrap == "[[1]]"
+    doAssert extraContext() == "[[22.40]]":
+      "unable to return a suffixed numeric literal by an implicit return"
+    doAssert 0x5a3a'wrap == "[[0x5a3a]]"
+    doAssert 0o5732'wrap == "[[0o5732]]"
+    doAssert 0b0101111010101'wrap == "[[0b0101111010101]]"
+    doAssert -38383839292839283928392839283928392839283.928493849385935898243e-50000'wrap == "[[-38383839292839283928392839283928392839283.928493849385935898243e-50000]]"
+    doAssert 1234.56'wrap == "[[1234.56]]":
+      "unable to properly account for context with suffixed numeric literals"
+
+  block: # verify that the i64, f32, etc builtin suffixes still parse correctly
+    const expectedF32: float32 = 123.125
+    proc `'f9`(number: string): string =   # proc starts with 'f' just like 'f32'
+      "[[" & number & "]]"
+    proc `'f32a`(number: string): string =   # looks even more like 'f32'
+      "[[" & number & "]]"
+    proc `'d9`(number: string): string =   # proc starts with 'd' just like the d suffix
+      "[[" & number & "]]"
+    proc `'i9`(number: string): string =   # proc starts with 'i' just like 'i64'
+      "[[" & number & "]]"
+    proc `'u9`(number: string): string =   # proc starts with 'u' just like 'u8'
+      "[[" & number & "]]"
+
+    doAssert 123.125f32 == expectedF32:
+      "failing to support non-quoted legacy f32 floating point suffix"
+    doAssert 123.125'f32 == expectedF32
+    doAssert 123.125e0'f32 == expectedF32
+    doAssert 1234.56'wrap == 1234.56'f9
+    doAssert 1234.56'wrap == 1234.56'f32a
+    doAssert 1234.56'wrap == 1234.56'd9
+    doAssert 1234.56'wrap == 1234.56'i9
+    doAssert 1234.56'wrap == 1234.56'u9
+    doAssert lispReprStr(1234.56'u9) == """(DotExpr (RStrLit "1234.56") (Ident "\'u9"))""":
+      "failed to properly build AST for suffix that starts with u"
+    doAssert -128'i8 == (-128).int8
+
+  block: # case checks
+    doAssert 1E2 == 100:
+      "lexer not handling upper-case exponent"
+    doAssert 1.0E2 == 100.0
+    doAssert 1e2 == 100
+    doAssert 0xdeadBEEF'wrap == "[[0xdeadBEEF]]":
+      "lexer not maintaining original case"
+    doAssert 0.1E12'wrap == "[[0.1E12]]"
+    doAssert 0.0e12'wrap == "[[0.0e12]]"
+    doAssert 0.0e+12'wrap == "[[0.0e+12]]"
+    doAssert 0.0e-12'wrap == "[[0.0e-12]]"
+    doAssert 0e-12'wrap == "[[0e-12]]"
+
+  block: # macro and template usage
+    template `'foo`(a: string): untyped = (a, 2)
+    doAssert -12'foo == ("-12", 2)
+    template `'fooplus`(a: string, b: int): untyped = (a, b)
+    doAssert -12'fooplus(2) == ("-12", 2)
+    template `'fooplusopt`(a: string, b: int = 99): untyped = (a, b)
+    doAssert -12'fooplusopt(2) == ("-12", 2)
+    doAssert -12'fooplusopt() == ("-12", 99)
+    doAssert -12'fooplusopt == ("-12", 99)
+    macro `'bar`(a: static string): untyped = newLit(a.repr)
+    doAssert -12'bar == "\"-12\""
+    macro deb(a): untyped = newLit(a.repr)
+    doAssert deb(-12'bar) == "-12'bar"
+
+  block: # bug 1 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+    macro deb1(a): untyped = newLit a.repr
+    macro deb2(a): untyped =
+      a[1] = ident($a[1])
+      newLit a.lispRepr
+    doAssert deb1(-12'wrap) == "-12'wrap"
+    doAssert deb1(-12'nonexistent) == "-12'nonexistent"
+    doAssert deb2(-12'nonexistent) == """(DotExpr (RStrLit "-12") (Ident "\'nonexistent"))"""
+    doAssert deb2(-12.wrap2) == """(DotExpr (IntLit -12) (Ident "wrap2"))"""
+    doAssert deb2(-12'wrap) == """(DotExpr (RStrLit "-12") (Ident "\'wrap"))"""
+
+  block: # bug 2 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+    template toSuf(`'suf`): untyped =
+      let x = -12'suf
+      x
+    doAssert toSuf(`'wrap`) == "[[-12]]"
+
+  block: # bug 10 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+    proc `myecho`(a: auto): auto = a
+    template fn1(): untyped =
+      let a = "abc"
+      -12'wrap
+    template fn2(): untyped =
+      `myecho` -12'wrap
+    template fn3(): untyped =
+      -12'wrap
+    doAssert fn1() == "[[-12]]"
+    doAssert fn2() == "[[-12]]"
+    doAssert fn3() == "[[-12]]"
+
+    block: # bug 9 from https://github.com/nim-lang/Nim/pull/17020#issuecomment-803193947
+      macro metawrap(): untyped =
+        func wrap1(a: string): string = "{" & a & "}"
+        func `'wrap3`(a: string): string = "{" & a & "}"
+        result = quote do:
+          let a1 {.inject.} = wrap1"-128"
+          let a2 {.inject.} = -128'wrap3
+      metawrap()
+      doAssert a1 == "{-128}"
+      doAssert a2 == "{-128}"
+
+static: main()
+main()
diff --git a/tests/tident.nim b/tests/lexer/tident.nim
index 1ed9894c6..e5177436d 100755..100644
--- a/tests/tident.nim
+++ b/tests/lexer/tident.nim
@@ -1,12 +1,25 @@
+discard """
+output: '''
+Length correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+Correct
+'''
+"""
 
 type
-  TIdObj* = object of TObject

-    id*: int                  # unique id; use this for comparisons and not the pointers

-  

-  PIdObj* = ref TIdObj

-  PIdent* = ref TIdent

-  TIdent*{.acyclic.} = object

-    s*: string

+  TIdObj* = object of RootObj
+    id*: int                  # unique id; use this for comparisons and not the pointers
+
+  PIdObj* = ref TIdObj
+  PIdent* = ref TIdent
+  TIdent*{.acyclic.} = object
+    s*: string
 
 proc myNewString(L: int): string {.inline.} =
   result = newString(L)
@@ -15,8 +28,7 @@ proc myNewString(L: int): string {.inline.} =
   for i in 0..L-1:
     if result[i] == '\0':
       echo("Correct")
-    else: 
+    else:
       echo("Wrong")
-  
-var s = myNewString(8)
 
+var s = myNewString(8)
diff --git a/tests/lexer/tind1.nim b/tests/lexer/tind1.nim
new file mode 100644
index 000000000..2185c3074
--- /dev/null
+++ b/tests/lexer/tind1.nim
@@ -0,0 +1,25 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 24
+"""
+
+import macros
+
+# finally optional indentation in 'if' expressions :-):
+var x = if 4 != 5:
+    "yes"
+  else:
+    "no"
+
+macro mymacro(n, b): untyped =
+  discard
+
+mymacro:
+  echo "test"
+else:
+  echo "else part"
+
+if 4 == 3:
+  echo "bug"
+  else:
+  echo "no bug"
diff --git a/tests/lexer/tindent1.nim b/tests/lexer/tindent1.nim
new file mode 100644
index 000000000..78a303783
--- /dev/null
+++ b/tests/lexer/tindent1.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''Success'''
+"""
+
+const romanNumbers1 =
+    [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1) ]
+
+const romanNumbers2 =
+    [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1)
+    ]
+
+const romanNumbers3 =
+  [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1)
+  ]
+
+const romanNumbers4 = [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1)
+    ]
+
+
+proc main =
+  var j = 0
+  while j < 10:
+    inc(j);
+
+  if j == 5: doAssert false
+
+var j = 0
+while j < 10:
+  inc(j);
+
+if j == 5: doAssert false
+
+main()
+echo "Success"
diff --git a/tests/lexer/tintegerliterals.nim b/tests/lexer/tintegerliterals.nim
new file mode 100644
index 000000000..fd401b71b
--- /dev/null
+++ b/tests/lexer/tintegerliterals.nim
@@ -0,0 +1,9 @@
+# test the valid literals
+doAssert 0b10 == 2
+doAssert 0B10 == 2
+doAssert 0x10 == 16
+doAssert 0X10 == 16
+doAssert 0o10 == 8
+# the following is deprecated:
+doAssert 0c10 == 8
+doAssert 0C10 == 8
diff --git a/tests/lexer/tinvalidintegerliteral1.nim b/tests/lexer/tinvalidintegerliteral1.nim
new file mode 100644
index 000000000..6bf7624f3
--- /dev/null
+++ b/tests/lexer/tinvalidintegerliteral1.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "invalid number"
+  file: "tinvalidintegerliteral1.nim"
+  line: 7
+"""
+
+echo 0b
diff --git a/tests/lexer/tinvalidintegerliteral2.nim b/tests/lexer/tinvalidintegerliteral2.nim
new file mode 100644
index 000000000..eb6efc131
--- /dev/null
+++ b/tests/lexer/tinvalidintegerliteral2.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "invalid number"
+  file: "tinvalidintegerliteral2.nim"
+  line: 7
+"""
+
+echo 0x
diff --git a/tests/lexer/tinvalidintegerliteral3.nim b/tests/lexer/tinvalidintegerliteral3.nim
new file mode 100644
index 000000000..e09cda54a
--- /dev/null
+++ b/tests/lexer/tinvalidintegerliteral3.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "0O5 is an invalid int literal; For octal literals use the '0o' prefix."
+  file: "tinvalidintegerliteral3.nim"
+  line: 7
+"""
+
+echo 0O5
diff --git a/tests/scantest.nim b/tests/lexer/tlexer.nim
index c9779c762..e36220e7a 100755..100644
--- a/tests/scantest.nim
+++ b/tests/lexer/tlexer.nim
@@ -1,62 +1,60 @@
-# We start with a comment

-# This is the same comment

-

-# This is a new one!

-

-# This should not be allowed!

-

-export

-main

-

-import

-  lexbase, os, strutils

-

-type

-  TMyRec {.final.} = object

-    x, y: int     # coordinates

-    c: char       # a character

-    a: int32      # an integer

-

-  PMyRec = ref TMyRec # a reference to `TMyRec`

-

-proc splitText(txt: string): seq[string] # splits a text into several lines

-                                         # the comment continues here

-                                         # this is not easy to parse!

-

-proc anotherSplit(txt: string): list[string] =

-  # the comment should belong to `anotherSplit`!

-  # another problem: comments are statements!

-

-const

-  x = 0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64 # x ~~ 1.72826e35

-  myNan = 0B01111111100000101100000000001000'f32 # NAN

-  y = """

-    a rather long text.

-    Over many

-    lines.

-  """

-  s = "\xff"

-  a = {0..234}

-  b = {0..high(int)}

-  v = 0'i32

-  z = 6767566'f32

-

-# small test program for lexbase

-

-proc main*(infile: string, a, b: int, someverylongnamewithtype = 0,

-           anotherlongthingie = 3) =

-  var

-    myInt: int = 0

-    a b = 9

-    s: sequence[string]

-  # this should be an error!

-  if initBaseLexer(L, infile, 30): nil

-  else:

-    writeln(stdout, "could not open: " & infile)

-  writeln(stdout, "Success!")

-  call(3, # we use 3

-       12, # we use 12

-       43 # we use 43

-       )

-

-main(ParamStr(1))

+discard """
+  disabled: true
+"""
+
+# We start with a comment
+# This is the same comment
+
+# This is a new one!
+
+import
+  lexbase, os, strutils
+
+type
+  TMyRec {.final.} = object
+    x, y: int     # coordinates
+    c: char       # a character
+    a: int32      # an integer
+
+  PMyRec = ref TMyRec # a reference to `TMyRec`
+
+proc splitText(txt: string): seq[string] # splits a text into several lines
+                                         # the comment continues here
+                                         # this is not easy to parse!
+
+proc anotherSplit(txt: string): seq[string] =
+  # the comment should belong to `anotherSplit`!
+  # another problem: comments are statements!
+
+const
+  x = 0B0_10001110100_0000101001000111101011101111111011000101001101001001'f64 # x ~~ 1.72826e35
+  myNan = 0B01111111100000101100000000001000'f32 # NAN
+  y = """
+    a rather long text.
+    Over many
+    lines.
+  """
+  s = "\xff"
+  a = {0..234}
+  b = {0..high(int)}
+  v = 0'i32
+  z = 6767566'f32
+
+# small test program for lexbase
+
+proc main*(infile: string, a, b: int, someverylongnamewithtype = 0,
+           anotherlongthingie = 3) =
+  var
+    myInt: int = 0
+    s: seq[string]
+  # this should be an error!
+  if initBaseLexer(L, infile, 30): nil
+  else:
+    writeLine(stdout, "could not open: " & infile)
+  writeLine(stdout, "Success!")
+  call(3, # we use 3
+       12, # we use 12
+       43) # we use 43
+
+
+main(ParamStr(1), 9, 0)
diff --git a/tests/lexer/tlexermisc.nim b/tests/lexer/tlexermisc.nim
new file mode 100644
index 000000000..3e3993599
--- /dev/null
+++ b/tests/lexer/tlexermisc.nim
@@ -0,0 +1,27 @@
+discard """
+  action: run
+  output: "equal"
+"""
+
+var t=0x950412DE
+
+if t==0x950412DE:
+    echo "equal"
+else:
+    echo "not equal"
+
+type
+  TArray = array[0x0012..0x0013, int]
+
+var a: TArray
+
+doAssert a[0x0012] == 0
+
+
+# #7884
+
+type Obj = object
+    ö: int
+
+let o = Obj(ö: 1)
+doAssert o.ö == 1
diff --git a/tests/lexer/tlexerspaces.nim b/tests/lexer/tlexerspaces.nim
new file mode 100644
index 000000000..14b16111d
--- /dev/null
+++ b/tests/lexer/tlexerspaces.nim
@@ -0,0 +1,2 @@
+discard 12 +                                                                                                                                                                                                                                                                           5
+discard 12 + 5                                                                                                                        
diff --git a/tests/lexer/tmissingnl.nim b/tests/lexer/tmissingnl.nim
new file mode 100644
index 000000000..dc939bcd2
--- /dev/null
+++ b/tests/lexer/tmissingnl.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "invalid indentation"
+  file: "tmissingnl.nim"
+  line: 7
+"""
+
+import strutils let s: seq[int] = @[0, 1, 2, 3, 4, 5, 6]
+
+#s[1..3] = @[]
diff --git a/tests/trawstr.nim b/tests/lexer/trawstr.nim
index 7b2db0335..aa41071d5 100755..100644
--- a/tests/trawstr.nim
+++ b/tests/lexer/trawstr.nim
@@ -1,5 +1,10 @@
-# Test the new raw strings:

-

-const

-  xxx = r"This is a raw string!"

-  yyy = "This not\" #ERROR

+discard """
+  errormsg: "closing \" expected"
+  file: "trawstr.nim"
+  line: 10
+"""
+# Test the new raw strings:
+
+const
+  xxx = r"This is a raw string!"
+  yyy = "This not\" #ERROR
diff --git a/tests/lexer/tstrlits.nim b/tests/lexer/tstrlits.nim
new file mode 100644
index 000000000..8e8250a5b
--- /dev/null
+++ b/tests/lexer/tstrlits.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "a\"\"long string\"\"\"\"\"abc\"def_'2'â—ðŒ†ðŒ†A"
+"""
+# Test the new different string literals
+
+const
+  tripleEmpty = """"long string"""""""" # "long string """""
+
+  rawQuote = r"a"""
+
+  raw = r"abc""def"
+
+  escaped = "\x5f'\50'\u25cf\u{1D306}\u{1d306}\u{41}"
+
+
+stdout.write(rawQuote)
+stdout.write(tripleEmpty)
+stdout.write(raw)
+stdout.writeLine(escaped)
diff --git a/tests/lexer/tunary_minus.nim b/tests/lexer/tunary_minus.nim
new file mode 100644
index 000000000..5ec2b5c70
--- /dev/null
+++ b/tests/lexer/tunary_minus.nim
@@ -0,0 +1,83 @@
+discard """
+  targets: "c cpp js"
+"""
+
+# Test numeric literals and handling of minus symbol
+
+import std/[macros, strutils]
+import std/private/jsutils
+
+import mlexerutils
+
+const one = 1
+const minusOne = `-`(one)
+
+# border cases that *should* generate compiler errors:
+assertAST dedent """
+  StmtList
+    Asgn
+      Ident "x"
+      Command
+        IntLit 4
+        IntLit -1""":
+  x = 4 -1
+assertAST dedent """
+  StmtList
+    VarSection
+      IdentDefs
+        Ident "x"
+        Ident "uint"
+        IntLit -1""":
+  var x: uint = -1
+template bad() =
+  x = 4 -1
+doAssert not compiles(bad())
+
+template main =
+  block: # check when a minus (-) is a negative sign for a literal
+    doAssert -1 == minusOne:
+      "unable to parse a spaced-prefixed negative int"
+    doAssert lispReprStr(-1) == """(IntLit -1)"""
+    doAssert -1.0'f64 == minusOne.float64
+    doAssert lispReprStr(-1.000'f64) == """(Float64Lit -1.0)"""
+    doAssert lispReprStr( -1.000'f64) == """(Float64Lit -1.0)"""
+    doAssert [-1].contains(minusOne):
+      "unable to handle negatives after square bracket"
+    doAssert lispReprStr([-1]) == """(Bracket (IntLit -1))"""
+    doAssert (-1, 2)[0] == minusOne:
+      "unable to handle negatives after parenthesis"
+    doAssert lispReprStr((-1, 2)) == """(TupleConstr (IntLit -1) (IntLit 2))"""
+    proc x(): int =
+      var a = 1;-1  # the -1 should act as the return value
+    doAssert x() == minusOne:
+      "unable to handle negatives after semi-colon"
+
+  block:
+    doAssert -0b111 == -7
+    doAssert -0xff == -255
+    doAssert -128'i8 == (-128).int8
+    doAssert $(-128'i8) == "-128"
+    doAssert -32768'i16 == int16.low
+    doAssert -2147483648'i32 == int32.low
+    when int.sizeof > 4:
+      doAssert -9223372036854775808 == int.low
+    whenJsNoBigInt64: discard
+    do:
+      doAssert -9223372036854775808 == int64.low
+
+  block: # check when a minus (-) is an unary op
+    doAssert -one == minusOne:
+      "unable to a negative prior to identifier"
+
+  block: # check when a minus (-) is a a subtraction op
+    doAssert 4-1 == 3:
+      "unable to handle subtraction sans surrounding spaces with a numeric literal"
+    doAssert 4-one == 3:
+      "unable to handle subtraction sans surrounding spaces with an identifier"
+    doAssert 4 - 1 == 3:
+      "unable to handle subtraction with surrounding spaces with a numeric literal"
+    doAssert 4 - one == 3:
+      "unable to handle subtraction with surrounding spaces with an identifier"
+
+static: main()
+main()
diff --git a/tests/lexer/tunderscores.nim b/tests/lexer/tunderscores.nim
new file mode 100644
index 000000000..1896a2898
--- /dev/null
+++ b/tests/lexer/tunderscores.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "invalid token: trailing underscore"
+  file: "tunderscores.nim"
+  line: 8
+"""
+# Bug #502670
+
+var ef_ = 3  #ERROR_MSG invalid token: _
+var a__b = 1
+var c___d = 2
+echo(ab, cd, ef_)
diff --git a/tests/lexer/tunicode_operators.nim b/tests/lexer/tunicode_operators.nim
new file mode 100644
index 000000000..6ad40beab
--- /dev/null
+++ b/tests/lexer/tunicode_operators.nim
@@ -0,0 +1,16 @@
+#{.experimental: "unicodeOperators".}
+
+proc `⊙`(x, y: int): int = x * y
+proc `⊙=`(x: var int, y: int) = x *= y
+
+proc `⊞++`(x, y: int): int = x + y
+
+const a = 9
+
+var x = 45
+x ⊙= a⊞++4⊙3
+
+var y = 45
+y *= 9 + 4 * 3
+
+assert x == y
diff --git a/tests/lookups/issue_23032/deep_scope.nim b/tests/lookups/issue_23032/deep_scope.nim
new file mode 100644
index 000000000..3e25809a7
--- /dev/null
+++ b/tests/lookups/issue_23032/deep_scope.nim
@@ -0,0 +1,2 @@
+type A*[T] = object
+proc foo*(a: A[int]): bool = false
diff --git a/tests/lookups/issue_23172/m23172.nim b/tests/lookups/issue_23172/m23172.nim
new file mode 100644
index 000000000..36af48761
--- /dev/null
+++ b/tests/lookups/issue_23172/m23172.nim
@@ -0,0 +1,6 @@
+type
+  Foo* = object
+  Bar* = object
+
+func `$`*(x: Foo | Bar): string =
+  "X"
diff --git a/tests/mambsym1.nim b/tests/lookups/mambsym1.nim
index cf8ac5242..c4902b1b4 100755..100644
--- a/tests/mambsym1.nim
+++ b/tests/lookups/mambsym1.nim
@@ -1,10 +1,10 @@
-import mambsym2 # import TExport

-

-type

-  TExport* = enum x, y, z

-  TOtherEnum* = enum mDec, mInc, mAssign

-

-proc ha() =

-  var

-    x: TExport # no error

-  nil

+import mambsym2 # import TExport
+
+type
+  TExport* = enum x, y, z
+  TOtherEnum* = enum mDec, mInc, mAssign
+
+proc ha() =
+  var
+    x: TExport # no error
+  discard
diff --git a/tests/mambsym2.nim b/tests/lookups/mambsym2.nim
index eac8de6ba..21d980073 100755..100644
--- a/tests/mambsym2.nim
+++ b/tests/lookups/mambsym2.nim
@@ -1,3 +1,3 @@
-type

-  TExport* = enum a, b, c

-  

+type
+  TExport* = enum a, b, c
+
diff --git a/tests/lookups/mambsym3.nim b/tests/lookups/mambsym3.nim
new file mode 100644
index 000000000..946a5ff29
--- /dev/null
+++ b/tests/lookups/mambsym3.nim
@@ -0,0 +1,4 @@
+# Module A
+var x*: string
+proc foo*(a: string) =
+  echo "A: ", a
diff --git a/tests/lookups/mambsym4.nim b/tests/lookups/mambsym4.nim
new file mode 100644
index 000000000..ed66cc16d
--- /dev/null
+++ b/tests/lookups/mambsym4.nim
@@ -0,0 +1,4 @@
+# Module B
+var x*: int
+proc foo*(b: int) =
+  echo "B: ", b
diff --git a/tests/mambsys1.nim b/tests/lookups/mambsys1.nim
index 5472b5ae4..22e54cb94 100755..100644
--- a/tests/mambsys1.nim
+++ b/tests/lookups/mambsys1.nim
@@ -1,7 +1,7 @@
-import mambsys2 # import TExport

-

-type

-  TExport* = enum x, y, z

-

-proc foo*(x: int) =

-  nil

+import mambsys2 # import TExport
+
+type
+  TExport* = enum x, y, z
+
+proc foo*(x: int) =
+  discard
diff --git a/tests/mambsys2.nim b/tests/lookups/mambsys2.nim
index 395425b86..ef63e4f7e 100755..100644
--- a/tests/mambsys2.nim
+++ b/tests/lookups/mambsys2.nim
@@ -1,4 +1,4 @@
-type

-  TExport* = enum x, y, z # exactly the same type!

-

-proc foo*(x: int) = nil

+type
+  TExport* = enum x, y, z # exactly the same type!
+
+proc foo*(x: int) = discard
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/mbind3.nim b/tests/lookups/mbind3.nim
new file mode 100644
index 000000000..1a7d3b63b
--- /dev/null
+++ b/tests/lookups/mbind3.nim
@@ -0,0 +1,10 @@
+# Module A
+var
+  lastId = 0
+
+template genId*: int =
+  bind lastId
+  inc(lastId)
+  lastId
+
+
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/t23032.nim b/tests/lookups/t23032.nim
new file mode 100644
index 000000000..144abcb05
--- /dev/null
+++ b/tests/lookups/t23032.nim
@@ -0,0 +1,13 @@
+discard """
+action: "run"
+outputsub: "proc (a: A[system.float]): bool{.noSideEffect, gcsafe.}"
+"""
+
+import issue_23032/deep_scope
+
+proc foo(a: A[float]):bool = true
+
+let p: proc = foo
+echo p.typeof
+doAssert p(A[float]()) == true
+doAssert compiles(doAssert p(A[int]()) == true) == false
diff --git a/tests/lookups/t23172.nim b/tests/lookups/t23172.nim
new file mode 100644
index 000000000..9edf9905a
--- /dev/null
+++ b/tests/lookups/t23172.nim
@@ -0,0 +1,9 @@
+import issue_23172/m23172
+
+type FooX = distinct Foo
+
+func `$`*(x: FooX): string =
+  $m23172.Foo(x)
+
+var a: FooX
+doAssert $a == "X"
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/tambiguousemit.nim b/tests/lookups/tambiguousemit.nim
new file mode 100644
index 000000000..4f4bacce4
--- /dev/null
+++ b/tests/lookups/tambiguousemit.nim
@@ -0,0 +1,12 @@
+discard """
+  cmd: "nim check $options $file" # use check to assure error is pre-codegen
+  matrix: "; --backend:js" # backend shouldn't matter but at least check js
+"""
+
+proc foo(x: int) = discard
+proc foo(x: float) = discard
+
+{.emit: ["// ", foo].} #[tt.Error
+                ^ ambiguous identifier: 'foo' -- use one of the following:
+  tambiguousemit.foo: proc (x: int){.noSideEffect, gcsafe.}
+  tambiguousemit.foo: proc (x: float){.noSideEffect, gcsafe.}]#
diff --git a/tests/lookups/tambprocvar.nim b/tests/lookups/tambprocvar.nim
new file mode 100644
index 000000000..f5c3fde4f
--- /dev/null
+++ b/tests/lookups/tambprocvar.nim
@@ -0,0 +1,19 @@
+discard """
+  action: reject
+  cmd: "nim check $file"
+  nimout: '''
+tambprocvar.nim(15, 11) Error: ambiguous identifier: 'foo' -- use one of the following:
+  tambprocvar.foo: proc (x: int){.noSideEffect, gcsafe.}
+  tambprocvar.foo: proc (x: float){.noSideEffect, gcsafe.}
+'''
+"""
+
+block:
+  proc foo(x: int) = discard
+  proc foo(x: float) = discard
+
+  let x = foo
+
+block:
+  let x = `+` #[tt.Error
+          ^ ambiguous identifier: '+' -- use one of the following:]#
diff --git a/tests/tambsym.nim b/tests/lookups/tambsym.nim
index b8eae3ba3..bd0f41717 100755..100644
--- a/tests/tambsym.nim
+++ b/tests/lookups/tambsym.nim
@@ -1,8 +1,13 @@
-# Test ambiguous symbols

-

-import mambsym1, mambsym2

-

-var

-  v: TExport #ERROR_MSG ambiguous identifier

-

-v = y

+discard """
+  errormsg: "ambiguous identifier"
+  file: "tambsym.nim"
+  line: 11
+"""
+# Test ambiguous symbols
+
+import mambsym1, mambsym2
+
+var
+  v: TExport #ERROR_MSG ambiguous identifier
+
+v = y
diff --git a/tests/tambsym2.nim b/tests/lookups/tambsym2.nim
index 9178182aa..747f1a086 100755..100644
--- a/tests/tambsym2.nim
+++ b/tests/lookups/tambsym2.nim
@@ -1,15 +1,18 @@
+discard """
+  output: "7"
+"""
 # Test overloading of procs with locals
 
 type
   TMyType = object
     len: int
     data: string
-    
+
 proc len(x: TMyType): int {.inline.} = return x.len
 
-proc x(s: TMyType, len: int) = 
-  writeln(stdout, len(s))
-  
+proc x(s: TMyType, len: int) =
+  writeLine(stdout, len(s))
+
 var
   m: TMyType
 m.len = 7
diff --git a/tests/lookups/tambsym3.nim b/tests/lookups/tambsym3.nim
new file mode 100644
index 000000000..6bbebca10
--- /dev/null
+++ b/tests/lookups/tambsym3.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "ambiguous identifier: 'mDec' -- use one of the following:"
+  file: "tambsym3.nim"
+  line: 11
+"""
+# Test ambiguous symbols
+
+import mambsym1, times
+
+var
+  v = mDec #ERROR_MSG ambiguous identifier
+
+writeLine(stdout, ord(v))
diff --git a/tests/lookups/tambsymmanual.nim b/tests/lookups/tambsymmanual.nim
new file mode 100644
index 000000000..3ad91b8cc
--- /dev/null
+++ b/tests/lookups/tambsymmanual.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''
+A: abc
+B: 123
+A: def
+4
+'''
+"""
+# Module C
+import mambsym3, mambsym4
+
+foo("abc") # A: abc
+foo(123) # B: 123
+let inferred: proc (x: string) = foo
+foo("def") # A: def
+
+doAssert not compiles(write(stdout, x)) # error: x is ambiguous
+write(stdout, mambsym3.x) # no error: qualifier used
+
+proc bar(a: int): int = a + 1
+doAssert bar(x) == x + 1 # no error: only A.x of type int matches
+
+var x = 4
+write(stdout, x) # not ambiguous: uses the module C's x
+echo() # for test output
diff --git a/tests/tambsys.nim b/tests/lookups/tambsys.nim
index bb2622824..aa740c38f 100755..100644
--- a/tests/tambsys.nim
+++ b/tests/lookups/tambsys.nim
@@ -1,7 +1,10 @@
-# Test ambiguous symbols

-

-import mambsys1, mambsys2

-

-var

-  v: mambsys1.TExport

-mambsys2.foo(3) #OUT

+discard """
+  output: ""
+"""
+# Test ambiguous symbols
+
+import mambsys1, mambsys2
+
+var
+  v: mambsys1.TExport
+mambsys2.foo(3) #OUT
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/tbind.nim b/tests/lookups/tbind.nim
new file mode 100644
index 000000000..f3fb952e3
--- /dev/null
+++ b/tests/lookups/tbind.nim
@@ -0,0 +1,78 @@
+discard """
+output: '''
+3
+1
+1
+1
+5
+'''
+"""
+
+
+block tbind:
+# Test the new ``bind`` keyword for templates
+
+  proc p1(x: int8, y: int): int = return x + y
+
+  template tempBind(x, y): untyped =
+    bind p1
+    p1(x, y)
+
+  proc p1(x: int, y: int8): int = return x - y
+
+  # This is tricky: the call to ``p1(1'i8, 2'i8)`` should not fail in line 6,
+  # because it is not ambiguous there. But it is ambiguous after line 8.
+
+  echo tempBind(1'i8, 2'i8) #OUT 3
+
+
+import mbind3
+echo genId() #OUT 1
+
+
+import strtabs
+block tbinoverload:
+  template t() =
+    block:
+      bind newStringTable
+      discard {"Content-Type": "text/html"}.newStringTable()
+
+      discard {:}.newStringTable
+  #discard {"Content-Type": "text/html"}.newStringTable()
+  t()
+
+
+block tmixin:
+  type
+    TFoo1 = object of RootObj
+      v: int
+    TFoo2 = object of TFoo1
+      v2: int
+
+  proc test(f: TFoo1) =
+    echo "1"
+
+  proc Foo[T](f: T) =
+    mixin test
+    test(f)
+
+  var
+    a: TFoo1
+    b: TFoo2
+
+
+  proc test(f: TFoo2) =
+    echo "2"
+
+  Foo(a)
+  Foo(b)
+
+# issue #11811
+proc p(a : int) =
+  echo a
+
+proc printVar*[T:int|float|string](a : T) =
+  bind p
+  p(a)
+
+printVar(5)
diff --git a/tests/lookups/tbind_for_generics.nim b/tests/lookups/tbind_for_generics.nim
new file mode 100644
index 000000000..db5fbebbc
--- /dev/null
+++ b/tests/lookups/tbind_for_generics.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "type mismatch: got <Foo, Foo>"
+  line: 8
+"""
+proc g[T](x: T) =
+  bind `+`
+  # because we bind `+` here, we must not find the `+` for 'Foo' below:
+  echo x + x
+
+type
+  Foo = object
+    a: int
+
+proc `+`(a, b: Foo): Foo = Foo(a: a.a+b.a)
+
+g(3)
+g(Foo(a: 8))
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/test.nim b/tests/lookups/test.nim
new file mode 100644
index 000000000..dfacaf5b5
--- /dev/null
+++ b/tests/lookups/test.nim
@@ -0,0 +1,23 @@
+discard """
+output: '''
+
+[Suite] memoization
+'''
+"""
+
+# This file needs to be called 'test' nim to provoke a clash
+# with the unittest.test name. Issue #
+
+import unittest, macros
+
+# bug #4555
+
+macro memo(n: untyped) =
+  result = n
+
+proc fastFib(n: int): int {.memo.} = 40
+proc fib(n: int): int = 40
+
+suite "memoization":
+  test "recursive function memoization":
+    check fastFib(40) == fib(40)
diff --git a/tests/lookups/tgensym.nim b/tests/lookups/tgensym.nim
new file mode 100644
index 000000000..e33a2783f
--- /dev/null
+++ b/tests/lookups/tgensym.nim
@@ -0,0 +1,16 @@
+discard """
+  output: "123100"
+"""
+
+template hygienic(val) =
+  var x = val
+  stdout.write x
+
+var x = 100
+
+hygienic 1
+hygienic 2
+hygienic 3
+
+echo x
+
diff --git a/tests/lookups/tgensymgeneric.nim b/tests/lookups/tgensymgeneric.nim
new file mode 100644
index 000000000..6e1df4842
--- /dev/null
+++ b/tests/lookups/tgensymgeneric.nim
@@ -0,0 +1,54 @@
+discard """
+  output: '''true'''
+"""
+
+# We need to open the gensym'ed symbol again so that the instantiation
+# creates a fresh copy; but this is wrong the very first reason for gensym
+# is that scope rules cannot be used! So simply removing 'sfGenSym' does
+# not work. Copying the symbol does not work either because we're already
+# the owner of the symbol! What we need to do is to copy the symbol
+# in the generic instantiation process...
+
+type
+  TA = object
+    x: int
+  TB = object
+    x: string
+
+template genImpl() =
+  var gensymed: T
+  when T is TB:
+    gensymed.x = "abc"
+  else:
+    gensymed.x = 123
+  result = move gensymed
+
+proc gen[T](x: T): T =
+  genImpl()
+
+var
+  a: TA
+  b: TB
+let x = gen(a)
+let y = gen(b)
+
+doAssert x.x == 123
+doAssert y.x == "abc"
+
+# test symbol equality
+
+import macros
+
+static:
+  let sym1 = genSym()
+  let sym2 = genSym()
+  let sym3 = sym1
+  let nimsym = sym1.symbol
+  doAssert sym1 == sym1
+  doAssert sym2 != sym3
+  doAssert sym2.symbol != sym3.symbol
+  doAssert sym3 == sym1
+  doAssert sym1.symbol == sym1.symbol
+  doAssert nimsym == nimsym
+
+echo "true"
diff --git a/tests/lookups/tinvalidbindtypedesc.nim b/tests/lookups/tinvalidbindtypedesc.nim
new file mode 100644
index 000000000..1c71c8daf
--- /dev/null
+++ b/tests/lookups/tinvalidbindtypedesc.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <typedesc[float], string>"
+  line: 10
+"""
+
+proc foo(T: typedesc; some: T) =
+  echo($some)
+
+foo int, 4
+foo float, "bad"
diff --git a/tests/lookups/tkoeniglookup.nim b/tests/lookups/tkoeniglookup.nim
new file mode 100644
index 000000000..8b140cceb
--- /dev/null
+++ b/tests/lookups/tkoeniglookup.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''x: 0 y: 0'''
+"""
+
+proc toString*[T](x: T): string = return $x
+
+
+type
+  TMyObj = object
+    x, y: int
+
+proc `$`*(a: TMyObj): string =
+  result = "x: " & $a.x & " y: " & $a.y
+
+var a: TMyObj
+echo toString(a)
+
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/lookups/tnicerrorforsymchoice.nim b/tests/lookups/tnicerrorforsymchoice.nim
new file mode 100644
index 000000000..6001b6b09
--- /dev/null
+++ b/tests/lookups/tnicerrorforsymchoice.nim
@@ -0,0 +1,23 @@
+discard """
+  errormsg: "type mismatch: got <proc (s: TScgi: ScgiState or AsyncScgiState) | proc (client: AsyncSocket, headers: StringTableRef, input: string){.noSideEffect, gcsafe.}>"
+  line: 23
+"""
+
+# Fake ScgiState objects, from now-deprecated scgi module
+type
+  ScgiState* = object of RootObj ## SCGI state object
+  AsyncScgiState* = object of RootObj ## SCGI state object
+
+#bug #442
+import asyncnet, strtabs
+proc handleSCGIRequest[TScgi: ScgiState | AsyncScgiState](s: TScgi) =
+  discard
+proc handleSCGIRequest(client: AsyncSocket, headers: StringTableRef,
+                       input: string) =
+  discard
+
+proc test(handle: proc (client: AsyncSocket, headers: StringTableRef,
+                        input: string), b: int) =
+  discard
+
+test(handleSCGIRequest)
diff --git a/tests/lookups/told_bind_expr.nim b/tests/lookups/told_bind_expr.nim
new file mode 100644
index 000000000..56389eaf6
--- /dev/null
+++ b/tests/lookups/told_bind_expr.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "ambiguous call"
+  file: "told_bind_expr.nim"
+  line: 13
+"""
+
+# Pre-0.9 deprecated bind expression syntax
+
+proc p1(x: int8, y: int): int = return x + y
+proc p1(x: int, y: int8): int = return x - y
+
+template tempBind(x, y): untyped =
+  (bind p1(x, y))  #ERROR_MSG ambiguous call
+
+echo tempBind(1'i8, 2'i8)
diff --git a/tests/lookups/tredef.nim b/tests/lookups/tredef.nim
new file mode 100644
index 000000000..7c1df238e
--- /dev/null
+++ b/tests/lookups/tredef.nim
@@ -0,0 +1,29 @@
+template foo(a: int, b: string) = discard
+foo(1, "test")
+
+proc bar(a: int, b: string) = discard
+bar(1, "test")
+
+template foo(a: int, b: string) {.redefine.} = bar(a, b)
+foo(1, "test")
+
+block:
+  proc bar(a: int, b: string) = discard
+  template foo(a: int, b: string) = discard
+  foo(1, "test")
+  bar(1, "test")
+
+proc baz =
+  proc foo(a: int, b: string) = discard
+  proc foo(b: string) =
+    template bar(a: int, b: string) = discard
+    bar(1, "test")
+
+  foo("test")
+
+  block:
+    proc foo(b: string) = discard
+    foo("test")
+    foo(1, "test")
+
+baz()
diff --git a/tests/lookups/tundeclaredmixin.nim b/tests/lookups/tundeclaredmixin.nim
new file mode 100644
index 000000000..74d16cdde
--- /dev/null
+++ b/tests/lookups/tundeclaredmixin.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout: '''
+  mixin nothing, add
+'''
+"""
+
+# issue #22012
+
+import macros
+
+expandMacros:
+  proc foo[T](): int =
+    # `nothing` is undeclared, `add` is declared
+    mixin nothing, add
+    123
+
+  doAssert foo[int]() == 123
diff --git a/tests/m14634.nim b/tests/m14634.nim
new file mode 100644
index 000000000..f19f02f0c
--- /dev/null
+++ b/tests/m14634.nim
@@ -0,0 +1,48 @@
+#[
+Tool to investigate underlying reasons for https://github.com/nim-lang/Nim/pull/14634
+nim r --threads:on -d:threadsafe tests/m14634.nim
+]#
+
+when not defined(windows):
+  import std/selectors
+
+  type TestData = object
+    s1, s2, s3: int
+
+  proc timerNotificationTestImpl(data: var TestData) =
+    var selector = newSelector[int]()
+    let t0 = 5
+    var timer = selector.registerTimer(t0, false, 0)
+    let t = 2000
+      # values too close to `t0` cause the test to be flaky in CI on OSX+freebsd
+      # When running locally, t0=100, t=98 will succeed some of the time which indicates
+      # there is some lag involved. Note that the higher `t-t0` is, the less times
+      # the test fails.
+    var rc1 = selector.select(t)
+    var rc2 = selector.select(t)
+    doAssert len(rc1) <= 1 and len(rc2) <= 1
+    data.s1 += ord(len(rc1) == 1)
+    data.s2 += ord(len(rc2) == 1)
+    selector.unregister(timer)
+    discard selector.select(0)
+    selector.registerTimer(t0, true, 0)
+      # same comment as above
+    var rc4 = selector.select(t)
+    let t2 = 100
+      # this can't be too large as it'll actually wait that long:
+      # timer_notification_test.n * t2
+    var rc5 = selector.select(t2)
+    doAssert len(rc4) + len(rc5) <= 1
+    data.s3 += ord(len(rc4) + len(rc5) == 1)
+    doAssert(selector.isEmpty())
+    selector.close()
+
+  proc timerNotificationTest() =
+    var data: TestData
+    let n = 10
+    for i in 0..<n:
+      timerNotificationTestImpl(data)
+    doAssert data.s1 == n and data.s2 == n and data.s3 == n, $data
+
+  when isMainModule:
+    timerNotificationTest()
diff --git a/tests/macros/m18235.nim b/tests/macros/m18235.nim
new file mode 100644
index 000000000..6bb4547e0
--- /dev/null
+++ b/tests/macros/m18235.nim
@@ -0,0 +1,42 @@
+import macros
+
+# Necessary code to update the AST on a symbol across module boundaries when
+# processed by a type macro. Used by a test of a corresponding name of this
+# file.
+
+macro eexport(n: typed): untyped =
+  result = copyNimTree(n)
+  # turn exported nnkSym -> nnkPostfix(*, nnkIdent), forcing re-sem
+  result[0] = nnkPostfix.newTree(ident"*").add:
+    n.name.strVal.ident
+
+macro unexport(n: typed): untyped =
+  result = copyNimTree(n)
+  # turn nnkSym -> nnkIdent, forcing re-sem and dropping any exported-ness
+  # that might be present
+  result[0] = n.name.strVal.ident
+
+proc foo*() {.unexport.} = discard
+proc bar() {.eexport.} = discard
+
+proc foooof*() {.unexport, eexport, unexport.} = discard
+proc barrab() {.eexport, unexport, eexport.} = discard
+
+macro eexportMulti(n: typed): untyped =
+  # use the call version of `eexport` macro for one or more decls
+  result = copyNimTree(n)
+  for i in 0..<result.len:
+    result[i] = newCall(ident"eexport", result[i])
+
+macro unexportMulti(n: typed): untyped =
+  # use the call version of `unexport` macro for one or more decls
+  result = copyNimTree(n)
+  for i in 0..<result.len:
+    result[i] = newCall(ident"unexport", result[i])
+
+unexportMulti:
+  proc oof*() = discard
+
+eexportMulti:
+  proc rab() = discard
+  proc baz*() = discard
\ No newline at end of file
diff --git a/tests/macros/macro_bug.nim b/tests/macros/macro_bug.nim
new file mode 100644
index 000000000..c723a4ab6
--- /dev/null
+++ b/tests/macros/macro_bug.nim
@@ -0,0 +1,18 @@
+import macros
+
+macro macro_bug*(s: untyped) =
+  echo s.treeRepr
+  s.expectKind({nnkProcDef, nnkMethodDef})
+
+  var params = s.params
+
+  let genericParams = s[2]
+  result = newNimNode(nnkProcDef).add(
+    s.name, s[1], genericParams, params, pragma(s), newEmptyNode())
+
+  # don't really do anything
+  var body = body(s)
+  result.add(body)
+
+  echo "result:"
+  echo result.repr
diff --git a/tests/macros/mparsefile.nim b/tests/macros/mparsefile.nim
new file mode 100644
index 000000000..8ac99d568
--- /dev/null
+++ b/tests/macros/mparsefile.nim
@@ -0,0 +1,4 @@
+let a = 1
+let b = 2
+let c =
+let d = 4
diff --git a/tests/macros/t14227.nim b/tests/macros/t14227.nim
new file mode 100644
index 000000000..4206e2c06
--- /dev/null
+++ b/tests/macros/t14227.nim
@@ -0,0 +1,23 @@
+discard """
+  action: "compile"
+"""
+import sugar
+
+
+block:
+  let y = @[@[1, 2], @[2, 4, 6]]
+  let x = collect(newSeq):
+    for i in y:
+      if i.len > 2:
+        for j in i:
+          j
+  echo(x)
+
+block:
+  let y = @[@[1, 2], @[2, 4, 6]]
+  let x = collect(newSeq):
+    for i in y:
+      for j in i:
+        if i.len > 2:
+          j
+  echo(x)
diff --git a/tests/macros/t14329.nim b/tests/macros/t14329.nim
new file mode 100644
index 000000000..b5606424a
--- /dev/null
+++ b/tests/macros/t14329.nim
@@ -0,0 +1,4 @@
+import macros
+
+macro myMacro(n) =
+  let x = if true: newLit"test" else: error "error", n
diff --git a/tests/macros/t14511.nim b/tests/macros/t14511.nim
new file mode 100644
index 000000000..f3b1e2894
--- /dev/null
+++ b/tests/macros/t14511.nim
@@ -0,0 +1,54 @@
+discard """
+  output: "true\n(y: XInt, a: 5)\n(y: XString, b: \"abc\")"
+"""
+
+import macros
+
+block TEST_1:
+  # https://github.com/nim-lang/Nim/issues/14511
+
+  template myPragma() {.pragma.}
+
+  type
+    XType = enum
+      XInt,
+      XString,
+      XUnused
+    X = object
+      case y {.myPragma.}: XType
+        of XInt, XUnused:
+          a: int
+        else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error
+          b: string
+
+  var x: X = X(y: XInt, a: 5)
+  echo x.y.hasCustomPragma(myPragma)
+  echo x
+  echo X(y: XString, b: "abc")
+
+
+block TEST_2:
+  template myDevice(val: string) {.pragma.}
+  template myKey(val: string) {.pragma.}
+  template myMouse(val: string) {.pragma.}
+
+  type
+    Device {.pure.} = enum Keyboard, Mouse
+    Key = enum Key1, Key2
+    Mouse = enum Mouse1, Mouse2
+
+  type
+    Obj = object of RootObj
+      case device {.myDevice: "MyDevicePragmaStr".}: Device
+      of Device.Keyboard:
+        key {.myKey: "MyKeyPragmaStr".}: Key
+      else: # <-- Else case caused the "Error: index 1 not in 0 .. 0" error
+        mouse {.myMouse: "MyMousePragmaStr".}: Mouse
+
+  var obj: Obj
+  assert obj.device.hasCustomPragma(myDevice) == true
+  assert obj.key.hasCustomPragma(myKey) == true
+  assert obj.mouse.hasCustomPragma(myMouse) == true
+  assert obj.device.getCustomPragmaVal(myDevice) == "MyDevicePragmaStr"
+  assert obj.key.getCustomPragmaVal(myKey) == "MyKeyPragmaStr"
+  assert obj.mouse.getCustomPragmaVal(myMouse) == "MyMousePragmaStr"
\ No newline at end of file
diff --git a/tests/macros/t14847.nim b/tests/macros/t14847.nim
new file mode 100644
index 000000000..0e6d0dd2d
--- /dev/null
+++ b/tests/macros/t14847.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "98"
+"""
+import macros
+
+#bug #14847
+proc hello*(b: string) =
+  echo b
+
+macro dispatch(pro: typed, params: untyped): untyped =
+  var impl = pro.getImpl
+  let id = ident(pro.strVal & "_coverage")
+  impl[0] = id
+  let call = newCall(id, params)
+
+  result = newStmtList()
+  result.add(impl)
+  result.add(call)
+
+dispatch(hello, "98")
diff --git a/tests/macros/t15691.nim b/tests/macros/t15691.nim
new file mode 100644
index 000000000..c1e8a8648
--- /dev/null
+++ b/tests/macros/t15691.nim
@@ -0,0 +1,22 @@
+discard """
+  action: compile
+"""
+
+import std/macros
+
+macro simplifiedExpandMacros(body: typed): untyped =
+  result = body
+
+simplifiedExpandMacros:
+  proc testProc() = discard
+
+simplifiedExpandMacros:
+  template testTemplate(): untyped = discard
+
+# Error: illformed AST: macro testMacro(): untyped =
+simplifiedExpandMacros:
+  macro testMacro(): untyped = discard
+
+# Error: illformed AST: converter testConverter(x: int): float =
+simplifiedExpandMacros:
+  converter testConverter(x: int): float = discard
diff --git a/tests/macros/t15751.nim b/tests/macros/t15751.nim
new file mode 100644
index 000000000..fcabb2f9e
--- /dev/null
+++ b/tests/macros/t15751.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim c --hints:off $file"
+  nimout: "out"
+"""
+
+# bug #15751
+macro print(n: untyped): untyped =
+  echo n.repr
+
+print:
+  out
diff --git a/tests/macros/t16758.nim b/tests/macros/t16758.nim
new file mode 100644
index 000000000..66b6d42c5
--- /dev/null
+++ b/tests/macros/t16758.nim
@@ -0,0 +1,38 @@
+discard """

+errormsg: "'blk.p(a)' has nil child at index 1"

+action: reject

+"""

+import macros

+

+type BlockLiteral[T] = object

+  p: T

+

+proc p[T](a:int) = echo 1

+proc p[T](a:string) = echo "a"

+

+iterator arguments(formalParams: NimNode): NimNode =

+  var iParam = 0

+  for i in 1 ..< formalParams.len:

+    let pp = formalParams[i]

+    for j in 0 .. pp.len - 3:

+      yield pp[j]

+      inc iParam

+

+macro implementInvoke(T: typedesc): untyped =

+  let t = getTypeImpl(T)[1]

+

+  let call = newCall(newDotExpr(ident"blk", ident"p"))

+  let params = copyNimTree(t[0])

+  result = newProc(ident"invoke", body = call)

+  # result[2] = newTree(nnkGenericParams,T)

+  for n in arguments(params):

+    call.add(n)

+  

+  params.insert(1, newIdentDefs(ident"blk", newTree(nnkBracketExpr, bindSym"BlockLiteral", T)))

+  result.params = params

+

+proc getInvoke(T: typedesc) =

+  implementInvoke(T)

+

+

+getInvoke(proc(a: int))

diff --git a/tests/macros/t17836.nim b/tests/macros/t17836.nim
new file mode 100644
index 000000000..2453637f5
--- /dev/null
+++ b/tests/macros/t17836.nim
@@ -0,0 +1,15 @@
+import macros
+
+# Ensure that `isNil` works in the typed macro context when pass procs.
+
+type
+  O = object
+    fn: proc(i: int): int
+
+var o: O
+
+macro typedBug(expr: typed) =
+  doAssert expr[1] != nil
+  doAssert not expr[1].isNil
+
+typedBug(o.fn)
\ No newline at end of file
diff --git a/tests/macros/t18203.nim b/tests/macros/t18203.nim
new file mode 100644
index 000000000..aae0a2690
--- /dev/null
+++ b/tests/macros/t18203.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--hint:SuccessX:off --hint:Link:off --hint:Conf:off --hint:CC:off --hint:XDeclaredButNotUsed:on"
+  nimout: '''
+'''
+nimoutFull: true
+action: compile
+"""
+
+# bug #18203
+import std/macros
+
+macro foo(x: typed) = newProc ident"bar"
+proc bar() {.foo.} = raise
+bar()
+
diff --git a/tests/macros/t18235.nim b/tests/macros/t18235.nim
new file mode 100644
index 000000000..ba5c48a24
--- /dev/null
+++ b/tests/macros/t18235.nim
@@ -0,0 +1,18 @@
+import m18235
+
+# this must error out because it was never actually exported
+doAssert(not declared(foo))
+doAssert not compiles(foo())
+
+doAssert(not declared(foooof))
+doAssert not compiles(foooof())
+
+doAssert(not declared(oof))
+doAssert not compiles(oof())
+
+# this should have been exported just fine
+
+bar()
+barrab()
+rab()
+baz()
\ No newline at end of file
diff --git a/tests/macros/t19766_20114.nim b/tests/macros/t19766_20114.nim
new file mode 100644
index 000000000..ac336f150
--- /dev/null
+++ b/tests/macros/t19766_20114.nim
@@ -0,0 +1,16 @@
+discard """
+  action: compile
+  nimout: '''
+const
+  foo {.strdefine.} = "abc"
+let hey {.tddd.} = 5
+'''
+"""
+
+import macros
+
+template tddd {.pragma.}
+
+expandMacros:
+  const foo {.strdefine.} = "abc"
+  let hey {.tddd.} = 5
diff --git a/tests/macros/t20067.nim b/tests/macros/t20067.nim
new file mode 100644
index 000000000..0ee3a4712
--- /dev/null
+++ b/tests/macros/t20067.nim
@@ -0,0 +1,28 @@
+discard """
+  output: '''
+b.defaultVal = foo
+$c.defaultVal = bar
+'''
+"""
+
+import macros
+
+# #18976
+
+macro getString(identifier): string =
+  result = newLit($identifier)
+doAssert getString(abc) == "abc"
+doAssert getString(`a b c`) == "abc"
+
+# #20067
+
+template defaultVal*(value : typed) {.pragma.}
+
+type A = ref object
+  b {.defaultVal: "foo".}: string
+  `$c` {.defaultVal: "bar".}: string
+
+let a = A(b: "a", `$c`: "b")
+
+echo "b.defaultVal = " & a.b.getCustomPragmaVal(defaultVal)
+echo "$c.defaultVal = " & a.`$c`.getCustomPragmaVal(defaultVal)
diff --git a/tests/macros/t20435.nim b/tests/macros/t20435.nim
new file mode 100644
index 000000000..824282198
--- /dev/null
+++ b/tests/macros/t20435.nim
@@ -0,0 +1,30 @@
+
+#[
+  A better test requires matching, so the use of @ working can be showcased
+  For example:
+
+  proc regularCase[T]() = 
+    case [(1, 3), (3, 4)]:
+    of [(1, @a), (_, @b)]:
+      echo a, b
+    else: discard
+]#
+
+{.experimental: "caseStmtMacros".}
+
+import macros
+
+type Foo = object
+
+macro `case`(obj: Foo) = quote do: discard
+
+proc notGeneric() =
+  case Foo()
+  of a b c d: discard
+
+proc generic[T]() =
+  case Foo()
+  of a b c d: discard
+
+notGeneric()
+generic[int]()
diff --git a/tests/macros/t21593.nim b/tests/macros/t21593.nim
new file mode 100644
index 000000000..b0b7ebe75
--- /dev/null
+++ b/tests/macros/t21593.nim
@@ -0,0 +1,13 @@
+discard """
+nimout: '''
+StmtList
+  UIntLit 18446744073709551615
+  IntLit -1'''
+"""
+
+import macros
+
+dumpTree:
+  0xFFFFFFFF_FFFFFFFF'u
+  0xFFFFFFFF_FFFFFFFF
+
diff --git a/tests/macros/t23032_1.nim b/tests/macros/t23032_1.nim
new file mode 100644
index 000000000..4e1707414
--- /dev/null
+++ b/tests/macros/t23032_1.nim
@@ -0,0 +1,19 @@
+import std/macros
+
+type A[T, H] = object
+
+proc `%*`(a: A): bool = true
+proc `%*`[T](a: A[int, T]): bool = false
+
+macro collapse(s: untyped) =
+  result = newStmtList()
+  result.add quote do:
+    doAssert(`s`(A[float, int]()) == true)
+
+macro startHere(n: untyped): untyped =
+  result = newStmtList()
+  let s = n[0]
+  result.add quote do:
+    `s`.collapse()
+
+startHere(`a` %* `b`)
diff --git a/tests/macros/t23032_2.nim b/tests/macros/t23032_2.nim
new file mode 100644
index 000000000..8dde29e10
--- /dev/null
+++ b/tests/macros/t23032_2.nim
@@ -0,0 +1,20 @@
+discard """
+  action: "reject"
+  errormsg: "ambiguous identifier: '%*'"
+"""
+import std/macros
+
+type A[T, H] = object
+
+proc `%*`[T](a: A) = discard
+proc `%*`[T](a: A[int, T]) = discard
+
+macro collapse(s: typed) = discard
+
+macro startHere(n: untyped): untyped =
+  result = newStmtList()
+  let s = n[0]
+  result.add quote do:
+    collapse(`s`.typeof())
+
+startHere(`a` %* `b`)
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/t7454.nim b/tests/macros/t7454.nim
new file mode 100644
index 000000000..e527de0c3
--- /dev/null
+++ b/tests/macros/t7454.nim
@@ -0,0 +1,8 @@
+discard """
+errormsg: "expression has no type:"
+line: 8
+"""
+
+macro p(t: typedesc): typedesc =
+  discard
+var a: p(int)
diff --git a/tests/macros/t7875.nim b/tests/macros/t7875.nim
new file mode 100644
index 000000000..7b6e47b86
--- /dev/null
+++ b/tests/macros/t7875.nim
@@ -0,0 +1,22 @@
+discard """
+  nimout: "var mysym`gensym0: MyType[float32]"
+  joinable: false
+"""
+
+import macros
+
+type
+  MyType[T] = object
+
+# this is totally fine
+var mysym: MyType[float32]
+
+macro foobar(): untyped =
+  let floatSym = bindSym"float32"
+
+  result = quote do:
+    var mysym: MyType[`floatSym`]
+
+  echo result.repr
+
+foobar()
diff --git a/tests/macros/t8997.nim b/tests/macros/t8997.nim
new file mode 100644
index 000000000..b06223717
--- /dev/null
+++ b/tests/macros/t8997.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "illformed AST: "
+  line: 24
+"""
+
+import macros
+
+type
+  Node* = ref object
+    children: seq[Node]
+
+proc newNode*(): Node =
+  Node(children: newSeq[Node]())
+
+macro build*(body: untyped): untyped =
+
+  template appendElement(tmp, childrenBlock) {.dirty.} =
+    bind newNode
+    let tmp = newNode()
+    tmp.children = childrenBlock  # this line seems to be the problem
+
+  let tmp = genSym(nskLet, "tmp")
+  let childrenBlock = newEmptyNode()
+  result = getAst(appendElement(tmp, childrenBlock))
+
+build(body)
diff --git a/tests/macros/tastrepr.nim b/tests/macros/tastrepr.nim
new file mode 100644
index 000000000..96a37c7a2
--- /dev/null
+++ b/tests/macros/tastrepr.nim
@@ -0,0 +1,58 @@
+discard """
+output: '''
+
+var data = @[(1, "one"), (2, "two")]
+for (i, d) in pairs(data):
+  discard
+for i, d in pairs(data):
+  discard
+for i, (x, y) in pairs(data):
+  discard
+var
+  a = 1
+  b = 2
+type
+  A* = object
+
+var data = @[(1, "one"), (2, "two")]
+for (i, d) in pairs(data):
+  discard
+for i, d in pairs(data):
+  discard
+for i, (x, y) in pairs(data):
+  discard
+var (a, b) = (1, 2)
+type
+  A* = object
+
+var t04 = 1.0'f128
+t04 = 2.0'f128
+'''
+"""
+
+import macros
+
+macro echoTypedRepr(arg: typed) =
+  result = newCall(ident"echo", newLit(arg.repr))
+
+macro echoUntypedRepr(arg: untyped) =
+  result = newCall(ident"echo", newLit(arg.repr))
+
+template echoTypedAndUntypedRepr(arg: untyped) =
+  echoTypedRepr(arg)
+  echoUntypedRepr(arg)
+
+echoTypedAndUntypedRepr:
+  var data = @[(1,"one"), (2,"two")]
+  for (i, d) in pairs(data):
+    discard
+  for i, d in pairs(data):
+    discard
+  for i, (x,y) in pairs(data):
+    discard
+  var (a,b) = (1,2)
+  type A* = object # issue #22933
+
+echoUntypedRepr:
+  var t04 = 1'f128
+  t04 = 2'f128
diff --git a/tests/macros/tbindsym.nim b/tests/macros/tbindsym.nim
new file mode 100644
index 000000000..a493d6a88
--- /dev/null
+++ b/tests/macros/tbindsym.nim
@@ -0,0 +1,67 @@
+discard """
+  nimout: '''initApple
+deinitApple
+Coral
+enum
+  redCoral, blackCoral'''
+  output: '''TFoo
+TBar'''
+"""
+
+# bug #1319
+
+import macros
+
+type
+  TTextKind = enum
+    TFoo, TBar
+
+macro test: untyped =
+  var x = @[TFoo, TBar]
+  result = newStmtList()
+  for i in x:
+    result.add newCall(newIdentNode("echo"),
+      case i
+      of TFoo:
+        bindSym("TFoo")
+      of TBar:
+        bindSym("TBar"))
+
+test()
+
+# issue 7827, bindSym power up
+{.experimental: "dynamicBindSym".}
+type
+  Apple = ref object
+    name: string
+    color: int
+    weight: int
+
+proc initApple(name: string): Apple =
+  discard
+
+proc deinitApple(x: Apple) =
+  discard
+
+macro wrapObject(obj: typed, n: varargs[untyped]): untyped =
+  let m = n[0]
+  for x in m:
+    var z = bindSym x
+    echo z.repr
+
+wrapObject(Apple):
+  initApple
+  deinitApple
+
+type
+  Coral = enum
+    redCoral
+    blackCoral
+
+macro mixer(): untyped =
+  let m = "Co" & "ral"
+  let x = bindSym(m)
+  echo x.repr
+  echo getType(x).repr
+
+mixer()
diff --git a/tests/macros/tcasestmtmacro.nim b/tests/macros/tcasestmtmacro.nim
new file mode 100644
index 000000000..32019a92a
--- /dev/null
+++ b/tests/macros/tcasestmtmacro.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''
+yes
+'''
+"""
+
+import macros
+
+macro `case`(n: tuple): untyped =
+  result = newTree(nnkIfStmt)
+  let selector = n[0]
+  for i in 1 ..< n.len:
+    let it = n[i]
+    case it.kind
+    of nnkElse, nnkElifBranch, nnkElifExpr, nnkElseExpr:
+      result.add it
+    of nnkOfBranch:
+      for j in 0..it.len-2:
+        let cond = newCall("==", selector, it[j])
+        result.add newTree(nnkElifBranch, cond, it[^1])
+    else:
+      error "custom 'case' for tuple cannot handle this node", it
+
+var correct = false
+
+case ("foo", 78)
+of ("foo", 78):
+  correct = true
+  echo "yes"
+of ("bar", 88): echo "no"
+else: discard
+
+doAssert correct
diff --git a/tests/macros/tclosuremacro.nim b/tests/macros/tclosuremacro.nim
new file mode 100644
index 000000000..44c2411a5
--- /dev/null
+++ b/tests/macros/tclosuremacro.nim
@@ -0,0 +1,80 @@
+discard """
+  output: '''
+noReturn
+calling mystuff
+yes
+calling mystuff
+yes
+'''
+"""
+
+import sugar, macros
+
+proc twoParams(x: (int, int) -> int): int =
+  result = x(5, 5)
+
+proc oneParam(x: int -> int): int =
+  x(5)
+
+proc noParams(x: () -> int): int =
+  result = x()
+
+proc noReturn(x: () -> void) =
+  x()
+
+proc doWithOneAndTwo(f: (int, int) -> int): int =
+  f(1,2)
+
+doAssert twoParams(proc (a, b: auto): auto = a + b) == 10
+doAssert twoParams((x, y) => x + y) == 10
+doAssert oneParam(x => x+5) == 10
+doAssert noParams(() => 3) == 3
+doAssert doWithOneAndTwo((x, y) => x + y) == 3
+
+noReturn((() -> void) => echo("noReturn"))
+
+proc pass2(f: (int, int) -> int): (int) -> int =
+  ((x: int) -> int) => f(2, x)
+
+doAssert pass2((x, y) => x + y)(4) == 6
+
+const fun = (x, y: int) {.noSideEffect.} => x + y
+
+doAssert typeof(fun) is (proc (x, y: int): int {.nimcall.})
+doAssert fun(3, 4) == 7
+
+proc register(name: string; x: proc()) =
+  echo "calling ", name
+  x()
+
+register("mystuff", proc () =
+  echo "yes"
+)
+
+proc helper(x: NimNode): NimNode =
+  if x.kind == nnkProcDef:
+    result = copyNimTree(x)
+    result[0] = newEmptyNode()
+    result = newCall("register", newLit($x[0]), result)
+  else:
+    result = copyNimNode(x)
+    for i in 0..<x.len:
+      result.add helper(x[i])
+
+macro m(x: untyped): untyped =
+  result = helper(x)
+
+m:
+  proc mystuff() =
+    echo "yes"
+
+const typedParamAndPragma = (x, y: int) -> int => x + y
+doAssert typedParamAndPragma(1, 2) == 3
+
+type
+  Bot = object
+    call: proc (): string {.noSideEffect.}
+
+var myBot = Bot()
+myBot.call = () {.noSideEffect.} => "I'm a bot."
+doAssert myBot.call() == "I'm a bot."
diff --git a/tests/macros/tcollect.nim b/tests/macros/tcollect.nim
new file mode 100644
index 000000000..ae28ab61b
--- /dev/null
+++ b/tests/macros/tcollect.nim
@@ -0,0 +1,63 @@
+discard """
+  output: '''@[2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4, 2, 3, 4]
+@[0, 1, 2, 3]'''
+"""
+
+const data = [1,2,3,4,5,6]
+
+import macros
+
+macro collect(body): untyped =
+  # analyse the body, find the deepest expression 'it' and replace it via
+  # 'result.add it'
+  let res = genSym(nskVar, "collectResult")
+
+  when false:
+    proc detectForLoopVar(n: NimNode): NimNode =
+      if n.kind == nnkForStmt:
+        result = n[0]
+      else:
+        for x in n:
+          result = detectForLoopVar(x)
+          if result != nil: return result
+        return nil
+
+  proc t(n, res: NimNode): NimNode =
+    case n.kind
+    of nnkStmtList, nnkStmtListExpr, nnkBlockStmt, nnkBlockExpr,
+       nnkWhileStmt,
+       nnkForStmt, nnkIfExpr, nnkIfStmt, nnkTryStmt, nnkCaseStmt,
+       nnkElifBranch, nnkElse, nnkElifExpr:
+      result = copyNimTree(n)
+      if n.len >= 1:
+        result[^1] = t(n[^1], res)
+    else:
+      if true: #n == it:
+        template adder(res, it) =
+          res.add it
+        result = getAst adder(res, n)
+      else:
+        result = n
+
+  when false:
+    let it = detectForLoopVar(body)
+    if it == nil: error("no for loop in body", body)
+
+  let v = newTree(nnkVarSection,
+     newTree(nnkIdentDefs, res, newTree(nnkBracketExpr, bindSym"seq",
+     newCall(bindSym"type", body)), newEmptyNode()))
+
+  result = newTree(nnkStmtListExpr, v, t(body, res), res)
+  #echo repr result
+
+let stuff = collect:
+  var i = -1
+  while i < 4:
+    inc i
+    for it in data:
+      if it < 5 and it > 1:
+        it
+
+echo stuff
+
+echo collect(for i in 0..3: i)
diff --git a/tests/macros/tcomplexecho.nim b/tests/macros/tcomplexecho.nim
new file mode 100644
index 000000000..d58fa561c
--- /dev/null
+++ b/tests/macros/tcomplexecho.nim
@@ -0,0 +1,42 @@
+discard """
+  output: '''3
+OK
+56
+123
+56
+61'''
+"""
+
+import macros
+
+# Bug from the forum
+macro addEcho1(s: untyped): untyped =
+  s.body.add(newCall("echo", newStrLitNode("OK")))
+  result = s
+
+proc f1() {.addEcho1.} =
+  let i = 1+2
+  echo i
+
+f1()
+
+# bug #537
+proc test(): seq[NimNode] {.compiletime.} =
+  result = @[]
+  result.add parseExpr("echo 56")
+  result.add parseExpr("echo 123")
+  result.add parseExpr("echo 56")
+
+proc foo(): seq[NimNode] {.compiletime.} =
+  result = @[]
+  result.add test()
+  result.add parseExpr("echo(5+56)")
+
+macro bar() =
+  result = newNimNode(nnkStmtList)
+  let x = foo()
+  for xx in x:
+    result.add xx
+  echo treeRepr(result)
+
+bar()
diff --git a/tests/macros/tcprag.nim b/tests/macros/tcprag.nim
new file mode 100644
index 000000000..71618883f
--- /dev/null
+++ b/tests/macros/tcprag.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''true
+true
+true
+'''
+"""
+
+# issue #7615
+import macros
+
+template table(name: string) {.pragma.}
+
+type
+   User {.table("tuser").} = object
+      id: int
+      name: string
+      age: int
+
+echo User.hasCustomPragma(table)
+
+
+## crash: Error: internal error: (filename: "sempass2.nim", line: 560, column: 19)
+macro m1(T: typedesc): untyped =
+  getAST hasCustomPragma(T, table)
+echo m1(User) # Oops crash
+
+
+## This works
+macro m2(T: typedesc): untyped =
+  result = quote do:
+    `T`.hasCustomPragma(table)
+echo m2(User)
diff --git a/tests/macros/tdumpast.nim b/tests/macros/tdumpast.nim
new file mode 100644
index 000000000..484b3c2f3
--- /dev/null
+++ b/tests/macros/tdumpast.nim
@@ -0,0 +1,161 @@
+# Dump the contents of a NimNode
+
+import macros
+
+block:
+  template plus(a, b: untyped): untyped {.dirty} =
+    a + b
+
+  macro call(e: untyped): untyped =
+    result = newCall("foo", newStrLitNode("bar"))
+
+  macro dumpAST(n: untyped): string =
+    var msg = ""
+    msg.add "lispRepr:\n" & n.lispRepr & "\n"
+    msg.add "treeRepr:\n" & n.treeRepr & "\n"
+
+    var plusAst = getAst(plus(1, 2))
+    msg.add "lispRepr:\n" & n.lispRepr & "\n"
+
+    var callAst = getAst(call(4))
+    msg.add "callAst.lispRepr:\n" & callAst.lispRepr & "\n"
+
+    var e = parseExpr("foo(bar + baz)")
+    msg.add "e.lispRepr:\n" & e.lispRepr & "\n"
+    result = msg.newLit
+
+  let a = dumpAST:
+    proc add(x, y: int): int =
+      return x + y
+    const foo = 3
+
+  doAssert a == """
+lispRepr:
+(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3))))
+treeRepr:
+StmtList
+  ProcDef
+    Ident "add"
+    Empty
+    Empty
+    FormalParams
+      Ident "int"
+      IdentDefs
+        Ident "x"
+        Ident "y"
+        Ident "int"
+        Empty
+    Empty
+    Empty
+    StmtList
+      ReturnStmt
+        Infix
+          Ident "+"
+          Ident "x"
+          Ident "y"
+  ConstSection
+    ConstDef
+      Ident "foo"
+      Empty
+      IntLit 3
+lispRepr:
+(StmtList (ProcDef (Ident "add") (Empty) (Empty) (FormalParams (Ident "int") (IdentDefs (Ident "x") (Ident "y") (Ident "int") (Empty))) (Empty) (Empty) (StmtList (ReturnStmt (Infix (Ident "+") (Ident "x") (Ident "y"))))) (ConstSection (ConstDef (Ident "foo") (Empty) (IntLit 3))))
+callAst.lispRepr:
+(Call (Ident "foo") (StrLit "bar"))
+e.lispRepr:
+(Call (Ident "foo") (Infix (Ident "+") (Ident "bar") (Ident "baz")))
+"""
+
+macro fun() =
+  let n = quote do:
+    1+1 == 2
+  doAssert n.repr == "1 + 1 == 2", n.repr
+fun()
+
+macro fun2(): untyped =
+  let n = quote do:
+    1 + 2 * 3 == 1 + 6
+  doAssert n.repr == "1 + 2 * 3 == 1 + 6", n.repr
+fun2()
+
+macro fun3(): untyped =
+  let n = quote do:
+    int | float | array | seq | object | ptr | pointer | float32
+  doAssert n.repr == "int | float | array | seq | object | ptr | pointer | float32", n.repr
+fun3()
+
+macro fun4() =
+  let n = quote do:
+    (a: 1)
+  doAssert n.repr == "(a: 1)", n.repr
+fun4()
+
+# nkTupleConstr vs nkPar tests:
+block: # lispRepr
+  macro lispRepr2(a: untyped): string = newLit a.lispRepr
+
+  doAssert lispRepr2(()) == """(TupleConstr)"""
+  doAssert lispRepr2((a: 1)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)))"""
+  doAssert lispRepr2((a: 1, b: 2)) == """(TupleConstr (ExprColonExpr (Ident "a") (IntLit 1)) (ExprColonExpr (Ident "b") (IntLit 2)))"""
+  doAssert lispRepr2((1,)) == """(TupleConstr (IntLit 1))"""
+  doAssert lispRepr2((1, 2)) == """(TupleConstr (IntLit 1) (IntLit 2))"""
+  doAssert lispRepr2((1, 2, 3.0)) == """(TupleConstr (IntLit 1) (IntLit 2) (FloatLit 3.0))"""
+  doAssert lispRepr2((1)) == """(Par (IntLit 1))"""
+  doAssert lispRepr2((1+2)) == """(Par (Infix (Ident "+") (IntLit 1) (IntLit 2)))"""
+
+block: # repr
+  macro repr2(a: untyped): string = newLit a.repr
+
+  doAssert repr2(()) == "()"
+  doAssert repr2((a: 1)) == "(a: 1)"
+  doAssert repr2((a: 1, b: 2)) == "(a: 1, b: 2)"
+  doAssert repr2((1,)) == "(1,)"
+  doAssert repr2((1, 2)) == "(1, 2)"
+  doAssert repr2((1, 2, 3.0)) == "(1, 2, 3.0)"
+  doAssert repr2((1)) == "(1)"
+  doAssert repr2((1+2)) == "(1 + 2)"
+
+block: # treeRepr
+  macro treeRepr2(a: untyped): string = newLit a.treeRepr
+  macro treeRepr3(a: typed): string = newLit a.treeRepr
+
+  doAssert treeRepr2(1+1 == 2) == """
+Infix
+  Ident "=="
+  Infix
+    Ident "+"
+    IntLit 1
+    IntLit 1
+  IntLit 2"""
+
+  proc baz() = discard
+  proc baz(a: int) = discard
+  proc baz(a: float) = discard
+
+  doAssert treeRepr3(baz()) == """
+Call
+  Sym "baz""""
+
+  let a = treeRepr3(block:
+    proc bar(a: auto) = baz())
+  doAssert a == """
+BlockStmt
+  Empty
+  ProcDef
+    Sym "bar"
+    Empty
+    GenericParams
+      Sym "a:type"
+    FormalParams
+      Empty
+      IdentDefs
+        Sym "a"
+        Sym "auto"
+        Empty
+    Empty
+    Bracket
+      Empty
+      Empty
+    StmtList
+      Call
+        OpenSymChoice 3 "baz""""
diff --git a/tests/macros/tdumpast2.nim b/tests/macros/tdumpast2.nim
new file mode 100644
index 000000000..c4c591b2a
--- /dev/null
+++ b/tests/macros/tdumpast2.nim
@@ -0,0 +1,36 @@
+# Dump the contents of a NimNode
+
+import macros
+
+proc dumpit(n: NimNode): string {.compileTime.} =
+  if n == nil: return "nil"
+  result = $n.kind
+  add(result, "(")
+  case n.kind
+  of nnkEmpty: discard # same as nil node in this representation
+  of nnkNilLit:                  add(result, "nil")
+  of nnkCharLit..nnkInt64Lit:    add(result, $n.intVal)
+  of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
+  of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
+  of nnkIdent:                   add(result, $n.ident)
+  of nnkSym, nnkNone:            assert false
+  else:
+    add(result, dumpit(n[0]))
+    for j in 1..n.len-1:
+      add(result, ", ")
+      add(result, dumpit(n[j]))
+  add(result, ")")
+
+macro dumpAST(n): untyped =
+  # dump AST as a side-effect and return the inner node
+  let n = callsite()
+  echo dumpit(n)
+  result = n[1]
+
+dumpAST:
+  proc add(x, y: int): int =
+    return x + y
+
+  proc sub(x, y: int): int = return x - y
+
+
diff --git a/tests/macros/tdumpastgen.nim b/tests/macros/tdumpastgen.nim
new file mode 100644
index 000000000..0e0581f6a
--- /dev/null
+++ b/tests/macros/tdumpastgen.nim
@@ -0,0 +1,45 @@
+discard """
+nimout: '''nnkStmtList.newTree(
+  nnkVarSection.newTree(
+    nnkIdentDefs.newTree(
+      newIdentNode("x"),
+      newEmptyNode(),
+      nnkCall.newTree(
+        nnkDotExpr.newTree(
+          newIdentNode("baz"),
+          newIdentNode("create")
+        ),
+        newLit(56)
+      )
+    )
+  ),
+  nnkProcDef.newTree(
+    newIdentNode("foo"),
+    newEmptyNode(),
+    newEmptyNode(),
+    nnkFormalParams.newTree(
+      newEmptyNode()
+    ),
+    newEmptyNode(),
+    newEmptyNode(),
+    nnkStmtList.newTree(
+      newCommentStmtNode("This is a docstring"),
+      nnkCommand.newTree(
+        newIdentNode("echo"),
+        newLit("bar")
+      )
+    )
+  )
+)'''
+"""
+
+# disabled; can't work as the output is done by the compiler
+
+import macros
+
+dumpAstGen:
+  var x = baz.create(56)
+
+  proc foo() =
+    ## This is a docstring
+    echo "bar"
diff --git a/tests/macros/tdumptree.nim b/tests/macros/tdumptree.nim
new file mode 100644
index 000000000..f540306c4
--- /dev/null
+++ b/tests/macros/tdumptree.nim
@@ -0,0 +1,27 @@
+discard """
+nimout: '''
+StmtList
+  VarSection
+    IdentDefs
+      Ident "x"
+      Empty
+      Call
+        DotExpr
+          Ident "foo"
+          Ident "create"
+        IntLit 56'''
+"""
+
+# disabled; can't work as the output is done by the compiler
+
+import macros
+
+#emit("type\n  TFoo = object\n    bar: int")
+
+#var f: TFoo
+#f.bar = 5
+#echo(f.bar)
+
+dumpTree:
+  var x = foo.create(56)
+
diff --git a/tests/macros/tescape_var_into_quotedo_as_const.nim b/tests/macros/tescape_var_into_quotedo_as_const.nim
new file mode 100644
index 000000000..1ed93f012
--- /dev/null
+++ b/tests/macros/tescape_var_into_quotedo_as_const.nim
@@ -0,0 +1,36 @@
+discard """
+  output: '''ok'''
+"""
+# bug #9864
+import macros, tables
+
+proc bar(shOpt: Table[string, int]) = discard
+
+macro dispatchGen(): untyped =
+  var shOpt = initTable[string, int]()
+  shOpt["foo"] = 10
+  result = quote do:
+     bar(`shOpt`)
+
+dispatchGen()
+
+type
+  Foo = object
+    data: seq[int]
+
+proc barB(a: Foo) = discard
+
+proc shOptB(): auto =
+  var shOpt: Foo
+  shOpt.data.setLen 1 # fails
+  shOpt
+
+macro dispatchGenB(): untyped =
+  var shOpt = shOptB() # fails
+
+  result = quote do:
+     barB(`shOpt`)
+
+dispatchGenB()
+
+echo "ok"
diff --git a/tests/macros/texpectIdent1.nim b/tests/macros/texpectIdent1.nim
new file mode 100644
index 000000000..26e52afb5
--- /dev/null
+++ b/tests/macros/texpectIdent1.nim
@@ -0,0 +1,18 @@
+discard """
+errormsg: "Expected identifier to be `foo` here"
+line: 18
+"""
+
+import macros
+
+macro testUntyped(arg: untyped): void =
+  arg.expectKind nnkStmtList
+  arg.expectLen 2
+  arg[0].expectKind nnkCall
+  arg[0][0].expectIdent "foo"  # must pass
+  arg[1].expectKind nnkCall
+  arg[1][0].expectIdent "foo"  # must fail
+
+testUntyped:
+  foo(123)
+  bar(321)
diff --git a/tests/macros/texpectIdent2.nim b/tests/macros/texpectIdent2.nim
new file mode 100644
index 000000000..887a6ddc3
--- /dev/null
+++ b/tests/macros/texpectIdent2.nim
@@ -0,0 +1,24 @@
+discard """
+errormsg: "Expected identifier to be `foo` here"
+line: 24
+"""
+
+import macros
+
+macro testTyped(arg: typed): void =
+  arg.expectKind nnkStmtList
+  arg.expectLen 2
+  arg[0].expectKind nnkCall
+  arg[0][0].expectIdent "foo"  # must pass
+  arg[1].expectKind nnkCall
+  arg[1][0].expectIdent "foo"  # must fail
+
+proc foo(arg: int) =
+  discard
+
+proc bar(arg: int) =
+  discard
+
+testTyped:
+  foo(123)
+  bar(321)
diff --git a/tests/macros/tfail_parse.nim b/tests/macros/tfail_parse.nim
new file mode 100644
index 000000000..1925f2b69
--- /dev/null
+++ b/tests/macros/tfail_parse.nim
@@ -0,0 +1,15 @@
+discard """
+action: "reject"
+cmd: "nim check $file"
+errormsg: "expected expression, but got multiple statements [ValueError]"
+file: "macros.nim"
+"""
+
+import macros
+static:
+  discard parseStmt("'")
+  discard parseExpr("'")
+  discard parseExpr("""
+proc foo()
+proc foo() = discard
+""")
diff --git a/tests/macros/tforloop_macro1.nim b/tests/macros/tforloop_macro1.nim
new file mode 100644
index 000000000..a8f45c7ac
--- /dev/null
+++ b/tests/macros/tforloop_macro1.nim
@@ -0,0 +1,44 @@
+discard """
+  output: '''0 1
+1 2
+2 3
+0 1
+1 2
+2 3
+0 1
+1 2
+2 3
+3 5'''
+"""
+
+import macros
+
+macro mymacro(): untyped =
+  result = newLit([1, 2, 3])
+
+for a, b in mymacro():
+  echo a, " ", b
+
+macro enumerate(x: ForLoopStmt): untyped =
+  expectKind x, nnkForStmt
+  # we strip off the first for loop variable and use
+  # it as an integer counter:
+  result = newStmtList()
+  result.add newVarStmt(x[0], newLit(0))
+  var body = x[^1]
+  if body.kind != nnkStmtList:
+    body = newTree(nnkStmtList, body)
+  body.add newCall(bindSym"inc", x[0])
+  var newFor = newTree(nnkForStmt)
+  for i in 1..x.len-3:
+    newFor.add x[i]
+  # transform enumerate(X) to 'X'
+  newFor.add x[^2][1]
+  newFor.add body
+  result.add newFor
+
+for a, b in enumerate(items([1, 2, 3])):
+  echo a, " ", b
+
+for a2, b2 in enumerate([1, 2, 3, 5]):
+  echo a2, " ", b2
diff --git a/tests/macros/tgetimpl.nim b/tests/macros/tgetimpl.nim
new file mode 100644
index 000000000..ab33131b0
--- /dev/null
+++ b/tests/macros/tgetimpl.nim
@@ -0,0 +1,103 @@
+discard """
+  nimout: '''foo = "muhaha"
+proc poo(x, y: int) =
+  let y = x
+  echo ["poo"]'''
+"""
+
+import macros
+
+const
+  foo = "muhaha"
+
+proc poo(x, y: int) =
+  let y = x
+  echo "poo"
+
+macro m(x: typed): untyped =
+  echo repr x.getImpl
+
+m(foo)
+m(poo)
+
+#------------
+
+macro checkOwner(x: typed, check_id: static[int]): untyped =
+  let sym = case check_id:
+    of 0: x
+    of 1: x.getImpl.body[0][0][0]
+    of 2: x.getImpl.body[0][0][^1]
+    of 3: x.getImpl.body[1][0]
+    else: x
+  result = newStrLitNode($sym.owner.symKind)
+
+macro isSameOwner(x, y: typed): untyped =
+  result =
+    if x.owner == y.owner: bindSym"true"
+    else: bindSym"false"
+
+
+static:
+  doAssert checkOwner(foo, 0) == "nskModule"
+  doAssert checkOwner(poo, 0) == "nskModule"
+  doAssert checkOwner(poo, 1) == "nskProc"
+  doAssert checkOwner(poo, 2) == "nskProc"
+  doAssert checkOwner(poo, 3) == "nskModule"
+  doAssert isSameOwner(foo, poo)
+  proc wrappedScope() =
+    proc dummyproc() = discard
+    doAssert isSameOwner(foo, dummyproc) == false
+    doAssert isSameOwner(poo, dummyproc) == false
+  wrappedScope()
+
+macro check_gen_proc(ex: typed): (bool, bool) =
+  let lenChoice = bindsym"len"
+  var is_equal = false 
+  var is_instance_of = false 
+  for child in lenChoice:
+    if not is_equal:
+      is_equal = ex[0] == child
+    if not is_instance_of:
+      is_instance_of = isInstantiationOf(ex[0], child)
+         
+  result = nnkTupleConstr.newTree(newLit(is_equal), newLit(is_instance_of))
+
+# check that len(seq[int]) is not equal to bindSym"len", but is instance of it
+let a = @[1,2,3]
+assert: check_gen_proc(len(a)) == (false, true)
+
+
+#---------------------------------------------------------------
+# issue #16110
+
+macro check(x: type): untyped =
+  let z = getType(x)
+  let y = getImpl(z[1])  
+  var sym = y[0]
+  if sym.kind == nnkPragmaExpr: sym = sym[0]
+  if sym.kind == nnkPostfix: sym = sym[1]
+  expectKind(z[1], nnkSym)
+  expectKind(sym, nnkSym)
+  expectKind(y[2], nnkObjectTy)
+  doAssert(sym == z[1])
+
+type
+  TirePtr = ptr object
+    code: int
+
+  TireRef* = ref object
+    code: int
+
+  TireRef2* {.inheritable.} = ref object
+    code: int
+
+  TireRef3* {.inheritable.} = object
+    code: int
+
+var z1: TirePtr
+check(typeof(z1[]))
+var z2: TireRef
+check(typeof(z2[]))
+var z3: TireRef2
+check(typeof(z3[]))
+check(TireRef3)
diff --git a/tests/macros/tgetraiseslist.nim b/tests/macros/tgetraiseslist.nim
new file mode 100644
index 000000000..79694a66f
--- /dev/null
+++ b/tests/macros/tgetraiseslist.nim
@@ -0,0 +1,29 @@
+discard """
+  nimout: '''##[ValueError, Gen[string]]##
+%%[RootEffect]%%
+true true'''
+"""
+
+import macros
+import std / effecttraits
+
+type
+  Gen[T] = object of CatchableError
+    x: T
+
+macro m(call: typed): untyped =
+  echo "##", repr getRaisesList(call[0]), "##"
+  echo "%%", repr getTagsList(call[0]), "%%"
+  echo isGcSafe(call[0]), " ", hasNoSideEffects(call[0])
+  result = call
+
+proc gutenTag() {.tags: RootEffect.} = discard
+
+proc r(inp: int) =
+  if inp == 0:
+    raise newException(ValueError, "bah")
+  elif inp == 1:
+    raise newException(Gen[string], "bahB")
+  gutenTag()
+
+m r(2)
diff --git a/tests/macros/tgettype.nim b/tests/macros/tgettype.nim
new file mode 100644
index 000000000..d91efe1fe
--- /dev/null
+++ b/tests/macros/tgettype.nim
@@ -0,0 +1,85 @@
+import std/macros
+import stdtest/testutils
+
+# getType
+
+block:
+  type
+    Model = object of RootObj
+    User = object of Model
+      name : string
+      password : string
+
+  macro testUser: string =
+    result = newLit(User.getType.lispRepr)
+
+  macro testGeneric(T: typedesc[Model]): string=
+    result = newLit(T.getType.lispRepr)
+
+  doAssert testUser == """(ObjectTy (Empty) (Sym "Model") (RecList (Sym "name") (Sym "password")))"""
+  doAssert User.testGeneric == """(BracketExpr (Sym "typeDesc") (Sym "User"))"""
+
+  macro assertVoid(e: typed): untyped =
+    assert(getTypeInst(e).typeKind == ntyVoid)
+
+  proc voidProc() = discard
+
+  assertVoid voidProc()
+
+block:
+  # refs #18220; not an actual solution (yet) but at least shows what's currently
+  # possible
+
+  type Callable1[R, T, U] = concept fn
+    fn(default(T)) is R
+    fn is U
+
+  # note that typetraits.arity doesn't work
+  macro arity(a: typed): int =
+    # number of params
+    # this is not production code!
+    let a2 = a.getType[1] # this used to crash nim, with: `vmdeps.nim(292, 25) `false``
+    newLit a2.len - 1
+
+  type Callable2[R, T, U] = concept fn
+    fn(default(T)) is R
+    fn is U
+    arity(U) == 2
+
+  proc map1[T, R, U](a: T, fn: Callable1[R, T, U]): R =
+    let fn = U(fn)
+      # `cast[U](fn)` would also work;
+      # this is currently needed otherwise, sigmatch errors with:
+      # Error: attempting to call routine: 'fn'
+      #  found 'fn' [param declared in tgettype.nim(53, 28)]
+      # this can be fixed in future work
+    fn(a)
+
+  proc map2[T, R, U](a: T, fn: Callable2[R, T, U]): R =
+    let fn = U(fn)
+    fn(a)
+
+  proc fn1(a: int, a2 = 'x'): string = $(a, a2, "fn1")
+  proc fn2(a: int, a2 = "zoo"): string = $(a, a2, "fn2")
+  proc fn3(a: int, a2 = "zoo2"): string = $(a, a2, "fn3")
+  proc fn4(a: int): string {.inline.} = $(a, "fn4")
+  proc fn5(a: int): string = $(a, "fn5")
+
+  assertAll:
+    # Callable1
+    1.map1(fn1) == """(1, 'x', "fn1")"""
+    1.map1(fn2) == """(1, "zoo", "fn2")"""
+    1.map1(fn3) == """(1, "zoo", "fn3")"""
+      # fn3's optional param is not honored, because fn3 and fn2 yield same
+      # generic instantiation; this is a caveat with this approach
+      # There are several possible ways to improve things in future work.
+    1.map1(fn4) == """(1, "fn4")"""
+    1.map1(fn5) == """(1, "fn5")"""
+
+    # Callable2; prevents passing procs with optional params to avoid above
+    # mentioned caveat, but more restrictive
+    not compiles(1.map2(fn1))
+    not compiles(1.map2(fn2))
+    not compiles(1.map2(fn3))
+    1.map2(fn4) == """(1, "fn4")"""
+    1.map2(fn5) == """(1, "fn5")"""
diff --git a/tests/macros/tgettype2.nim b/tests/macros/tgettype2.nim
new file mode 100644
index 000000000..c579cf6ff
--- /dev/null
+++ b/tests/macros/tgettype2.nim
@@ -0,0 +1,99 @@
+discard """
+output: '''
+############
+#### gt ####
+############
+gt(Foo):	typeDesc[Foo]
+gt(Bar):	typeDesc[Bar]
+gt(Baz):	typeDesc[int]
+gt(foo):	distinct[int]
+gt(bar):	distinct[int]
+gt(baz):	int, int
+gt(v):	seq[int]
+gt(vv):	seq[float]
+gt(t):	distinct[tuple[int, int]]
+gt(tt):	distinct[tuple[float, float]]
+gt(s):	distinct[tuple[int, int]]
+#############
+#### gt2 ####
+#############
+gt2(Foo): 	Foo
+gt2(Bar): 	Bar
+gt2(Baz): 	Baz
+gt2(foo): 	Foo
+gt2(bar): 	Bar
+gt2(baz): 	Baz
+gt2(v): 	seq[int]
+gt2(vv): 	seq[float]
+gt2(t): 	MyType[system.int]
+gt2(tt): 	MyType[system.float]
+gt2(s): 	MySimpleType
+'''
+"""
+
+import macros, typetraits
+
+type Foo = distinct int
+type Bar = distinct int
+type Baz = int
+
+let foo = 0.Foo
+let bar = 1.Bar
+let baz = 2.Baz
+
+type MyType[T] = distinct tuple[a,b:T]
+type MySimpleType = distinct tuple[a,b: int]
+
+var v: seq[int]
+var vv: seq[float]
+var t: MyType[int]
+var tt: MyType[float]
+var s: MySimpleType
+
+echo "############"
+echo "#### gt ####"
+echo "############"
+
+macro gt(a: typed): string =
+  let b = a.getType
+  var str = "gt(" & $a & "):\t" & b.repr
+  if b.kind == nnkSym: # bad predicat to check weather the type has an implementation
+    str = str & ", " & b.getType.repr  # append the implementation to the result
+  result = newLit(str)
+
+echo gt(Foo) # typeDesc[Foo]
+echo gt(Bar) # typeDesc[Bar]
+echo gt(Baz) # typeDesc[int]     shouldn't it be typeDesc[Baz]?
+echo gt(foo) # distinct[int]     I would prefer Foo, distinct[int]
+echo gt(bar) # distinct[int]     I would prefer Bar, distinct[int]
+echo gt(baz) # int, int          I would prefer Baz, int
+
+echo gt(v)   # seq[int], ok
+echo gt(vv)  # seq[float], ok
+echo gt(t)   # MyType, distinct[tuple[int, int]]      I would prefer MyType[int],   distinct[tuple[int, int]]
+echo gt(tt)  # MyType, distinct[tuple[float, float]]  I would prefer MyType[float], distinct[tuple[int, int]]
+echo gt(s)   # distinct[tuple[int, int]]              I would prefer MySimpleType, distinct[tuple[int,int]]
+
+echo "#############"
+echo "#### gt2 ####"
+echo "#############"
+
+# get type name via typetraits
+
+macro gt2(a: typed): string =
+  let prefix = "gt2(" & $a & "): \t"
+  result = quote do:
+    `prefix` & `a`.type.name
+
+echo gt2(Foo) # Foo  shouldn't this be typeDesc[Foo] ?
+echo gt2(Bar) # Bar  shouldn't this be typeDesc[Bar] ?
+echo gt2(Baz) # Baz  shouldn't this be typeDesc[Baz] ?
+echo gt2(foo) # Foo
+echo gt2(bar) # Bar
+echo gt2(baz) # Baz
+
+echo gt2(v)   # seq[int]
+echo gt2(vv)  # seq[float]
+echo gt2(t)   # MyType[system.int]      why is it system.int and not just int like in seq?
+echo gt2(tt)  # MyType[system.float]    why is it system.float and not just float like in seq?
+echo gt2(s)   # MySimpleType
diff --git a/tests/macros/tgettype3.nim b/tests/macros/tgettype3.nim
new file mode 100644
index 000000000..786d09d8b
--- /dev/null
+++ b/tests/macros/tgettype3.nim
@@ -0,0 +1,48 @@
+discard """
+  output: "vec2"
+"""
+# bug #5131
+
+import macros
+
+type
+    vecBase[I: static[int], T] = distinct array[I, T]
+    vec2* = vecBase[2, float32]
+
+proc isRange(n: NimNode, rangeLen: int = -1): bool =
+    if n.kind == nnkBracketExpr and $(n[0]) == "range":
+        if rangeLen == -1:
+            result = true
+        elif n[2].intVal - n[1].intVal + 1 == rangeLen:
+            result = true
+
+proc getTypeName(t: NimNode, skipVar = false): string =
+    case t.kind
+    of nnkBracketExpr:
+        if $(t[0]) == "array" and t[1].isRange(2) and $(t[2]) == "float32":
+            result = "vec2"
+        elif $(t[0]) == "array" and t[1].isRange(3) and $(t[2]) == "float32":
+            result = "vec3"
+        elif $(t[0]) == "array" and t[1].isRange(4) and $(t[2]) == "float32":
+            result = "vec4"
+        elif $(t[0]) == "distinct":
+            result = getTypeName(t[1], skipVar)
+    of nnkSym:
+        case $t
+        of "vecBase": result = getTypeName(getType(t), skipVar)
+        of "float32": result = "float"
+        else:
+            result = $t
+    of nnkVarTy:
+        result = getTypeName(t[0])
+        if not skipVar:
+            result = "inout " & result
+    else:
+        echo "UNKNOWN TYPE: ", treeRepr(t)
+        assert(false, "Unknown type")
+
+macro typeName(t: typed): string =
+    result = newLit(getTypeName(getType(t)))
+
+var tt : vec2
+echo typeName(tt)
diff --git a/tests/macros/tgettypeinst.nim b/tests/macros/tgettypeinst.nim
new file mode 100644
index 000000000..e722f14aa
--- /dev/null
+++ b/tests/macros/tgettypeinst.nim
@@ -0,0 +1,214 @@
+discard """
+"""
+
+import macros
+
+proc symToIdent(x: NimNode): NimNode =
+  case x.kind:
+    of nnkCharLit..nnkUInt64Lit:
+      result = newNimNode(x.kind)
+      result.intVal = x.intVal
+    of nnkFloatLit..nnkFloat64Lit:
+      result = newNimNode(x.kind)
+      result.floatVal = x.floatVal
+    of nnkStrLit..nnkTripleStrLit:
+      result = newNimNode(x.kind)
+      result.strVal = x.strVal
+    of nnkIdent, nnkSym:
+      result = newIdentNode($x)
+    else:
+      result = newNimNode(x.kind)
+      for c in x:
+        result.add symToIdent(c)
+
+# check getTypeInst and getTypeImpl for given symbol x
+macro testX(x,inst0: typed; recurse: static[bool]; implX: typed) =
+  # check that getTypeInst(x) equals inst0
+  let inst = x.getTypeInst
+  let instr = inst.symToIdent.treeRepr
+  let inst0r = inst0.symToIdent.treeRepr
+  if instr != inst0r:
+    echo "instr:\n", instr
+    echo "inst0r:\n", inst0r
+    doAssert(instr == inst0r)
+
+  # check that getTypeImpl(x) is correct
+  #  if implX is nil then compare to inst0
+  #  else we expect implX to be a type definition
+  #       and we extract the implementation from that
+  let impl = x.getTypeImpl
+  var impl0 =
+    if implX.kind == nnkNilLit: inst0
+    else: implX[0][2]
+  let implr = impl.symToIdent.treerepr
+  let impl0r = impl0.symToIdent.treerepr
+  if implr != impl0r:
+    echo "implr:\n", implr
+    echo "impl0r:\n", impl0r
+    doAssert(implr == impl0r)
+
+  result = newStmtList()
+  #template echoString(s: string) = echo s.replace("\n","\n  ")
+  #result.add getAst(echoString("  " & inst0.repr))
+  #result.add getAst(echoString("  " & inst.repr))
+  #result.add getAst(echoString("  " & impl0.repr))
+  #result.add getAst(echoString("  " & impl.repr))
+
+  if recurse:
+    # now test using a newly formed variable of type getTypeInst(x)
+    template testDecl(n,m: typed) =
+      testV(n, false):
+        type _ = m
+    result.add getAst(testDecl(inst.symToIdent, impl.symToIdent))
+
+# test with a variable (instance) of type
+template testV(inst, recurse, impl) =
+  block:
+    #echo "testV(" & astToStr(inst) & ", " & $recurse & "):" & astToStr(impl)
+    var x: inst
+    testX(x, inst, recurse, impl)
+
+# test with a newly created typedesc (myType)
+# using the passed type as the implementation
+template testT(impl, recurse) =
+  block:
+    type myType = impl
+    testV(myType, recurse):
+      type _ = impl
+
+# test a built-in type whose instance is equal to the implementation
+template test(inst) =
+  testT(inst, false)
+  testV(inst, true, nil)
+
+# test a custom type with provided implementation
+template test(inst, impl) =
+  testV(inst, true, impl)
+
+type
+  Model = object of RootObj
+  User = object of Model
+    name : string
+    password : string
+
+  Tree = object of RootObj
+    value : int
+    left,right : ref Tree
+
+  MyEnum = enum
+    valueA, valueB, valueC
+
+  MySet = set[MyEnum]
+  MySeq = seq[int]
+  MyIntPtr = ptr int
+  MyIntRef = ref int
+
+  GenericObject[T] = object
+    value:T
+  Foo[N:static[int],T] = object
+  Bar[N:static[int],T] = object
+    #baz:Foo[N+1,GenericObject[T]]  # currently fails
+    baz:Foo[N,GenericObject[T]]
+
+  Generic[T] = seq[int]
+  Concrete = Generic[int]
+
+  Generic2[T1, T2] = seq[T1]
+  Concrete2 = Generic2[int, float]
+
+  Alias1 = float
+  Alias2 = Concrete
+  Alias3 = Concrete2
+
+  Vec[N: static[int],T] = object
+    arr: array[N,T]
+  Vec4[T] = Vec[4,T]
+
+
+test(bool)
+test(char)
+test(int)
+test(float)
+test(ptr int)
+test(ref int)
+test(array[1..10,Bar[2,Foo[3,float]]])
+test(array[MyEnum,Bar[2,Foo[3,float]]])
+test(distinct Bar[2,Foo[3,float]])
+test(tuple[a:int,b:Foo[-1,float]])
+test(seq[int])
+test(set[MyEnum])
+test(proc (a: int, b: Foo[2,float]))
+test(proc (a: int, b: Foo[2,float]): Bar[3,int])
+
+test(MyEnum):
+  type _ = enum
+    valueA, valueB, valueC
+test(Bar[2,Foo[3,float]]):
+  type _ = object
+    baz: Foo[2, GenericObject[Foo[3, float]]]
+test(Model):
+  type _ = object of RootObj
+test(User):
+  type _ = object of Model
+    name: string
+    password: string
+test(Tree):
+  type _ = object of RootObj
+    value: int
+    left: ref Tree
+    right: ref Tree
+test(Concrete):
+  type _ = seq[int]
+test(Generic[int]):
+  type _ = seq[int]
+test(Generic[float]):
+  type _ = seq[int]
+test(Concrete2):
+  type _ = seq[int]
+test(Generic2[int,float]):
+  type _ = seq[int]
+test(Alias1):
+  type _ = float
+test(Alias2):
+  type _ = seq[int]
+test(Alias3):
+  type _ = seq[int]
+test(Vec[4,float32]):
+  type _ = object
+    arr: array[0..3,float32]
+test(Vec4[float32]):
+  type _ = object
+    arr: array[0..3,float32]
+
+# bug #4862
+static:
+  discard typedesc[(int, int)].getTypeImpl
+
+# custom pragmas
+template myAttr() {.pragma.}
+template myAttr2() {.pragma.}
+template myAttr3() {.pragma.}
+template serializationKey(key: string) {.pragma.}
+
+type
+  MyObj {.packed,myAttr,serializationKey: "one".} = object
+    myField {.myAttr2,serializationKey: "two".}: int
+    myField2 {.myAttr3,serializationKey: "three".}: float
+
+# field pragmas not currently supported
+test(MyObj):
+  type
+    _ {.packed,myAttr,serializationKey: "one".} = object
+      myField: int
+      myField2: float
+
+block t9600:
+  type
+    Apple = ref object of RootObj
+
+  macro mixer(x: typed): untyped =
+    let w = getType(x)
+    let v = getTypeImpl(w[1])
+
+  var z: Apple
+  mixer(z)
diff --git a/tests/macros/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/tincremental.nim b/tests/macros/tincremental.nim
new file mode 100644
index 000000000..401d6f3f8
--- /dev/null
+++ b/tests/macros/tincremental.nim
@@ -0,0 +1,150 @@
+discard """
+  output: '''heavy_calc_impl is called
+sub_calc1_impl is called
+sub_calc2_impl is called
+** no changes recompute effectively
+** change one input and recompute effectively
+heavy_calc_impl is called
+sub_calc2_impl is called'''
+"""
+
+# sample incremental
+
+import tables
+import macros
+
+var inputs = initTable[string, float]() 
+var cache = initTable[string, float]()
+var dep_tree {.compileTime.} = initTable[string, string]()
+
+macro symHash(s: typed{nkSym}): string = 
+  result = newStrLitNode(symBodyHash(s))
+
+#######################################################################################
+
+template graph_node(key: string) {.pragma.}
+
+proc tag(n: NimNode): NimNode = 
+  ## returns graph node unique name of a function or nil if it is not a graph node
+  expectKind(n, {nnkProcDef, nnkFuncDef})
+  for p in n.pragma:
+    if p.len > 0 and p[0] == bindSym"graph_node":
+      return p[1]
+  return nil 
+
+macro graph_node_key(n: typed{nkSym}): untyped =
+  result = newStrLitNode(n.symBodyHash)
+
+macro graph_discovery(n: typed{nkSym}): untyped =
+  # discovers graph dependency tree and updated dep_tree global var
+  let mytag = newStrLitNode(n.symBodyHash)
+  var visited: seq[NimNode]
+  proc discover(n: NimNode) = 
+    case n.kind:
+      of nnkNone..pred(nnkSym), succ(nnkSym)..nnkNilLit: discard
+      of nnkSym:
+        if n.symKind in {nskFunc, nskProc}:
+          if n notin visited:
+            visited.add n
+            let tag = n.getImpl.tag
+            if tag != nil:
+              dep_tree[tag.strVal] =  mytag.strVal
+            else:
+              discover(n.getImpl.body)
+      else:
+        for child in n:
+          discover(child)
+  discover(n.getImpl.body)
+  result = newEmptyNode()
+
+#######################################################################################
+
+macro incremental_input(key: static[string], n: untyped{nkFuncDef}): untyped =
+  # mark leaf nodes of the graph
+  template getInput(key) {.dirty.} =
+    {.noSideEffect.}:
+      inputs[key]
+  result = n
+  result.pragma = nnkPragma.newTree(nnkCall.newTree(bindSym"graph_node", newStrLitNode(key)))
+  result.body = getAst(getInput(key))
+
+macro incremental(n: untyped{nkFuncDef}): untyped =
+  ## incrementalize side effect free computation
+  ## wraps function into caching layer, mark caching function as a graph_node
+  ## injects dependency discovery between graph nodes
+  template cache_func_body(func_name, func_name_str, func_call) {.dirty.} =
+    {.noSideEffect.}: 
+      graph_discovery(func_name)
+      let key = graph_node_key(func_name)
+      if key in cache:
+        result = cache[key]
+      else:
+        echo func_name_str & " is called"
+        result = func_call
+        cache[key] = result
+
+  let func_name = n.name.strVal & "_impl"
+  let func_call = nnkCall.newTree(ident func_name)
+  for i in 1..<n.params.len:
+    func_call.add n.params[i][0]
+  let cache_func = n.copyNimTree
+  cache_func.body = getAst(cache_func_body(ident func_name, func_name, func_call))
+  cache_func.pragma = nnkPragma.newTree(newCall(bindSym"graph_node", 
+    newCall(bindSym"symHash", ident func_name)))
+  
+  n.name = ident(func_name)
+  result = nnkStmtList.newTree(n, cache_func)
+
+###########################################################################
+### Example
+###########################################################################
+
+func input1(): float {.incremental_input("a1").}
+
+func input2(): float {.incremental_input("a2").}
+
+func sub_calc1(a: float): float  {.incremental.} = 
+  a + input1()
+
+func sub_calc2(b: float): float  {.incremental.} = 
+  b + input2()
+
+func heavy_calc(a: float, b: float): float {.incremental.} = 
+  sub_calc1(a) + sub_calc2(b)
+
+###########################################################################
+## graph finalize and inputs
+###########################################################################
+
+macro finalize_dep_tree(): untyped = 
+  result = nnkTableConstr.newNimNode
+  for key, val in dep_tree:
+    result.add nnkExprColonExpr.newTree(newStrLitNode key, newStrLitNode val)
+  result = nnkCall.newTree(bindSym"toTable", result)
+
+const dep_tree_final = finalize_dep_tree()
+
+proc set_input(key: string, val: float) = 
+  ## set input value
+  ## all affected nodes of graph are invalidated
+  inputs[key] = val
+  var k = key
+  while k != "":
+    k = dep_tree_final.getOrDefault(k , "")
+    cache.del(k)
+
+###########################################################################
+## demo
+###########################################################################
+
+set_input("a1", 5)
+set_input("a2", 2)
+discard heavy_calc(5.0, 10.0)
+
+echo "** no changes recompute effectively"
+discard heavy_calc(5.0, 10.0)
+
+echo "** change one input and recompute effectively"
+
+set_input("a2", 10)
+discard heavy_calc(5.0, 10.0)
diff --git a/tests/macros/tinvalidtypesym.nim b/tests/macros/tinvalidtypesym.nim
new file mode 100644
index 000000000..af6f31d10
--- /dev/null
+++ b/tests/macros/tinvalidtypesym.nim
@@ -0,0 +1,14 @@
+discard """
+errormsg: "type expected, but symbol 'MyType' has no type."
+"""
+
+import macros
+
+macro foobar(name) =
+  let sym = genSym(nskType, "MyType")
+
+  result = quote do:
+    type
+      `name` = `sym`
+
+foobar(MyAlias)
diff --git a/tests/macros/tisexported.nim b/tests/macros/tisexported.nim
new file mode 100644
index 000000000..53766edf5
--- /dev/null
+++ b/tests/macros/tisexported.nim
@@ -0,0 +1,10 @@
+import macros
+
+proc t1* = discard
+proc t2 = discard
+
+macro check(p1: typed, p2: typed) =
+  doAssert isExported(p1) == true
+  doAssert isExported(p2) == false
+
+check t1, t2
diff --git a/tests/macros/tlocktypednode1.nim b/tests/macros/tlocktypednode1.nim
new file mode 100644
index 000000000..f760c7cf1
--- /dev/null
+++ b/tests/macros/tlocktypednode1.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "typechecked nodes may not be modified"
+"""
+
+import macros
+
+macro doSomething(arg: typed): untyped =
+  echo arg.treeREpr
+  result = arg
+  result.add newCall(bindSym"echo", newLit(1))
+
+doSomething((echo(1); echo(2)))
diff --git a/tests/macros/tlocktypednode2.nim b/tests/macros/tlocktypednode2.nim
new file mode 100644
index 000000000..e921772b0
--- /dev/null
+++ b/tests/macros/tlocktypednode2.nim
@@ -0,0 +1,12 @@
+discard """
+errormsg: "typechecked nodes may not be modified"
+"""
+
+import macros
+
+macro doSomething(arg: typed): untyped =
+  echo arg.treeREpr
+  result = arg
+  result[0] = newCall(bindSym"echo", newLit(1))
+
+doSomething((echo(1); echo(2)))
diff --git a/tests/macros/tlocktypednode3.nim b/tests/macros/tlocktypednode3.nim
new file mode 100644
index 000000000..0eb9d4467
--- /dev/null
+++ b/tests/macros/tlocktypednode3.nim
@@ -0,0 +1,15 @@
+discard """
+errormsg: "typechecked nodes may not be modified"
+"""
+
+import macros
+
+macro doSomething(arg: typed): untyped =
+  echo arg.treeREpr
+  result = arg
+  result.add(
+    newCall(bindSym"echo", newLit(3)),
+    newCall(bindSym"echo", newLit(1))
+  )
+
+doSomething((echo(1); echo(2)))
diff --git a/tests/macros/tmacro1.nim b/tests/macros/tmacro1.nim
new file mode 100644
index 000000000..18bbeb53d
--- /dev/null
+++ b/tests/macros/tmacro1.nim
@@ -0,0 +1,119 @@
+import  macros
+
+macro test*(a: untyped): untyped =
+  var nodes: tuple[a, b: int]
+  nodes.a = 4
+  nodes[1] = 45
+
+  type
+    TTypeEx = object
+      x, y: int
+      case b: bool
+      of false: nil
+      of true: z: float
+
+  var t: TTypeEx
+  t.b = true
+  t.z = 4.5
+
+
+test:
+  "hi"
+
+
+template assertNot(arg: untyped): untyped =
+  assert(not(arg))
+
+
+proc foo(arg: int): void =
+  discard
+
+proc foo(arg: float): void =
+  discard
+
+static:
+  ## test eqIdent
+  let a = "abc_def"
+  let b = "abcDef"
+  let c = "AbcDef"
+  let d = nnkBracketExpr.newTree() # not an identifier at all
+
+  assert eqIdent(             a ,              b )
+  assert eqIdent(newIdentNode(a),              b )
+  assert eqIdent(             a , newIdentNode(b))
+  assert eqIdent(newIdentNode(a), newIdentNode(b))
+
+  assert eqIdent(               a ,                b )
+  assert eqIdent(genSym(nskLet, a),                b )
+  assert eqIdent(               a , genSym(nskLet, b))
+  assert eqIdent(genSym(nskLet, a), genSym(nskLet, b))
+
+  assert eqIdent(newIdentNode(  a), newIdentNode(  b))
+  assert eqIdent(genSym(nskLet, a), newIdentNode(  b))
+  assert eqIdent(newIdentNode(  a), genSym(nskLet, b))
+  assert eqIdent(genSym(nskLet, a), genSym(nskLet, b))
+
+  assertNot eqIdent(             c ,              b )
+  assertNot eqIdent(newIdentNode(c),              b )
+  assertNot eqIdent(             c , newIdentNode(b))
+  assertNot eqIdent(newIdentNode(c), newIdentNode(b))
+
+  assertNot eqIdent(               c ,                b )
+  assertNot eqIdent(genSym(nskLet, c),                b )
+  assertNot eqIdent(               c , genSym(nskLet, b))
+  assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
+
+  assertNot eqIdent(newIdentNode(  c), newIdentNode(  b))
+  assertNot eqIdent(genSym(nskLet, c), newIdentNode(  b))
+  assertNot eqIdent(newIdentNode(  c), genSym(nskLet, b))
+  assertNot eqIdent(genSym(nskLet, c), genSym(nskLet, b))
+
+  # eqIdent on non identifier at all
+  assertNot eqIdent(a,d)
+
+  # eqIdent on sym choice
+  let fooSym = bindSym"foo"
+  assert fooSym.kind in {nnkOpenSymChoice, nnkClosedSymChoice}
+  assert    fooSym.eqIdent("fOO")
+  assertNot fooSym.eqIdent("bar")
+
+  # eqIdent on exported and backtick quoted identifiers
+  let procName = ident("proc")
+  let quoted = nnkAccQuoted.newTree(procName)
+  let exported = nnkPostfix.newTree(ident"*", procName)
+  let exportedQuoted = nnkPostfix.newTree(ident"*", quoted)
+
+  let nodes = @[procName, quoted, exported, exportedQuoted]
+
+  for i in 0 ..< nodes.len:
+    for j in 0 ..< nodes.len:
+      doAssert eqIdent(nodes[i], nodes[j])
+
+  for node in nodes:
+    doAssert eqIdent(node, "proc")
+
+
+  var empty: NimNode
+  var myLit = newLit("str")
+
+  assert( (empty or myLit) == myLit )
+
+  empty = newEmptyNode()
+
+  assert( (empty or myLit) == myLit )
+
+  proc bottom(): NimNode =
+    quit("may not be evaluated")
+
+  assert( (myLit or bottom()) == myLit )
+
+type
+  Fruit = enum
+    apple
+    banana
+    orange
+
+macro foo(x: typed) =
+  doAssert Fruit(x.intVal) == banana
+
+foo(banana)
diff --git a/tests/macros/tmacro2.nim b/tests/macros/tmacro2.nim
new file mode 100644
index 000000000..1ad63ec8c
--- /dev/null
+++ b/tests/macros/tmacro2.nim
@@ -0,0 +1,36 @@
+discard """
+  output: "ta-da Your value sir: 'HE!!!!o Wor!!d'"
+"""
+
+import macros, strutils
+
+proc testBlock(): string {.compileTime.} =
+  block myBlock:
+    while true:
+      echo "inner block"
+      break myBlock
+    echo "outer block"
+  result = "ta-da"
+
+macro mac(n: typed): string =
+  let n = callsite()
+  expectKind(n, nnkCall)
+  expectLen(n, 2)
+  expectKind(n[1], nnkStrLit)
+  var s: string = n[1].strVal
+  s = s.replace("l", "!!")
+  result = newStrLitNode("Your value sir: '$#'" % [s])
+
+const s = testBlock()
+const t = mac("HEllo World")
+echo s, " ", t
+
+
+#-----------------------------------------------------------------------------
+# issue #15326
+macro m(n:typed):auto =
+  result = n
+
+proc f[T](x:T): T {.m.} = x
+
+discard f(3)
\ No newline at end of file
diff --git a/tests/macros/tmacro3.nim b/tests/macros/tmacro3.nim
new file mode 100644
index 000000000..38e8349e7
--- /dev/null
+++ b/tests/macros/tmacro3.nim
@@ -0,0 +1,30 @@
+discard """
+  output: ""
+"""
+
+import  macros
+
+type
+    TA = tuple[a: int]
+    PA = ref TA
+
+macro test*(a: untyped): untyped =
+  var val: PA
+  new(val)
+  val.a = 4
+
+test:
+  "hi"
+
+macro test2*(a: untyped): untyped =
+  proc testproc(recurse: int) =
+    echo "That's weird"
+    var o : NimNode = nil
+    echo "  no its not!"
+    o = newNimNode(nnkNone)
+    if recurse > 0:
+      testproc(recurse - 1)
+  testproc(5)
+
+test2:
+  "hi"
diff --git a/tests/macros/tmacro4.nim b/tests/macros/tmacro4.nim
new file mode 100644
index 000000000..cb0399894
--- /dev/null
+++ b/tests/macros/tmacro4.nim
@@ -0,0 +1,17 @@
+discard """
+  output: "after"
+"""
+
+import macros
+
+macro test_macro*(s: string, n: untyped): untyped =
+  result = newNimNode(nnkStmtList)
+  var ass : NimNode = newNimNode(nnkAsgn)
+  add(ass, newIdentNode("str"))
+  add(ass, newStrLitNode("after"))
+  add(result, ass)
+when true:
+  var str: string = "before"
+  test_macro(str):
+    var i : integer = 123
+  echo str
diff --git a/tests/macros/tmacro5.nim b/tests/macros/tmacro5.nim
new file mode 100644
index 000000000..802fb28d5
--- /dev/null
+++ b/tests/macros/tmacro5.nim
@@ -0,0 +1,59 @@
+import macros,json
+
+var decls{.compileTime.}: seq[NimNode] = @[]
+var impls{.compileTime.}: seq[NimNode] = @[]
+
+macro importImpl_forward(name, returns: untyped): untyped =
+  result = newNimNode(nnkEmpty)
+  var func_name = newNimNode(nnkAccQuoted)
+  func_name.add newIdentNode("import")
+  func_name.add name
+
+  var res = newNimNode(nnkProcDef)
+  res.add newNimNode(nnkPostfix)
+  res[0].add newIdentNode("*")
+  res[0].add func_name
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkFormalParams)
+  res[3].add returns
+  var p1 = newNimNode(nnkIdentDefs)
+  p1.add newIdentNode("dat")
+  p1.add newIdentNOde("JsonNode")
+  p1.add newNimNode(nnkEmpty)
+  res[3].add p1
+  var p2 = newNimNode(nnkIdentDefs)
+  p2.add newIdentNode("errors")
+  p2.add newNimNode(nnkVarTy)
+  p2.add newNimNode(nnkEmpty)
+  p2[1].add newNimNode(nnkBracketExpr)
+  p2[1][0].add newIdentNode("seq")
+  p2[1][0].add newIdentNode("string")
+  res[3].add p2
+
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+  res.add newNimNode(nnkEmpty)
+
+  decls.add res
+  echo(repr(res))
+
+macro importImpl(name, returns, body: untyped) =
+  #var res = getAST(importImpl_forward(name, returns))
+  discard getAST(importImpl_forward(name, returns))
+  var res = copyNimTree(decls[decls.high])
+  res[6] = body
+  echo repr(res)
+  impls.add res
+
+macro okayy() =
+  result = newNimNode(nnkStmtList)
+  for node in decls: result.add node
+  for node in impls: result.add node
+
+importImpl(Item, int):
+  echo 42
+importImpl(Foo, int16):
+  echo 77
+
+okayy
diff --git a/tests/macros/tmacro6.nim b/tests/macros/tmacro6.nim
new file mode 100644
index 000000000..c65d34b6d
--- /dev/null
+++ b/tests/macros/tmacro6.nim
@@ -0,0 +1,75 @@
+discard """
+errormsg: "expression '123' is of type 'int literal(123)' and has to be used (or discarded)"
+line: 71
+"""
+
+import macros
+
+proc foo(a, b, c: int): int =
+  result += a
+  result += b
+  result += c
+
+macro bar(a, b, c: int): int =
+  result = newCall(ident"echo")
+  result.add a
+  result.add b
+  result.add c
+
+macro baz(a, b, c: int): int =
+  let stmt = nnkStmtListExpr.newTree()
+  stmt.add newCall(ident"echo", a)
+  stmt.add newCall(ident"echo", b)
+  stmt.add newCall(ident"echo", c)
+  stmt.add newLit(123)
+  return c
+
+# test no result type with explicit return
+
+macro baz2(a, b, c: int) =
+  let stmt = nnkStmtListExpr.newTree()
+  stmt.add newCall(ident"echo", a)
+  stmt.add newCall(ident"echo", b)
+  stmt.add newCall(ident"echo", c)
+  return stmt
+
+# test explicit void type with explicit return
+
+macro baz3(a, b, c: int): void =
+  let stmt = nnkStmtListExpr.newTree()
+  stmt.add newCall(ident"echo", a)
+  stmt.add newCall(ident"echo", b)
+  stmt.add newCall(ident"echo", c)
+  return stmt
+
+# test no result type with result variable
+
+macro baz4(a, b, c: int) =
+  result = nnkStmtListExpr.newTree()
+  result.add newCall(ident"echo", a)
+  result.add newCall(ident"echo", b)
+  result.add newCall(ident"echo", c)
+
+# test explicit void type with result variable
+
+macro baz5(a, b, c: int): void =
+  let result = nnkStmtListExpr.newTree()
+  result.add newCall(ident"echo", a)
+  result.add newCall(ident"echo", b)
+  result.add newCall(ident"echo", c)
+
+macro foobar1(): int =
+  result = quote do:
+    echo "Hello World"
+    1337
+
+echo foobar1()
+
+# this should create an error message, because 123 has to be discarded.
+
+macro foobar2() =
+  result = quote do:
+    echo "Hello World"
+    123
+
+echo foobar2()
diff --git a/tests/macros/tmacro7.nim b/tests/macros/tmacro7.nim
new file mode 100644
index 000000000..602191506
--- /dev/null
+++ b/tests/macros/tmacro7.nim
@@ -0,0 +1,36 @@
+discard """
+output: '''
+calling!stuff
+calling!stuff
+'''
+disabled: true
+"""
+
+# this test modifies an already semchecked ast (bad things happen)
+# this test relies on the bug #4547
+# issue #7792
+
+import macros
+
+proc callProc(str: string) =
+  echo "calling!" & str
+
+macro testMacro(code: typed): untyped =
+  let stmtList = newNimNode(nnkStmtList)
+
+  let stmts = code[6]
+
+  for n in stmts.children:
+    # the error happens here
+    stmtList.add(newCall(bindSym("callProc"), newLit("stuff")))
+
+  code[6] = stmtList
+
+  result = newEmptyNode()
+
+proc main() {.testMacro.} =
+  echo "test"
+  echo "test2"
+
+when isMainModule:
+  main()
diff --git a/tests/macros/tmacro8.nim b/tests/macros/tmacro8.nim
new file mode 100644
index 000000000..fdcec4dd4
--- /dev/null
+++ b/tests/macros/tmacro8.nim
@@ -0,0 +1,35 @@
+# issue #8573
+
+import
+  macros,
+  strutils,
+  terminal
+
+type LogSeverity* = enum
+  sevError = "Error"
+  sevWarn  = "Warn"
+  sevInfo  = "Info"
+  sevDebug = "Debug"
+
+macro log*(severity: static[LogSeverity], group: static[string], m: varargs[typed]): untyped =
+  let sevStr   = align("[" & toUpperAscii($severity) & "] ", 8)
+  let sevColor = case severity
+    of sevError: fgRed
+    of sevWarn:  fgYellow
+    of sevInfo:  fgWhite
+    of sevDebug: fgBlack
+
+  let groupStr = "[" & $group & "] "
+
+  result = quote do:
+    setStyle({ styleBright })
+    setForegroundColor(sevColor) # <==
+    write(stdout, sevStr)
+
+    setStyle({ styleDim })
+    setForegroundColor(fgWhite)
+    write(stdout, groupStr)
+
+  let wl = newCall(bindSym"styledWriteLine", bindSym"stdout")
+  for arg in m: wl.add(arg)
+  result.add(wl)
diff --git a/tests/macros/tmacroaspragma.nim b/tests/macros/tmacroaspragma.nim
new file mode 100644
index 000000000..5f06f2425
--- /dev/null
+++ b/tests/macros/tmacroaspragma.nim
@@ -0,0 +1,7 @@
+import macros
+
+macro foo(x: untyped): untyped =
+  echo treerepr(callsite())
+  result = newNimNode(nnkStmtList)
+
+proc zoo() {.foo.} = echo "hi"
diff --git a/tests/macros/tmacrogenerics.nim b/tests/macros/tmacrogenerics.nim
new file mode 100644
index 000000000..c31b5564c
--- /dev/null
+++ b/tests/macros/tmacrogenerics.nim
@@ -0,0 +1,38 @@
+discard """
+  nimout: '''
+instantiation 1 with typeDesc[int] and typeDesc[float]
+instantiation 2 with typeDesc[float] and typeDesc[string]
+instantiation 3 with typeDesc[string] and typeDesc[string]
+counter: 3
+'''
+  output: "int\nfloat\nint\nstring"
+"""
+
+import typetraits, macros
+
+var counter {.compileTime.} = 0
+
+macro makeBar(A, B: typedesc): typedesc =
+  inc counter
+  echo "instantiation ", counter, " with ", A.getTypeInst.repr, " and ", B.getTypeInst.repr
+  result = A
+
+type
+  Bar[T, U] = makeBar(T, U)
+
+var bb1: Bar[int, float]
+var bb2: Bar[float, string]
+var bb3: Bar[int, float]
+var bb4: Bar[string, string]
+
+proc match(a: int)    = echo "int"
+proc match(a: string) = echo "string"
+proc match(a: float)  = echo "float"
+
+match(bb1)
+match(bb2)
+match(bb3)
+match(bb4)
+
+static:
+  echo "counter: ", counter
diff --git a/tests/macros/tmacrogensym.nim b/tests/macros/tmacrogensym.nim
new file mode 100644
index 000000000..7c0d75f82
--- /dev/null
+++ b/tests/macros/tmacrogensym.nim
@@ -0,0 +1,65 @@
+import nativesockets, asyncdispatch, macros
+var p = newDispatcher()
+var sock = createAsyncNativeSocket()
+
+proc convertReturns(node, retFutureSym: NimNode): NimNode {.compileTime.} =
+  case node.kind
+  of nnkReturnStmt:
+    result = newCall(newIdentNode("complete"), retFutureSym, node[0])
+  else:
+    result = node
+    for i in 0 ..< node.len:
+      result[i] = convertReturns(node[i], retFutureSym)
+
+macro async2(prc: untyped): untyped =
+  expectKind(prc, nnkProcDef)
+
+  var outerProcBody = newNimNode(nnkStmtList)
+
+  # -> var retFuture = newFuture[T]()
+  var retFutureSym = newIdentNode("retFuture") #genSym(nskVar, "retFuture")
+  outerProcBody.add(
+    newVarStmt(retFutureSym,
+      newCall(
+        newNimNode(nnkBracketExpr).add(
+          newIdentNode("newFuture"),
+          prc[3][0][1])))) # Get type from return type of this proc.
+
+  # -> iterator nameIter(): FutureBase {.closure.} = <proc_body>
+  # Changing this line to: newIdentNode($prc[0].ident & "Iter") # will make it work.
+  var iteratorNameSym = genSym(nskIterator, $prc[0] & "Iter")
+  assert iteratorNameSym.symKind == nskIterator
+  #var iteratorNameSym = newIdentNode($prc[0].ident & "Iter")
+  var procBody = prc[6].convertReturns(retFutureSym)
+
+  var closureIterator = newProc(iteratorNameSym, [newIdentNode("FutureBase")],
+                                procBody, nnkIteratorDef)
+  closureIterator[4] = newNimNode(nnkPragma).add(newIdentNode("closure"))
+  outerProcBody.add(closureIterator)
+
+  # -> var nameIterVar = nameIter
+  # -> var first = nameIterVar()
+  var varNameIterSym = newIdentNode($prc[0] & "IterVar") #genSym(nskVar, $prc[0].ident & "IterVar")
+  var varNameIter = newVarStmt(varNameIterSym, iteratorNameSym)
+  outerProcBody.add varNameIter
+  var varFirstSym = genSym(nskVar, "first")
+  assert varFirstSym.symKind ==  nskVar
+  var varFirst = newVarStmt(varFirstSym, newCall(varNameIterSym))
+  outerProcBody.add varFirst
+
+
+  result = prc
+
+  # Remove the 'closure' pragma.
+  for i in 0 ..< result[4].len:
+    if result[4][i] == newIdentNode("async"):
+      result[4].del(i)
+
+  result[6] = outerProcBody
+
+proc readStuff(): Future[string] {.async2.} =
+  var fut = connect(sock, "irc.freenode.org", Port(6667))
+  yield fut
+  var fut2 = recv(sock, 50)
+  yield fut2
+  return fut2.read
diff --git a/tests/macros/tmacrogetimpl.nim b/tests/macros/tmacrogetimpl.nim
new file mode 100644
index 000000000..1d996ff29
--- /dev/null
+++ b/tests/macros/tmacrogetimpl.nim
@@ -0,0 +1,31 @@
+import macros
+
+# bug #5034
+
+macro copyImpl(srsProc: typed, toSym: untyped) =
+  result = copyNimTree(getImplTransformed(srsProc))
+  result[0] = ident $toSym.toStrLit()
+
+proc foo1(x: float, one: bool = true): float =
+  if one:
+    return 1'f
+  result = x
+
+proc bar1(what: string): string =
+  ## be a little more adversarial with `skResult`
+  proc buzz: string =
+    result = "lightyear"
+  if what == "buzz":
+    result = "buzz " & buzz()
+  else:
+    result = what
+  return result
+
+copyImpl(foo1, foo2)
+doAssert foo1(1'f) == 1.0
+doAssert foo2(10.0, false) == 10.0
+doAssert foo2(10.0) == 1.0
+
+copyImpl(bar1, bar2)
+doAssert bar1("buzz") == "buzz lightyear"
+doAssert bar1("macros") == "macros"
diff --git a/tests/macros/tmacros1.nim b/tests/macros/tmacros1.nim
new file mode 100644
index 000000000..c588ff7e6
--- /dev/null
+++ b/tests/macros/tmacros1.nim
@@ -0,0 +1,81 @@
+discard """
+  output: '''Got: 'nnkCall' hi
+{a}
+{b}
+{a, b}'''
+"""
+
+import macros
+
+macro outterMacro*(n, blck: untyped): untyped =
+  let n = callsite()
+  var j : string = "hi"
+  proc innerProc(i: int): string =
+    echo "Using arg ! " & n.repr
+    result = "Got: '" & $n.kind & "' " & $j
+  var callNode = n[0]
+  expectKind(n, NimNodeKind.nnkCall)
+  if n.len != 3 or n[1].kind != NimNodeKind.nnkIdent:
+    error("Macro " & callNode.repr &
+      " requires the ident passed as parameter (eg: " & callNode.repr &
+      "(the_name_you_want)): statements.")
+  result = newNimNode(NimNodeKind.nnkStmtList)
+  var ass : NimNode = newNimNode(nnkAsgn)
+  ass.add(newIdentNode(n[1].ident))
+  ass.add(newStrLitNode(innerProc(4)))
+  result.add(ass)
+
+var str: string
+outterMacro(str):
+  "hellow"
+echo str
+
+type E = enum a b
+macro enumerators1(): set[E] = newLit({a})
+
+macro enumerators2(): set[E] =
+  return newLit({b})
+
+macro enumerators3(): set[E] =
+  result = newLit({E.low .. E.high})
+
+var myEnums: set[E]
+
+
+myEnums = enumerators1()
+echo myEnums
+myEnums = enumerators2()
+echo myEnums
+myEnums = enumerators3()
+echo myEnums
+
+#10751
+
+type Tuple = tuple
+  a: string
+  b: int
+
+macro foo(t: static Tuple): untyped =
+  doAssert t.a == "foo"
+  doAssert t.b == 12345
+
+foo((a: "foo", b: 12345))
+
+
+# bug #16307
+
+macro bug(x: untyped): string =
+  newLit repr(x)
+
+let res = bug:
+  block:
+    ## one
+    ## two
+    ## three
+
+doAssert res == """
+
+block:
+  ## one
+  ## two
+  ## three"""
diff --git a/tests/macros/tmacros_issues.nim b/tests/macros/tmacros_issues.nim
new file mode 100644
index 000000000..a81c51658
--- /dev/null
+++ b/tests/macros/tmacros_issues.nim
@@ -0,0 +1,521 @@
+discard """
+  nimout: '''
+IntLit 5
+proc (x: int): string => typeDesc[proc[string, int]]
+proc (x: int): void => typeDesc[proc[void, int]]
+proc (x: int) => typeDesc[proc[void, int]]
+x => seq[int]
+a
+s
+d
+f
+TTaa
+TTaa
+TTaa
+TTaa
+true
+true
+nil
+42
+false
+true
+@[i0, i1, i2, i3, i4]
+@[tmp, tmp, tmp, tmp, tmp]
+'''
+
+  output: '''
+range[0 .. 100]
+array[0 .. 100, int]
+10
+test
+0o377'i8
+0o000000000755'i32
+1
+2
+3
+foo1
+foo2
+foo3
+true
+false
+true
+false
+1.0
+'''
+"""
+
+
+import macros, parseutils
+
+
+block t7723:
+  macro foo1(): untyped =
+    result = newStmtList()
+    result.add quote do:
+      proc init(foo: int, bar: typedesc[int]): int =
+        foo
+
+  #expandMacros:
+  foo1()
+
+  doAssert init(1, int) == 1
+
+
+
+block t8706:
+  macro varargsLen(args:varargs[untyped]): untyped =
+    doAssert args.kind == nnkArgList
+    doAssert args.len == 0
+    result = newLit(args.len)
+
+  template bar(a0:varargs[untyped]): untyped =
+    varargsLen(a0)
+
+  template foo(x: int, a0:varargs[untyped]): untyped =
+    bar(a0)
+
+  doAssert foo(42) == 0
+  doAssert bar() == 0
+
+
+
+block t9194:
+  type
+    Foo1 = range[0 .. 100]
+    Foo2 = array[0 .. 100, int]
+
+  macro get(T: typedesc): untyped =
+    # Get the X out of typedesc[X]
+    let tmp = getTypeImpl(T)
+    result = newStrLitNode(getTypeImpl(tmp[1]).repr)
+
+  echo Foo1.get
+  echo Foo2.get
+
+
+
+block t1944:
+  template t(e: untyped): untyped =
+    macro m(eNode: untyped): untyped =
+      echo eNode.treeRepr
+    m e
+
+  t 5
+
+
+block t926:
+  proc test(f: var NimNode) {.compileTime.} =
+    f = newNimNode(nnkStmtList)
+    f.add newCall(newIdentNode("echo"), newLit(10))
+
+  macro blah(prc: untyped): untyped =
+    result = prc
+    test(result)
+
+  proc test() {.blah.} =
+    echo 5
+
+
+
+block t2211:
+  macro showType(t:typed): untyped =
+    let ty = t.getType
+    echo t.repr, " => ", ty.repr
+
+  showType(proc(x:int): string)
+  showType(proc(x:int): void)
+  showType(proc(x:int))
+
+  var x: seq[int]
+  showType(x)
+
+
+
+block t1140:
+  proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
+    var splitValue: string
+    var read = value.parseUntil(splitValue, '$', index)
+
+    # when false:
+    if false:
+        var identifier: string
+        read = value.parseWhile(identifier, {}, index)
+        node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
+
+    if splitValue.len > 0:
+        node.insert node.len, newCall("add", ident("result"), newStrLitNode(splitValue))
+
+  proc parse_template(node: NimNode, value: string) {.compiletime.} =
+      var index = 0
+      while index < value.len and
+          parse_until_symbol(node, value, index): discard
+
+  macro tmpli(body: untyped): typed =
+      result = newStmtList()
+      result.add parseExpr("result = \"\"")
+      result.parse_template body[1].strVal
+
+
+  proc actual: string {.used.} = tmpli html"""
+      <p>Test!</p>
+      """
+
+  proc another: string {.used.} = tmpli html"""
+      <p>what</p>
+      """
+
+
+
+block tbugs:
+  type
+    Foo = object
+      s: char
+
+  iterator test2(f: string): Foo =
+    for i in f:
+      yield Foo(s: i)
+
+  macro test(): untyped =
+    for i in test2("asdf"):
+      echo i.s
+
+  test()
+
+
+  # bug 1297
+
+  type TType = tuple[s: string]
+
+  macro echotest(): untyped =
+    var t: TType
+    t.s = ""
+    t.s.add("test")
+    result = newCall(newIdentNode("echo"), newStrLitNode(t.s))
+
+  echotest()
+
+  # bug #1103
+
+  type
+      Td = tuple
+          a:string
+          b:int
+
+  proc get_data(d: Td) : string {.compileTime.} =
+      result = d.a # Works if a literal string is used here.
+      # Bugs if line A or B is active. Works with C
+      result &= "aa"          # A
+      #result.add("aa")       # B
+      #result = result & "aa" # C
+
+  macro m(s:static[Td]) : untyped =
+      echo get_data(s)
+      echo get_data(s)
+      result = newEmptyNode()
+
+  const s = ("TT", 3)
+  m(s)
+  m(s)
+
+  # bug #933
+
+  proc nilcheck(): NimNode {.compileTime.} =
+    echo(result == nil) # true
+    echo(result.isNil) # true
+    echo(repr(result)) # nil
+
+  macro testnilcheck(): untyped =
+    result = newNimNode(nnkStmtList)
+    discard nilcheck()
+
+  testnilcheck()
+
+  # bug #1323
+
+  proc calc(): array[1, int] =
+    result[0].inc()
+    result[0].inc()
+
+  const c = calc()
+  doAssert c[0] == 2
+
+
+  # bug #3046
+
+  macro sampleMacroInt(i: int): untyped =
+    echo i.intVal
+
+  macro sampleMacroBool(b: bool): untyped =
+    echo b.boolVal
+
+  sampleMacroInt(42)
+  sampleMacroBool(false)
+  sampleMacroBool(system.true)
+
+
+# bug #11131
+macro toRendererBug(n): untyped =
+  result = newLit repr(n)
+
+echo toRendererBug(0o377'i8)
+echo toRendererBug(0o755'i32)
+
+# bug #12129
+macro foobar() =
+  var loopVars = newSeq[NimNode](5)
+  for i, sym in loopVars.mpairs():
+    sym = ident("i" & $i)
+  echo loopVars
+  for sym in loopVars.mitems():
+    sym = ident("tmp")
+  echo loopVars
+
+foobar()
+
+
+# bug #13253
+import macros
+
+type
+  FooBar = object
+    a: seq[int]
+
+macro genFoobar(a: static FooBar): untyped =
+  result = newStmtList()
+  for b in a.a:
+    result.add(newCall(bindSym"echo", newLit b))
+
+proc foobar(a: static FooBar) =
+  genFoobar(a)  # removing this make it work
+  for b in a.a:
+    echo "foo" & $b
+
+proc main() =
+  const a: seq[int] = @[1, 2,3]
+  # Error: type mismatch: got <array[0..2, int]> but expected 'seq[int]'
+  const fb = Foobar(a: a)
+  foobar(fb)
+main()
+
+# bug #13484
+
+proc defForward(id, nid: NimNode): NimNode =
+  result = newProc(id, @[newIdentNode("bool"), newIdentDefs(nid, newIdentNode("int"))], body=newEmptyNode())
+
+proc defEven(evenid, oddid, nid: NimNode): NimNode =
+  result = quote do:
+    proc `evenid`(`nid`: int): bool =
+      if `nid` == 0:
+        return true
+      else:
+        return `oddid`(`nid` - 1)
+
+proc defOdd(evenid, oddid, nid: NimNode): NimNode =
+  result = quote do:
+    proc `oddid`(`nid`: int): bool =
+      if `nid` == 0:
+        return false
+      else:
+        return `evenid`(`nid` - 1)
+
+proc callNode(funid, param: NimNode): NimNode =
+  result = quote do:
+    `funid`(`param`)
+
+macro testEvenOdd3(): untyped =
+  let
+    evenid = newIdentNode("even3")
+    oddid = newIdentNode("odd3")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd4(): untyped =
+  let
+    evenid = newIdentNode("even4")
+    oddid = newIdentNode("odd4")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  # rewrite the body of proc node.
+  oddForward[6] = newStmtList()
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd5(): untyped =
+  let
+    evenid = genSym(nskProc, "even5")
+    oddid = genSym(nskProc, "odd5")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+macro testEvenOdd6(): untyped =
+  let
+    evenid = genSym(nskProc, "even6")
+    oddid = genSym(nskProc, "odd6")
+    nid = newIdentNode("n")
+    oddForward = defForward(oddid, nid)
+    even = defEven(evenid, oddid, nid)
+    odd = defOdd(evenid, oddid, nid)
+    callEven = callNode(evenid, newLit(42))
+    callOdd = callNode(oddid, newLit(42))
+  # rewrite the body of proc node.
+  oddForward[6] = newStmtList()
+  result = quote do:
+    `oddForward`
+    `even`
+    `odd`
+    echo `callEven`
+    echo `callOdd`
+
+# it works
+testEvenOdd3()
+
+# it causes an error (redefinition of odd4), which is correct
+assert not compiles testEvenOdd4()
+
+# it caused an error (still forwarded: odd5)
+testEvenOdd5()
+
+# it works, because the forward decl and definition share the symbol and the compiler is forgiving here
+#testEvenOdd6() #Don't test it though, the compiler may become more strict in the future
+
+# bug #15385
+var captured_funcs {.compileTime.}: seq[NimNode] = @[]
+
+macro aad*(fns: varargs[typed]): typed =
+  result = newStmtList()
+  for fn in fns:
+    captured_funcs.add fn[0]
+    result.add fn
+
+func exp*(x: float): float ## get different error if you remove forward declaration
+
+func exp*(x: float): float {.aad.} =
+  var x1 = min(max(x, -708.4), 709.8)
+  var result: float   ## looks weird because it is taken from template expansion
+  result = x1 + 1.0
+  result
+
+template check_accuracy(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
+
+  proc check_accuracy: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
+    let k = (rng.b - rng.a) / (float) n
+    var
+      res, x: float
+      i, max_ulp = 0
+      avg_ulp = 0.0
+
+    x = rng.a
+    while (i < n):
+      res = f(x)
+      i.inc
+      x = x + 0.001
+    (avg_ulp, max_ulp)
+  check_accuracy()
+
+discard check_accuracy(exp, -730.0..709.4, 4)
+
+# And without forward decl
+macro aad2*(fns: varargs[typed]): typed =
+  result = newStmtList()
+  for fn in fns:
+    captured_funcs.add fn[0]
+    result.add fn
+
+func exp2*(x: float): float {.aad2.} =
+  var x1 = min(max(x, -708.4), 709.8)
+  var result: float   ## looks weird because it is taken from template expansion
+  result = x1 + 1.0
+  result
+
+template check_accuracy2(f: untyped, rng: Slice[float], n: int, verbose = false): auto =
+
+  proc check_accuracy2: tuple[avg_ulp: float, max_ulp: int] {.gensym.} =
+    let k = (rng.b - rng.a) / (float) n
+    var
+      res, x: float
+      i, max_ulp = 0
+      avg_ulp = 0.0
+
+    x = rng.a
+    while (i < n):
+      res = f(x)
+      i.inc
+      x = x + 0.001
+    (avg_ulp, max_ulp)
+  check_accuracy2()
+
+discard check_accuracy2(exp2, -730.0..709.4, 4)
+
+# And minimized:
+macro aadMin(fn: typed): typed = fn
+
+func expMin: float
+
+func expMin: float {.aadMin.} = 1
+
+echo expMin()
+
+
+# doubly-typed forward decls
+macro noop(x: typed) = x
+noop:
+  proc cally() = discard
+
+cally()
+
+noop:
+  proc barry()
+
+proc barry() = discard
+
+# some more:
+proc barry2() {.noop.}
+proc barry2() = discard
+
+proc barry3() {.noop.}
+proc barry3() {.noop.} = discard
+
+
+# issue #15389
+block double_sem_for_procs:
+
+  macro aad(fns: varargs[typed]): typed =
+    result = newStmtList()
+    for fn in fns:
+      result.add fn
+
+  func exp(x: float): float {.aad.} =
+    var x1 = min(max(x, -708.4), 709.8)
+    if x1 > 0.0:
+      return x1 + 1.0
+    result = 10.0
+
+  discard exp(5.0)
diff --git a/tests/macros/tmacros_various.nim b/tests/macros/tmacros_various.nim
new file mode 100644
index 000000000..e351b4527
--- /dev/null
+++ b/tests/macros/tmacros_various.nim
@@ -0,0 +1,391 @@
+discard """
+  nimout: '''
+Infix
+  Ident "=>"
+  Call
+    Ident "name"
+    Ident "a"
+    ExprColonExpr
+      Ident "b"
+      Ident "cint"
+  NilLit
+macrocache ok
+'''
+
+  output: '''
+x = 10
+x + y = 30
+proc foo[T, N: static[int]]()
+proc foo[T; N: static[int]]()
+a[0]: 42
+a[1]: 45
+x: some string
+([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")])
+([("key", "val"), ("keyB", "2")], [("val", "key"), ("2", "keyB")])
+0
+0
+0
+'''
+"""
+
+
+import macros, sugar, macrocache
+
+
+block tdump:
+  let
+    x = 10
+    y = 20
+  dump x
+  dump(x + y)
+
+
+block texprcolonexpr:
+  macro def(x): untyped =
+    echo treeRepr(x)
+
+  def name(a, b:cint) => nil
+
+
+
+block tgenericparams:
+  macro test():string =
+    let expr0 = "proc foo[T, N: static[int]]()"
+    let expr1 = "proc foo[T; N: static[int]]()"
+
+    newLit($toStrLit(parseExpr(expr0)) & "\n" & $toStrLit(parseExpr(expr1)))
+
+  echo test()
+
+
+
+block tidgen:
+  # Test compile-time state in same module
+  var gid {.compileTime.} = 3
+
+  macro genId(): int =
+    result = newIntLitNode(gid)
+    inc gid
+
+  proc Id1(): int {.compileTime.} = return genId()
+  proc Id2(): int {.compileTime.} = return genId()
+
+  doAssert Id1() == 3
+  doAssert Id2() == 4
+
+
+
+block tlexerex:
+  macro match(s: cstring|string; pos: int; sections: varargs[untyped]): untyped =
+    for sec in sections:
+      expectKind sec, nnkOfBranch
+      expectLen sec, 2
+    result = newStmtList()
+
+  var input = "the input"
+  var pos = 0
+  match input, pos:
+  of r"[a-zA-Z_]\w+": echo "an identifier"
+  of r"\d+": echo "an integer"
+  of r".": echo "something else"
+
+
+
+block tcopylineinfo:
+  # issue #5617, feature request
+  type Test = object
+
+  macro mixer(n: typed): untyped =
+    let x = newIdentNode("echo")
+    x.copyLineInfo(n)
+    result = newLit(x.lineInfo == n.lineInfo)
+
+  var z = mixer(Test)
+  doAssert z
+
+block tsetgetlineinfo:
+  # issue #21098, feature request
+  type Test = object
+
+  macro mixer1(n: typed): untyped =
+    let x = newIdentNode("echo")
+    var lineInfo = n.lineInfoObj
+    x.setLineInfo lineInfo
+    result = newLit(x.lineInfo == n.lineInfo)
+
+  macro mixer2(n: typed): untyped =
+    let x = newIdentNode("echo")
+    var lineInfo = n.lineInfoObj
+    lineInfo.line += 1
+    x.setLineInfo lineInfo
+    result = newLit(x.lineInfo != n.lineInfo)
+
+  doAssert mixer1(Test)
+
+  doAssert mixer2(Test)
+
+
+
+block tdebugstmt:
+  macro debug(n: varargs[untyped]): untyped =
+    result = newNimNode(nnkStmtList, n)
+    for i in 0..n.len-1:
+      add(result, newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
+      add(result, newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
+      add(result, newCall("writeLine", newIdentNode("stdout"), n[i]))
+
+  var
+    a: array[0..10, int]
+    x = "some string"
+  a[0] = 42
+  a[1] = 45
+
+  debug(a[0], a[1], x)
+
+const
+  pairs = {"key": "val", "keyB": "2"}
+
+macro bilookups(arg: static[openArray[(string, string)]]): untyped =
+  var a = newTree(nnkBracket)
+  var b = newTree(nnkBracket)
+  for (k, v) in items(arg):
+    a.add(newTree(nnkTupleConstr, newLit k, newLit v))
+    b.add(newTree(nnkTupleConstr, newLit v, newLit k))
+  result = newTree(nnkTupleConstr, a, b)
+
+macro bilookups2(arg: untyped): untyped =
+  var a = newTree(nnkBracket)
+  var b = newTree(nnkBracket)
+  arg.expectKind(nnkTableConstr)
+  for x in items(arg):
+    x.expectKind(nnkExprColonExpr)
+    a.add(newTree(nnkTupleConstr, x[0], x[1]))
+    b.add(newTree(nnkTupleConstr, x[1], x[0]))
+  result = newTree(nnkTupleConstr, a, b)
+
+const cnst1 = bilookups(pairs)
+echo cnst1
+const cnst2 = bilookups2({"key": "val", "keyB": "2"})
+echo cnst2
+
+
+
+# macrocache #11404
+const
+  mcTable = CacheTable"nimTest"
+  mcSeq = CacheSeq"nimTest"
+  mcCounter = CacheCounter"nimTest"
+
+static:
+  doAssert(mcCounter.value == 0) # CacheCounter.value
+  mcCounter.inc                  # CacheCounter.inc
+  doAssert(mcCounter.value == 1) # CacheCounter.value
+
+  let a = newLit(1)
+  let b = newLit(2)
+  let c = newLit(3)
+  let d = newLit(4)
+
+  mcSeq.add a # CacheSeq.add
+  mcSeq.add b # CacheSeq.add
+  mcSeq.add c # CacheSeq.add
+
+  doAssert(mcSeq.len == 3)  # CacheSeq.len
+  #doAssert(c in mcSeq)      # CacheSeq.contains
+  #doAssert(d notin mcSeq)   # CacheSeq.contains
+
+  mcSeq.incl d              # CacheSeq.incl
+  doAssert(mcSeq.len == 4)  # CacheSeq.len
+
+  mcSeq.incl c              # CacheSeq.incl
+  doAssert(mcSeq.len == 4)  # CacheSeq.len
+
+  doAssert(mcSeq[3] == d)   # CacheSeq.[]
+
+  #doAssert(mcSeq.pop() == d)# CacheSeq.pop
+  #doAssert(mcSeq.len == 3)  # CacheSeq.len
+
+  doAssert(mcTable.len == 0)  # CacheTable.len
+  mcTable["a"] = a            # CacheTable.[]=
+  doAssert(mcTable.len == 1)  # CacheTable.len
+
+  doAssert(mcTable["a"] == a) # CacheTable.[]
+  #doAssert("a" in mcTable)    # CacheTable.contains
+  #doAssert(mcTable.hasKey("a"))# CacheTable.hasKey
+
+  for k, v in mcTable:  # CacheTable.items
+    doAssert(k == "a")
+    doAssert(v == a)
+
+  echo "macrocache ok"
+
+block tupleNewLitTests:
+  macro t(): untyped =
+    result = newLit (1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))
+  doAssert $t() == """(1, "foo", (), (1,), (a1: 'x', a2: @["ba"]))"""
+    # this `$` test is needed because tuple equality doesn't distinguish
+    # between named vs unnamed tuples
+  doAssert t() == (1, "foo", (), (1, ), (a1: 'x', a2: @["ba"]))
+
+from strutils import contains
+block getImplTransformed:
+  macro bar(a: typed): string =
+    # newLit a.getImpl.repr # this would be before code transformation
+    let b = a.getImplTransformed
+    newLit b.repr
+  template toExpand() =
+    for ai in 0..2: echo ai
+  proc baz(a=1): int =
+    defer: discard
+    toExpand()
+    12
+  const code = bar(baz)
+  # sanity check:
+  doAssert "finally" in code # `defer` is lowered to try/finally
+  doAssert "while" in code # `for` is lowered to `while`
+  doAssert "toExpand" notin code
+    # template is expanded (but that would already be the case with
+    # `a.getImpl.repr`, unlike the other transformations mentioned above
+
+
+# test macro resemming
+macro makeVar(): untyped =
+  quote:
+    var tensorY {.inject.}: int
+
+macro noop(a: typed): untyped =
+  a
+
+noop:
+  makeVar
+echo tensorY
+
+macro xbenchmark(body: typed): untyped =
+  result = body
+
+xbenchmark:
+  proc fastSHA(inputtest: string) =
+    discard inputtest
+  fastSHA("hey")
+
+block: # issue #4547
+  macro lazy(stmtList : typed) : untyped =
+    let decl = stmtList[0]
+    decl.expectKind nnkLetSection
+    let name = decl[0][0].strVal
+    let call = decl[0][2].copy
+    call.expectKind nnkCall
+    let ident = newIdentNode("get" & name)
+    result = quote do:
+      var value : type(`call`)
+      proc `ident`() : type(`call`) =
+        if value.isNil:
+          value = `call`
+        value
+  type MyObject = object
+    a,b: int    
+  # this part, the macro call and it's result (written in the comment below) is important
+  lazy:
+    let y = new(MyObject)
+  #[
+    var value: type(new(MyObject))
+    proc gety(): type(new(MyObject)) =
+      if value.isNil:
+        value = new(MyObject)
+      value    
+  ]#
+  doAssert gety().a == 0  # works and should work
+  doAssert gety().b == 0  # works and should work
+  doAssert not declared(y)
+  doAssert not compiles(y.a)       # identifier y should not exist anymore
+  doAssert not compiles(y.b)       # identifier y should not exist anymore
+
+block: # bug #13511
+  type
+    Builder = ref object
+      components: seq[Component]
+    Component = object
+
+  proc add(builder: var Builder, component: Component) {.compileTime.} =
+    builder.components.add(component)
+
+  macro debugAst(arg: typed): untyped =
+    ## just for debugging purpose.
+    discard arg.treeRepr
+    return arg
+
+  static:
+    var component = Component()
+    var builder = Builder()
+
+    template foo(): untyped =
+      ## WAS: this doc comment causes compilation failure.
+      builder
+
+    debugAst:
+      add(foo(), component)
+
+block: # bug #15118
+  macro flop(name: static string) =
+    let id = genSym(nskType, "env")
+    let r =
+      nnkStmtList.newTree(
+        nnkTypeSection.newTree(
+          nnkTypeDef.newTree(
+            id,
+            newEmptyNode(),
+            nnkRefTy.newTree(
+              nnkObjectTy.newTree(
+                newEmptyNode(),
+                newEmptyNode(),
+                nnkRecList.newTree(
+                  nnkIdentDefs.newTree(
+                    newIdentNode(name),
+                    newIdentNode("int"),
+                    newEmptyNode()
+                  )
+                )
+              ) 
+            )
+          )
+        ),
+
+        # var f: T
+  
+        nnkVarSection.newTree(
+          nnkIdentDefs.newTree(
+            newIdentNode("f"),
+            id,
+            newEmptyNode()
+          )
+        ),
+
+        # echo f.a
+        nnkCommand.newTree(
+          newIdentNode("new"),
+          newIdentNode("f")
+        ),
+
+        nnkCommand.newTree(
+          newIdentNode("echo"),
+          nnkDotExpr.newTree(
+            newIdentNode("f"),
+            newIdentNode(name)
+          )
+        )
+      )
+    r
+
+
+  block:
+    flop("a")
+
+  block:
+    flop("b")
+
+static:
+  block:
+    const containsTable = CacheTable"containsTable"
+    doAssert "foo" notin containsTable
+    containsTable["foo"] = newLit 42
+    doAssert "foo" in containsTable
diff --git a/tests/macros/tmacrostmt.nim b/tests/macros/tmacrostmt.nim
new file mode 100644
index 000000000..817bc8352
--- /dev/null
+++ b/tests/macros/tmacrostmt.nim
@@ -0,0 +1,155 @@
+import macros
+macro case_token(n: varargs[untyped]): untyped =
+  # creates a lexical analyzer from regular expressions
+  # ... (implementation is an exercise for the reader :-)
+  nil
+
+case_token: # this colon tells the parser it is a macro statement
+of r"[A-Za-z_]+[A-Za-z_0-9]*":
+  return tkIdentifier
+of r"0-9+":
+  return tkInteger
+of r"[\+\-\*\?]+":
+  return tkOperator
+else:
+  return tkUnknown
+
+case_token: inc i
+
+#bug #488
+
+macro foo() =
+  var exp = newCall("whatwhat", newIntLitNode(1))
+  if compiles(getAst(exp)):
+    return exp
+  else: echo "Does not compute! (test OK)"
+
+foo()
+
+#------------------------------------
+# bug #8287
+type MyString = distinct string
+
+proc `$` (c: MyString): string {.borrow.}
+
+proc `!!` (c: cstring): int =
+  c.len
+
+proc f(name: MyString): int =
+  !! $ name
+
+macro repr_and_parse(fn: typed) =
+  let fn_impl = fn.getImpl
+  fn_impl.name = genSym(nskProc, $fn_impl.name)
+  echo fn_impl.repr
+  result = parseStmt(fn_impl.repr)
+
+macro repr_to_string(fn: typed): string =
+  let fn_impl = fn.getImpl
+  result = newStrLitNode(fn_impl.repr)
+
+repr_and_parse(f)
+
+
+#------------------------------------
+# bugs #8343 and #8344
+proc one_if_proc(x, y : int): int =
+  if x < y: result = x
+  else: result = y
+
+proc test_block(x, y : int): int =
+  block label:
+    result = x
+    result = y
+
+#------------------------------------
+# bugs #8348
+
+template `>`(x, y: untyped): untyped =
+  ## "is greater" operator. This is the same as ``y < x``.
+  y < x
+
+proc test_cond_stmtlist(x, y: int): int =
+  result = x
+  if x > y:
+    result = x
+
+
+#------------------------------------
+# bug #8762
+proc t2(a, b: int): int =
+  `+`(a, b)
+
+
+#------------------------------------
+# bug #8761
+
+proc fn1(x, y: int):int =
+  2 * (x + y)
+
+proc fn2(x, y: float): float =
+  (y + 2 * x) / (x - y)
+
+proc fn3(x, y: int): bool =
+  (((x and 3) div 4) or (x mod (y xor -1))) == 0 or y notin [1,2]
+
+proc fn4(x: int): int =
+  if x mod 2 == 0: return x + 2
+  else: return 0
+
+proc fn5(a, b: float): float =
+  result = - a * a / (b * b)
+
+proc `{}`(x: seq[float], i: int, j: int): float = 
+  x[i + 0 * j]
+
+proc `{}=`(x: var seq[float], i: int, val: float) = 
+  x[i] = val
+
+proc fn6() =
+  var a = @[1.0, 2.0]
+  let z = a{0, 1} 
+  a{2} = 5.0
+
+
+#------------------------------------
+# bug #10807
+proc fn_unsafeaddr(x: int): int =
+  cast[int](unsafeAddr(x))
+
+static:
+  let fn1s = "proc fn1(x, y: int): int =\n  result = 2 * (x + y)\n"
+  let fn2s = "proc fn2(x, y: float): float =\n  result = (y + 2 * x) / (x - y)\n"
+  let fn3s = "proc fn3(x, y: int): bool =\n  result = ((x and 3) div 4 or x mod (y xor -1)) == 0 or not contains([1, 2], y)\n"
+  let fn4s = "proc fn4(x: int): int =\n  if x mod 2 == 0:\n    return x + 2\n  else:\n    return 0\n"
+  let fn5s = "proc fn5(a, b: float): float =\n  result = -a * a / (b * b)\n"
+  let fn6s = "proc fn6() =\n  var a = @[1.0, 2.0]\n  let z = a{0, 1}\n  a{2} = 5.0\n"
+  let fnAddr = "proc fn_unsafeaddr(x: int): int =\n  result = cast[int](addr(x))\n"
+
+  doAssert fn1.repr_to_string == fn1s
+  doAssert fn2.repr_to_string == fn2s
+  doAssert fn3.repr_to_string == fn3s
+  doAssert fn4.repr_to_string == fn4s
+  doAssert fn5.repr_to_string == fn5s
+  doAssert fn6.repr_to_string == fn6s
+  doAssert fn_unsafeaddr.repr_to_string == fnAddr
+
+#------------------------------------
+# bug #8763
+
+type
+  A {.pure.} = enum
+    X, Y
+  B {.pure.} = enum
+    X, Y
+
+proc test_pure_enums(a: B) =
+  case a
+    of B.X: echo B.X
+    of B.Y: echo B.Y
+
+repr_and_parse(one_if_proc)
+repr_and_parse(test_block)
+repr_and_parse(test_cond_stmtlist)
+repr_and_parse(t2)
+repr_and_parse(test_pure_enums)
diff --git a/tests/macros/tmacrotypes.nim b/tests/macros/tmacrotypes.nim
new file mode 100644
index 000000000..13b421303
--- /dev/null
+++ b/tests/macros/tmacrotypes.nim
@@ -0,0 +1,157 @@
+discard """
+  nimout: '''intProc; ntyProc; proc[int, int, float]; proc (a: int; b: float): int {.nimcall.}
+void; ntyVoid; void; void
+int; ntyInt; int; int
+proc () {.nimcall.}; ntyProc; proc[void]; proc () {.nimcall.}
+voidProc; ntyProc; proc[void]; proc () {.nimcall.}
+listing fields for ObjType
+a: string
+b: int
+listing fields for ObjRef
+skipping ref type
+a: string
+b: int
+listing fields for RefType
+skipping ref type
+a: int
+b: float
+listing fields for typeof(a)
+skipping ref type
+a: string
+b: int
+listing fields for typeof(b)
+skipping ref type
+a: string
+b: int
+listing fields for typeof(c)
+skipping ref type
+a: int
+b: float
+listing fields for typeof(x)
+a: string
+b: int
+listing fields for typeof(x)
+a: int
+b: float
+typeDesc[range[1 .. 5]]; ntyTypeDesc; typeDesc[range[1, 5]]; typeDesc[range[1 .. 5]]
+typeDesc[range]; ntyTypeDesc; typeDesc[range[T]]; typeDesc[range]'''
+"""
+
+import macros, typetraits
+
+macro checkType(ex: typed): untyped =
+  echo ex.getTypeInst.repr, "; ", ex.typeKind, "; ", ex.getType.repr, "; ", ex.getTypeImpl.repr
+
+macro checkProcType(fn: typed): untyped =
+  if fn.kind == nnkProcDef:
+    result = fn
+  let fn_sym = if fn.kind == nnkProcDef: fn[0] else: fn
+  echo fn_sym, "; ", fn_sym.typeKind, "; ", fn_sym.getType.repr, "; ", fn_sym.getTypeImpl.repr
+
+proc voidProc = echo "hello"
+proc intProc(a: int, b: float): int {.checkProcType.} = 10
+
+checkType(voidProc())
+checkType(intProc(10, 20.0))
+checkType(voidProc)
+checkProcType(voidProc)
+
+macro listFields(T: typed) =
+  echo "listing fields for ", repr(T)
+  let inputExprType = getType(T)
+
+  var objType = inputExprType[1]
+  if objType.kind == nnkBracketExpr and objType.len > 1:
+    if ((objType[0].kind == nnkRefTy) or
+        (objType[0].kind == nnkSym and eqIdent(objType[0], "ref"))):
+      echo "skipping ref type"
+      objType = objType[1]
+
+  let typeAst = objType.getImpl
+
+  var objectDef = typeAst[2]
+  if objectDef.kind == nnkRefTy:
+    objectDef = objectDef[0]
+
+  let recList = objectDef[2]
+  for rec in recList:
+    echo $rec[0], ": ", $rec[1]
+
+type
+  ObjType* = object of RootObj
+    a: string
+    b: int
+
+  ObjRef = ref ObjType
+
+  RefType* = ref object of RootObj
+    a: int
+    b: float
+
+listFields ObjType
+listFields ObjRef
+listFields RefType
+
+let
+  a = new ObjType
+  b = new ObjRef
+  c = new RefType
+
+listFields typeOf(a)
+listFields typeOf(b)
+listFields typeOf(c)
+
+proc genericProc(x: object) =
+  listFields typeOf(x)
+
+genericProc a[]
+genericProc b[]
+genericProc c[]
+
+# bug #10548
+block:
+  var c {.compileTime.} = 0
+
+  macro meshImpl(arg: typed): untyped =
+    inc c
+    result = arg
+
+  type
+    Blub = int32
+    Mesh = meshImpl(Club)
+    Club = Blub
+
+  static: doAssert(c == 1)
+
+# bug #10702
+type
+  VectorElementType = SomeNumber | bool
+  Vec*[N : static[int], T: VectorElementType] = object
+    arr*: array[N, T]
+
+type
+  Vec4*[T: VectorElementType] = Vec[4,T]
+  Vec3*[T: VectorElementType] = Vec[3,T]
+  Vec2*[T: VectorElementType] = Vec[2,T]
+
+template vecGen(U:untyped,V:typed):typed=
+  ## ``U`` suffix
+  ## ``V`` valType
+  ##
+  type
+    `Vec2 U`* {.inject.} = Vec2[V]
+    `Vec3 U`* {.inject.} = Vec3[V]
+    `Vec4 U`* {.inject.} = Vec4[V]
+
+vecGen(f, float32)
+
+macro foobar(arg: typed): untyped =
+  let typ = arg.getTypeInst
+  doAssert typ.getImpl[^1].kind == nnkCall
+
+var x: Vec2f
+
+foobar(x)
+
+checkType(range[1..5])
+checkType(range)
diff --git a/tests/macros/tmemit.nim b/tests/macros/tmemit.nim
new file mode 100644
index 000000000..6c9f9f935
--- /dev/null
+++ b/tests/macros/tmemit.nim
@@ -0,0 +1,38 @@
+discard """
+  output: '''
+c_func
+12
+'''
+"""
+
+import macros, strutils
+
+# bug #1025
+
+macro foo(icname): untyped =
+  let ic = newStrLitNode($icname)
+  result = quote do:
+    proc x* =
+      proc private {.exportc: `ic`.} = discard
+      echo `ic`
+      private()
+
+foo(c_func)
+x()
+
+
+template volatileLoad[T](x: ptr T): T =
+  var res: T
+  {.emit: [res, " = (*(", type(x[]), " volatile*)", x, ");"].}
+  res
+
+template volatileStore[T](x: ptr T; y: T) =
+  {.emit: ["*((", type(x[]), " volatile*)(", x, ")) = ", y, ";"].}
+
+proc main =
+  var st: int
+  var foo: ptr int = addr st
+  volatileStore(foo, 12)
+  echo volatileLoad(foo)
+
+main()
diff --git a/tests/macros/tmsginfo.nim b/tests/macros/tmsginfo.nim
new file mode 100644
index 000000000..f08a231fb
--- /dev/null
+++ b/tests/macros/tmsginfo.nim
@@ -0,0 +1,24 @@
+discard """
+  nimout: '''tmsginfo.nim(21, 1) Warning: foo1 [User]
+tmsginfo.nim(22, 13) template/generic instantiation of `foo2` from here
+tmsginfo.nim(15, 10) Warning: foo2 [User]
+tmsginfo.nim(23, 1) Hint: foo3 [User]
+tmsginfo.nim(19, 7) Hint: foo4 [User]
+'''
+"""
+
+import macros
+
+macro foo1(y: untyped): untyped =
+  warning("foo1", y)
+macro foo2(y: untyped): untyped =
+  warning("foo2")
+macro foo3(y: untyped): untyped =
+  hint("foo3", y)
+macro foo4(y: untyped): untyped =
+  hint("foo4")
+
+proc x1() {.foo1.} = discard
+proc x2() {.foo2.} = discard
+proc x3() {.foo3.} = discard
+proc x4() {.foo4.} = discard
diff --git a/tests/macros/tnewlit.nim b/tests/macros/tnewlit.nim
new file mode 100644
index 000000000..70683f880
--- /dev/null
+++ b/tests/macros/tnewlit.nim
@@ -0,0 +1,194 @@
+import macros
+
+type
+  MyType = object
+    a : int
+    b : string
+
+  RefObject = ref object
+    x: int
+
+  RegularObject = object
+    x: int
+
+  ObjectRefAlias = ref RegularObject
+
+macro test_newLit_MyType: untyped =
+  let mt = MyType(a: 123, b:"foobar")
+  result = newLit(mt)
+
+doAssert test_newLit_MyType == MyType(a: 123, b:"foobar")
+
+macro test_newLit_array: untyped =
+  let arr = [1,2,3,4,5]
+  result = newLit(arr)
+
+doAssert test_newLit_array == [1,2,3,4,5]
+
+macro test_newLit_seq_int: untyped =
+  let s: seq[int] = @[1,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int] = test_newLit_seq_int
+  doAssert tmp == @[1,2,3,4,5]
+
+macro test_newLit_seq_int8: untyped =
+  let s: seq[int8] = @[1'i8,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int8] = test_newLit_seq_int8
+  doAssert tmp == @[1'i8,2,3,4,5]
+
+macro test_newLit_seq_int16: untyped =
+  let s: seq[int16] = @[1'i16,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int16] = test_newLit_seq_int16
+  doAssert tmp == @[1'i16,2,3,4,5]
+
+macro test_newLit_seq_int32: untyped =
+  let s: seq[int32] = @[1'i32,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int32] = test_newLit_seq_int32
+  doAssert tmp == @[1'i32,2,3,4,5]
+
+macro test_newLit_seq_int64: untyped =
+  let s: seq[int64] = @[1'i64,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[int64] = test_newLit_seq_int64
+  doAssert tmp == @[1'i64,2,3,4,5]
+
+macro test_newLit_seq_uint: untyped =
+  let s: seq[uint] = @[1u,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint] = test_newLit_seq_uint
+  doAssert tmp == @[1u,2,3,4,5]
+
+macro test_newLit_seq_uint8: untyped =
+  let s: seq[uint8] = @[1'u8,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint8] = test_newLit_seq_uint8
+  doAssert tmp == @[1'u8,2,3,4,5]
+
+macro test_newLit_seq_uint16: untyped =
+  let s: seq[uint16] = @[1'u16,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint16] = test_newLit_seq_uint16
+  doAssert tmp == @[1'u16,2,3,4,5]
+
+macro test_newLit_seq_uint32: untyped =
+  let s: seq[uint32] = @[1'u32,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint32] = test_newLit_seq_uint32
+  doAssert tmp == @[1'u32,2,3,4,5]
+
+macro test_newLit_seq_uint64: untyped =
+  let s: seq[uint64] = @[1'u64,2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[uint64] = test_newLit_seq_uint64
+  doAssert tmp == @[1'u64,2,3,4,5]
+
+macro test_newLit_seq_float: untyped =
+  let s: seq[float] = @[1.0, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float] = test_newLit_seq_float
+  doAssert tmp == @[1.0, 2,3,4,5]
+
+macro test_newLit_seq_float32: untyped =
+  let s: seq[float32] = @[1.0'f32, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float32] = test_newLit_seq_float32
+  doAssert tmp == @[1.0'f32, 2,3,4,5]
+
+macro test_newLit_seq_float64: untyped =
+  let s: seq[float64] = @[1.0'f64, 2,3,4,5]
+  result = newLit(s)
+
+block:
+  let tmp: seq[float64] = test_newLit_seq_float64
+  doAssert tmp == @[1.0'f64, 2,3,4,5]
+
+macro test_newLit_tuple: untyped =
+  let tup: tuple[a:int,b:string] = (a: 123, b: "223")
+  result = newLit(tup)
+
+doAssert test_newLit_tuple == (a: 123, b: "223")
+
+type
+  ComposedType = object
+    mt: MyType
+    arr: array[4,int]
+    data: seq[byte]
+
+macro test_newLit_ComposedType: untyped =
+  let ct = ComposedType(mt: MyType(a: 123, b:"abc"), arr: [1,2,3,4], data: @[1.byte, 3, 7, 127])
+  result = newLit(ct)
+
+doAssert test_newLit_ComposedType == ComposedType(mt: MyType(a: 123, b:"abc"), arr: [1,2,3,4], data: @[1.byte, 3, 7, 127])
+
+macro test_newLit_empty_seq_string: untyped =
+  var strSeq = newSeq[string](0)
+  result = newLit(strSeq)
+
+block:
+  # x needs to be of type seq[string]
+  var x = test_newLit_empty_seq_string
+  x.add("xyz")
+
+type
+  MyEnum = enum
+    meA
+    meB
+
+macro test_newLit_Enum: untyped =
+  result = newLit(meA)
+
+block:
+  let tmp: MyEnum = meA
+  doAssert tmp == test_newLit_Enum
+
+macro test_newLit_set: untyped =
+  let myset = {MyEnum.low .. MyEnum.high}
+  result = newLit(myset)
+
+block:
+  let tmp: set[MyEnum] = {MyEnum.low .. MyEnum.high}
+  doAssert tmp == test_newLit_set
+
+macro test_newLit_ref_object: untyped =
+  var x = RefObject(x: 10)
+  return newLit(x)
+
+block:
+  let x = test_newLit_ref_object()
+  doAssert $(x[]) == "(x: 10)"
+
+macro test_newLit_object_ref_alias: untyped =
+  var x = ObjectRefAlias(x: 10)
+  return newLit(x)
+
+block:
+  let x = test_newLit_object_ref_alias()
+  doAssert $(x[]) == "(x: 10)"
+
diff --git a/tests/macros/tnewproc.nim b/tests/macros/tnewproc.nim
new file mode 100644
index 000000000..a5bfd6dca
--- /dev/null
+++ b/tests/macros/tnewproc.nim
@@ -0,0 +1,51 @@
+import macros
+
+macro test(a: untyped): untyped =
+  # proc hello*(x: int = 3, y: float32): int {.inline.} = discard
+  let
+    nameNode = nnkPostfix.newTree(
+      newIdentNode("*"),
+      newIdentNode("hello")
+    )
+    params = @[
+      newIdentNode("int"),
+      nnkIdentDefs.newTree(
+        newIdentNode("x"),
+        newIdentNode("int"),
+        newLit(3)
+      ),
+      nnkIdentDefs.newTree(
+        newIdentNode("y"),
+        newIdentNode("float32"),
+        newEmptyNode()
+      )
+    ]
+    paramsNode = nnkFormalParams.newTree(params)
+    pragmasNode = nnkPragma.newTree(
+      newIdentNode("inline")
+    )
+    bodyNode = nnkStmtList.newTree(
+      nnkDiscardStmt.newTree(
+        newEmptyNode()
+      )
+    )
+
+  var
+    expected = nnkProcDef.newTree(
+      nameNode,
+      newEmptyNode(),
+      newEmptyNode(),
+      paramsNode,
+      pragmasNode,
+      newEmptyNode(),
+      bodyNode
+    )
+
+  doAssert expected == newProc(name=nameNode, params=params,
+                                    body = bodyNode, pragmas=pragmasNode)
+  expected.pragma = newEmptyNode()
+  doAssert expected == newProc(name=nameNode, params=params,
+                                    body = bodyNode)
+
+test:
+  42
diff --git a/tests/macros/tnodecompare.nim b/tests/macros/tnodecompare.nim
new file mode 100644
index 000000000..5ffb495b1
--- /dev/null
+++ b/tests/macros/tnodecompare.nim
@@ -0,0 +1,39 @@
+import macros
+
+static:
+  let nodeA = newCommentStmtNode("this is a comment")
+  doAssert nodeA.repr == "## this is a comment"
+  doAssert nodeA.strVal == "this is a comment"
+  doAssert $nodeA == "this is a comment"
+
+  let nodeB = newCommentStmtNode("this is a comment")
+  doAssert nodeA == nodeB
+  nodeB.strVal = "this is a different comment"
+  doAssert nodeA != nodeB
+
+macro test(a: typed, b: typed): untyped =
+  newLit(a == b)
+
+doAssert test(1, 1) == true
+doAssert test(1, 2) == false
+
+type
+  Obj = object of RootObj
+  Other = object of RootObj
+
+doAssert test(Obj, Obj) == true
+doAssert test(Obj, Other) == false
+
+var a, b: int
+
+doAssert test(a, a) == true
+doAssert test(a, b) == false
+
+macro test2: untyped =
+  newLit(bindSym"Obj" == bindSym"Obj")
+
+macro test3: untyped =
+  newLit(bindSym"Obj" == bindSym"Other")
+
+doAssert test2() == true
+doAssert test3() == false
diff --git a/tests/macros/tparsefile.nim b/tests/macros/tparsefile.nim
new file mode 100644
index 000000000..a41223f80
--- /dev/null
+++ b/tests/macros/tparsefile.nim
@@ -0,0 +1,11 @@
+import macros
+
+static:
+  let fn = "mparsefile.nim"
+  var raised = false
+  try:
+    discard parseStmt(staticRead(fn), filename = fn)
+  except ValueError as e:
+    raised = true
+    doAssert e.msg == "mparsefile.nim(4, 1) Error: invalid indentation"
+  doAssert raised
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/macros/tprochelpers.nim b/tests/macros/tprochelpers.nim
new file mode 100644
index 000000000..d95a2ced8
--- /dev/null
+++ b/tests/macros/tprochelpers.nim
@@ -0,0 +1,22 @@
+import std/macros
+import stdtest/testutils
+
+macro test1(prc: untyped): untyped =
+  assertAll:
+    prc.params.len == 2
+    prc.params[1].len == 4
+    prc.pragma.len == 2
+
+  prc.params = nnkFormalParams.newTree(
+    ident("int")
+  )
+  prc.pragma = newEmptyNode()
+
+  assertAll:
+    prc.params.len == 1
+    prc.pragma.len == 0
+  prc
+
+proc test(a, b: int): int {.gcsafe, raises: [], test1.} = 5
+
+type hello = proc(a, b: int): int {.gcsafe, raises: [], test1.}
diff --git a/tests/macros/tquotedo.nim b/tests/macros/tquotedo.nim
new file mode 100644
index 000000000..6acb8ef4e
--- /dev/null
+++ b/tests/macros/tquotedo.nim
@@ -0,0 +1,51 @@
+discard """
+output: '''
+123
+Hallo Welt
+Hallo Welt
+1
+()
+'''
+"""
+
+import macros
+
+macro mac(): untyped =
+  quote do:
+    proc test(): int =
+      (proc(): int = result = 123)()
+
+mac()
+echo test()
+
+macro foobar(arg: untyped): untyped =
+  result = arg
+  result.add quote do:
+    `result`
+
+foobar:
+  echo "Hallo Welt"
+
+# bug #3744
+import macros
+macro t(): untyped =
+  return quote do:
+    proc tp(): int =
+      result = 1
+t()
+
+echo tp()
+
+
+# https://github.com/nim-lang/Nim/issues/9866
+type
+  # Foo = int # works
+  Foo = object # fails
+
+macro dispatchGen(): untyped =
+  var shOpt: Foo
+  result = quote do:
+    let baz = `shOpt`
+    echo `shOpt`
+
+dispatchGen()
diff --git a/tests/macros/tquotewords.nim b/tests/macros/tquotewords.nim
new file mode 100644
index 000000000..e718d25f9
--- /dev/null
+++ b/tests/macros/tquotewords.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "thisanexample"
+"""
+# Test an idea I recently had:
+
+import macros
+
+macro quoteWords(n: varargs[untyped]): untyped =
+  let n = callsite()
+  result = newNimNode(nnkBracket, n)
+  for i in 1..n.len-1:
+    expectKind(n[i], nnkIdent)
+    result.add(toStrLit(n[i]))
+
+const
+  myWordList = quoteWords(this, an, example)
+
+var s = ""
+for w in items(myWordList):
+  s.add(w)
+
+echo s #OUT thisanexample
diff --git a/tests/macros/trecmacro.nim b/tests/macros/trecmacro.nim
new file mode 100644
index 000000000..d804178bc
--- /dev/null
+++ b/tests/macros/trecmacro.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "recursive dependency: 'dump'"
+  file: "trecmacro.nim"
+  line: 8
+"""
+
+macro dump(n: untyped): untyped =
+  dump(n)
+  if kind(n) == nnkNone:
+    nil
+  else:
+    hint($kind(n))
+    for i in countUp(0, len(n)-1):
+      nil
diff --git a/tests/macros/treturnsempty.nim b/tests/macros/treturnsempty.nim
new file mode 100644
index 000000000..a5a678af3
--- /dev/null
+++ b/tests/macros/treturnsempty.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "type mismatch"
+  line: 11
+"""
+# bug #2372
+macro foo(dummy: int): untyped =
+  discard
+
+proc takeStr(s: string) = echo s
+
+takeStr foo(12)
diff --git a/tests/macros/tsame_name_497.nim b/tests/macros/tsame_name_497.nim
new file mode 100644
index 000000000..9f26a4024
--- /dev/null
+++ b/tests/macros/tsame_name_497.nim
@@ -0,0 +1,6 @@
+
+import macro_bug
+
+type TObj = object
+
+proc f(o: TObj) {.macro_bug.} = discard
diff --git a/tests/macros/tsametype.nim b/tests/macros/tsametype.nim
new file mode 100644
index 000000000..5219a3767
--- /dev/null
+++ b/tests/macros/tsametype.nim
@@ -0,0 +1,42 @@
+discard """
+output: '''true
+false
+true
+false
+true
+false
+true
+false
+true
+false'''
+joinable: false
+"""
+
+import macros
+
+macro same(a: typedesc, b: typedesc): untyped =
+  newLit(a.getType[1].sameType b.getType[1])
+
+echo same(int, int)
+echo same(int, float)
+
+type
+  SomeInt = int
+  DistinctInt = distinct int
+  SomeFloat = float
+  DistinctFloat = distinct float
+
+echo same(int, SomeInt)
+echo same(int, DistinctInt)
+echo same(float, SomeFloat)
+echo same(float, DistinctFloat)
+
+type
+  Obj = object of RootObj
+  SubObj = object of Obj
+  Other = object of RootObj
+
+echo same(Obj, Obj)
+echo same(int, Obj)
+echo same(SubObj, SubObj)
+echo same(Other, Obj)
diff --git a/tests/macros/tslice.nim b/tests/macros/tslice.nim
new file mode 100644
index 000000000..c64289ec6
--- /dev/null
+++ b/tests/macros/tslice.nim
@@ -0,0 +1,38 @@
+import macros
+
+macro test(): untyped =
+  result = nnkStmtList.newTree()
+  let n = nnkStmtList.newTree(
+    newIdentNode("one"),
+    newIdentNode("two"),
+    newIdentNode("three"),
+    newIdentNode("four"),
+    newIdentNode("five"),
+    newIdentNode("six")
+  )
+
+  var i = 1
+  for x in n[1 .. ^2]:
+    assert x == n[i]
+    i.inc
+  assert i == 5
+
+  i = 3
+  for x in n[3..^1]:
+    assert x == n[i]
+    i.inc
+  assert i == 6
+
+  i = 0
+  for x in n[0..3]:
+    assert x == n[i]
+    i.inc
+  assert i == 4
+
+  i = 0
+  for x in n[0..5]:
+    assert x == n[i]
+    i.inc
+  assert i == 6
+
+test()
diff --git a/tests/macros/tstaticparamsmacro.nim b/tests/macros/tstaticparamsmacro.nim
new file mode 100644
index 000000000..2632ca730
--- /dev/null
+++ b/tests/macros/tstaticparamsmacro.nim
@@ -0,0 +1,75 @@
+discard """
+  nimout: '''
+letters
+aa
+bb
+numbers
+11
+22
+AST a
+@[(c: 11, d: 22), (c: 33, d: 44)]
+AST b
+(e: @[55, 66], f: @[77, 88])
+55
+10
+20Test
+20
+'''
+"""
+
+import macros
+
+type
+  TConfig = tuple
+    letters: seq[string]
+    numbers:seq[int]
+
+const data: Tconfig = (@["aa", "bb"], @[11, 22])
+
+macro mymacro(data: static[TConfig]): untyped =
+  echo "letters"
+  for s in items(data.letters):
+    echo s
+  echo "numbers"
+  for n in items(data.numbers):
+    echo n
+
+mymacro(data)
+
+type
+  Ta = seq[tuple[c:int, d:int]]
+  Tb = tuple[e:seq[int], f:seq[int]]
+
+const
+  a : Ta = @[(11, 22), (33, 44)]
+  b : Tb = (@[55,66], @[77, 88])
+
+macro mA(data: static[Ta]): untyped =
+  echo "AST a\n", repr(data)
+
+macro mB(data: static[Tb]): untyped =
+  echo "AST b\n", repr(data)
+  echo data.e[0]
+
+mA(a)
+mB(b)
+
+type
+  Foo[N: static[int], Z: static[string]] = object
+
+macro staticIntMacro(f: static[int]): untyped = echo f
+staticIntMacro 10
+
+var
+  x: Foo[20, "Test"]
+
+macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): untyped =
+  echo N, Z
+
+genericMacro x
+
+template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
+
+static:
+  echo genericTemplate(x)
+
diff --git a/tests/macros/tstringinterp.nim b/tests/macros/tstringinterp.nim
new file mode 100644
index 000000000..74c73599b
--- /dev/null
+++ b/tests/macros/tstringinterp.nim
@@ -0,0 +1,73 @@
+discard """
+  output: "Hello Alice, 64 | Hello Bob, 10$"
+"""
+
+import macros, parseutils, strutils
+
+proc concat(strings: varargs[string]): string =
+  result = newString(0)
+  for s in items(strings): result.add(s)
+
+template processInterpolations(e) =
+  var s = e[1].strVal
+  for f in interpolatedFragments(s):
+    case f.kind
+    of ikStr:         addString(f.value)
+    of ikDollar:      addDollar()
+    of ikVar, ikExpr: addExpr(newCall("$", parseExpr(f.value)))
+
+macro formatStyleInterpolation(e: untyped): untyped =
+  let e = callsite()
+  var
+    formatString = ""
+    arrayNode = newNimNode(nnkBracket)
+    idx = 1
+
+  proc addString(s: string) =
+    formatString.add(s)
+
+  proc addExpr(e: NimNode) =
+    arrayNode.add(e)
+    formatString.add("$" & $(idx))
+    inc idx
+
+  proc addDollar() =
+    formatString.add("$$")
+
+  processInterpolations(e)
+
+  result = parseExpr("\"x\" % [y]")
+  result[1].strVal = formatString
+  result[2] = arrayNode
+
+macro concatStyleInterpolation(e: untyped): untyped =
+  let e = callsite()
+  var args: seq[NimNode]
+  newSeq(args, 0)
+
+  proc addString(s: string)    = args.add(newStrLitNode(s))
+  proc addExpr(e: NimNode) = args.add(e)
+  proc addDollar()             = args.add(newStrLitNode"$")
+
+  processInterpolations(e)
+
+  result = newCall("concat", args)
+
+###
+
+proc sum(a, b, c: int): int =
+  return (a + b + c)
+
+var
+  alice = "Alice"
+  bob = "Bob"
+  a = 10
+  b = 20
+  c = 34
+
+var
+  s1 = concatStyleInterpolation"Hello ${alice}, ${sum(a, b, c)}"
+  s2 = formatStyleInterpolation"Hello ${bob}, ${sum(alice.len, bob.len, 2)}$$"
+
+write(stdout, s1 & " | " & s2)
+write(stdout, "\n")
diff --git a/tests/macros/tstructuredlogging.nim b/tests/macros/tstructuredlogging.nim
new file mode 100644
index 000000000..649c6c0bd
--- /dev/null
+++ b/tests/macros/tstructuredlogging.nim
@@ -0,0 +1,154 @@
+discard """
+output: '''
+main started: a=10, b=inner-b, c=10, d=some-d, x=16, z=20
+exiting: a=12, b=overridden-b, c=100, msg=bye bye, x=16
+'''
+"""
+
+import macros, tables
+
+template scopeHolder =
+  0 # scope revision number
+
+type
+  BindingsSet = Table[string, NimNode]
+
+proc actualBody(n: NimNode): NimNode =
+  # skip over the double StmtList node introduced in `mergeScopes`
+  result = n.body
+  if result.kind == nnkStmtList and result[0].kind == nnkStmtList:
+    result = result[0]
+
+iterator bindings(n: NimNode, skip = 0): (string, NimNode) =
+  for i in skip ..< n.len:
+    let child = n[i]
+    if child.kind in {nnkAsgn, nnkExprEqExpr}:
+      let name = $child[0]
+      let value = child[1]
+      yield (name, value)
+
+proc scopeRevision(scopeHolder: NimNode): int =
+  # get the revision number from a scopeHolder sym
+  assert scopeHolder.kind == nnkSym
+  var revisionNode = scopeHolder.getImpl.actualBody[0]
+  result = int(revisionNode.intVal)
+
+proc lastScopeHolder(scopeHolders: NimNode): NimNode =
+  # get the most recent scopeHolder from a symChoice node
+  if scopeHolders.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
+    var bestScopeRev = 0
+    assert scopeHolders.len > 0
+    for scope in scopeHolders:
+      let rev = scope.scopeRevision
+      if result == nil or rev > bestScopeRev:
+        result = scope
+        bestScopeRev = rev
+  else:
+    result = scopeHolders
+
+  assert result.kind == nnkSym
+
+macro mergeScopes(scopeHolders: typed, newBindings: untyped): untyped =
+  var
+    bestScope = scopeHolders.lastScopeHolder
+    bestScopeRev = bestScope.scopeRevision
+
+  var finalBindings = initTable[string, NimNode]()
+  for k, v in bindings(bestScope.getImpl.actualBody, skip = 1):
+    finalBindings[k] = v
+
+  for k, v in bindings(newBindings):
+    finalBindings[k] = v
+
+  var newScopeDefinition = newStmtList(newLit(bestScopeRev + 1))
+
+  for k, v in finalBindings:
+    newScopeDefinition.add newAssignment(newIdentNode(k), v)
+
+  result = quote:
+    template scopeHolder {.redefine.} = `newScopeDefinition`
+
+template scope(newBindings: untyped) {.dirty.} =
+  mergeScopes(bindSym"scopeHolder", newBindings)
+
+type
+  TextLogRecord = object
+    line: string
+
+  StdoutLogRecord = object
+
+template setProperty(r: var TextLogRecord, key: string, val: string, isFirst: bool) =
+  if not first: r.line.add ", "
+  r.line.add key
+  r.line.add "="
+  r.line.add val
+
+template setEventName(r: var StdoutLogRecord, name: string) =
+  stdout.write(name & ": ")
+
+template setProperty(r: var StdoutLogRecord, key: string, val: auto, isFirst: bool) =
+  when not isFirst: stdout.write ", "
+  stdout.write key
+  stdout.write "="
+  stdout.write $val
+
+template flushRecord(r: var StdoutLogRecord) =
+  stdout.write "\n"
+  stdout.flushFile
+
+macro logImpl(scopeHolders: typed,
+              logStmtProps: varargs[untyped]): untyped =
+  let lexicalScope = scopeHolders.lastScopeHolder.getImpl.actualBody
+  var finalBindings = initOrderedTable[string, NimNode]()
+
+  for k, v in bindings(lexicalScope, skip = 1):
+    finalBindings[k] = v
+
+  for k, v in bindings(logStmtProps, skip = 1):
+    finalBindings[k] = v
+
+  finalBindings.sort(system.cmp)
+
+  let eventName = logStmtProps[0]
+  assert eventName.kind in {nnkStrLit}
+  let record = genSym(nskVar, "record")
+
+  result = quote:
+    var `record`: StdoutLogRecord
+    setEventName(`record`, `eventName`)
+
+  var isFirst = true
+  for k, v in finalBindings:
+    result.add newCall(newIdentNode"setProperty",
+                       record, newLit(k), v, newLit(isFirst))
+    isFirst = false
+
+  result.add newCall(newIdentNode"flushRecord", record)
+
+template log(props: varargs[untyped]) {.dirty.} =
+  logImpl(bindSym"scopeHolder", props)
+
+scope:
+  a = 12
+  b = "original-b"
+
+scope:
+  x = 16
+  b = "overridden-b"
+
+scope:
+  c = 100
+
+proc main =
+  scope:
+    c = 10
+
+  scope:
+    z = 20
+
+  log("main started", a = 10, b = "inner-b", d = "some-d")
+
+main()
+
+log("exiting", msg = "bye bye")
+
diff --git a/tests/macros/ttemplatesymbols.nim b/tests/macros/ttemplatesymbols.nim
new file mode 100644
index 000000000..3182de79d
--- /dev/null
+++ b/tests/macros/ttemplatesymbols.nim
@@ -0,0 +1,171 @@
+import
+  macros, algorithm, strutils
+
+proc normalProc(x: int) =
+  echo x
+
+template templateWithtouParams =
+  echo 10
+
+proc overloadedProc(x: int) =
+  echo x
+
+proc overloadedProc(x: string) =
+  echo x
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+template normalTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+macro normalMacro(x: int): untyped =
+  discard
+
+macro macroWithoutParams: untyped =
+  discard
+
+macro inspectSymbol(sym: typed, expected: static[string]): untyped =
+  if sym.kind == nnkSym:
+    echo "Symbol node:"
+    let res = sym.getImpl.repr & "\n"
+    echo res
+    # echo "|", res, "|"
+    # echo "|", expected, "|"
+    if expected.len > 0: assert res == expected
+  elif sym.kind in {nnkClosedSymChoice, nnkOpenSymChoice}:
+    echo "Begin sym choice:"
+    var results = newSeq[string](0)
+    for innerSym in sym:
+      results.add innerSym.getImpl.repr
+    sort(results, cmp[string])
+    let res = results.join("\n") & "\n"
+    echo res
+    if expected.len > 0: assert res == expected
+    echo "End symchoice."
+  else:
+    echo "Non-symbol node: ", sym.kind
+    if expected.len > 0: assert $sym.kind == expected
+
+macro inspectUntyped(sym: untyped, expected: static[string]): untyped =
+  let res = sym.repr
+  echo "Untyped node: ", res
+  assert res == expected
+
+inspectSymbol templateWithtouParams, "nnkCommand"
+  # this template is expanded, because bindSym was not used
+  # the end result is the template body (nnkCommand)
+
+inspectSymbol bindSym("templateWithtouParams"), """
+template templateWithtouParams() =
+  echo 10
+
+"""
+
+inspectSymbol macroWithoutParams, "nnkEmpty"
+  # Just like the template above, the macro was expanded
+
+inspectSymbol bindSym("macroWithoutParams"), """
+macro macroWithoutParams(): untyped =
+  discard
+
+"""
+
+inspectSymbol normalMacro, """
+macro normalMacro(x: int): untyped =
+  discard
+
+"""
+  # Since the normalMacro has params, it's automatically
+  # treated as a symbol here (no need for `bindSym`)
+
+inspectSymbol bindSym("normalMacro"), """
+macro normalMacro(x: int): untyped =
+  discard
+
+"""
+
+inspectSymbol normalTemplate, """
+template normalTemplate(x: int) =
+  echo x
+
+"""
+
+inspectSymbol bindSym("normalTemplate"), """
+template normalTemplate(x: int) =
+  echo x
+
+"""
+
+inspectSymbol overloadedTemplate, """
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+"""
+
+inspectSymbol bindSym("overloadedTemplate"), """
+template overloadedTemplate(x: int) =
+  echo x
+
+template overloadedTemplate(x: string) =
+  echo x
+
+"""
+
+inspectUntyped bindSym("overloadedTemplate"), """bindSym("overloadedTemplate")"""
+  # binSym is active only in the presence of `typed` params.
+  # `untyped` params still get the raw AST
+
+inspectSymbol normalProc, """
+proc normalProc(x: int) =
+  echo [x]
+
+"""
+
+inspectSymbol bindSym("normalProc"), """
+proc normalProc(x: int) =
+  echo [x]
+
+"""
+
+inspectSymbol overloadedProc, """
+proc overloadedProc(x: int) =
+  echo [x]
+
+proc overloadedProc(x: string) =
+  echo [x]
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+"""
+
+inspectSymbol overloadedProc[float], """
+proc overloadedProc(x: T) =
+  echo [x]
+
+"""
+  # As expected, when we select a specific generic, the
+  # AST is no longer a symChoice
+
+inspectSymbol bindSym("overloadedProc"), """
+proc overloadedProc(x: int) =
+  echo [x]
+
+proc overloadedProc(x: string) =
+  echo [x]
+
+proc overloadedProc[T](x: T) =
+  echo x
+
+"""
+
diff --git a/tests/macros/ttryparseexpr.nim b/tests/macros/ttryparseexpr.nim
new file mode 100644
index 000000000..e6e9e9880
--- /dev/null
+++ b/tests/macros/ttryparseexpr.nim
@@ -0,0 +1,24 @@
+discard """
+  outputsub: '''Error: expression expected, but found '[EOF]' 45'''
+"""
+
+# feature request #1473
+import macros
+
+macro test(text: string): untyped =
+  try:
+    result = parseExpr(text.strVal)
+  except ValueError:
+    result = newLit getCurrentExceptionMsg()
+
+const
+  valid = 45
+  a = test("foo&&")
+  b = test("valid")
+  c = test("\"") # bug #2504
+
+echo a, " ", b
+
+static:
+  # Issue #9918
+  discard parseStmt("echo(1+1);")
diff --git a/tests/macros/ttypenodes.nim b/tests/macros/ttypenodes.nim
new file mode 100644
index 000000000..233ea9780
--- /dev/null
+++ b/tests/macros/ttypenodes.nim
@@ -0,0 +1,16 @@
+import macros
+
+macro makeEnum(): untyped =
+  newTree(nnkEnumTy, newEmptyNode(), ident"a", ident"b", ident"c")
+
+macro makeObject(): untyped =
+  newTree(nnkObjectTy, newEmptyNode(), newEmptyNode(), newTree(nnkRecList,
+    newTree(nnkIdentDefs, ident"x", ident"y", ident"int", newEmptyNode())))
+
+type
+  Foo = makeEnum()
+  Bar = makeObject()
+
+doAssert {a, b, c} is set[Foo]
+let bar = Bar(x: 3, y: 4)
+doAssert (bar.x, bar.y) == (3, 4)
diff --git a/tests/macros/tvarargsuntyped.nim b/tests/macros/tvarargsuntyped.nim
new file mode 100644
index 000000000..5a06adcca
--- /dev/null
+++ b/tests/macros/tvarargsuntyped.nim
@@ -0,0 +1,108 @@
+discard """
+  output: '''Let's go!
+(left: 2, r: 7, x: 8, height: 4, s: test, width: 3, y: 9, top: 1, g: 7, b: 8)
+(left: 2, r: 7, x: 8, height: 4, s: text, width: 3, y: 9, top: 1, g: 7, b: 8)
+(left: 2, r: 7, x: 8, height: 4, s: text, width: 3, y: 9, top: 4, g: 7, b: 8)
+(left: 2, r: 7, x: 8, height: 4, s: test, width: 3, y: 9, top: 1, g: 7, b: 8)
+10
+hello 18.0'''
+"""
+
+import macros
+
+proc internalBar(top, left, width, height: cint, s: string, x, y: int, r,g,b: int) =
+  echo "(left: ", left, ", r: ", r, ", x: ", x, ", height: ", height, ", s: ", s,
+    ", width: ", width, ", y: ", y, ", top: ", top, ", g: ", g, ", b: ", b, ")"
+
+# we need these dummy constructors due to the wrong implementation
+# of 'varargs[untyped]' in the compiler:
+
+proc point(x, y: int): int = discard
+proc color(r, g, b: int): int = discard
+proc rect(a, b, c, d: int): int = discard
+
+template declareUnpackingMacro(nimname,extname) =
+  macro nimname(n: varargs[untyped]): untyped =
+    var s: string = astToStr(extname) & "("
+    var first = true
+    echo repr n
+    for x in n.children:
+      var unpack = false
+      if x.kind in nnkCallKinds:
+        case $x[0]
+        of "point":
+          expectLen(x, 3)
+          unpack = true
+        of "rect":
+          expectLen(x, 5)
+          unpack = true
+        of "color":
+          expectLen(x, 4)
+          unpack = true
+        else: discard
+      if unpack:
+        for i in 1..<x.len:
+          if first:
+            first = false
+          else:
+            add(s, ", ")
+          add(s, repr(x[i]))
+      else:
+        if first:
+          first = false
+        else:
+          add(s, ", ")
+        add(s, repr(x))
+
+    add(s, ")")
+    echo s
+    result = parseStmt(s)
+
+declareUnpackingMacro(bar,internalBar)
+
+type MyInt = distinct int
+
+proc myInt(i: int): MyInt = cast[MyInt](i)
+
+converter toCInt(mi: MyInt): cint = cast[cint](mi)
+
+echo "Let's go!"
+
+bar(rect(1, 2, 3, 4), "test", point(8, 9), color(7,7,8))
+
+bar(1,2,3,4,"text",8,9,7,7,8)
+
+bar(myInt(4),2,3,4,"text",8,9,7,7,8)
+
+let top: cint = 1
+let left: cint = 2
+let width: cint = 3
+let height: cint = 4
+
+bar(rect(top, left, width, height), "test", point(8, 9), color(7,7,8))
+
+
+# bug #10075
+
+import macros
+
+proc convert_hidden_stdconv(args: NimNode): NimNode =
+  var n = args
+  while n.len == 1 and n[0].kind == nnkHiddenStdConv:
+    n = n[0][1]
+  return n
+
+macro t2(s: int, v: varargs[untyped]): untyped =
+  let v = convert_hidden_stdconv(v)
+  echo v.treeRepr
+  let (v1, v2) = (v[0], v[1])
+  quote do:
+    echo `v1`, " ", `v2`
+
+template t1(s: int, v: varargs[typed]) =
+  #static:
+  #   dumpTree v
+  echo s
+  t2(s, v)
+
+t1(10, "hello", 18.0)
diff --git a/tests/macros/tvtable.nim b/tests/macros/tvtable.nim
new file mode 100644
index 000000000..0f322b7d5
--- /dev/null
+++ b/tests/macros/tvtable.nim
@@ -0,0 +1,74 @@
+discard """
+  output: '''
+OBJ 1 foo
+10
+OBJ 1 bar
+OBJ 2 foo
+5
+OBJ 2 bar
+'''
+"""
+
+type
+  # these are the signatures of the virtual procs for each type
+  fooProc[T] = proc (o: var T): int {.nimcall.}
+  barProc[T] = proc (o: var T) {.nimcall.}
+
+  # an untyped table to store the proc pointers
+  # it's also possible to use a strongly typed tuple here
+  VTable = array[0..1, pointer]
+
+  TBase {.inheritable.} = object
+    vtbl: ptr VTable
+
+  TUserObject1 = object of TBase
+    x: int
+
+  TUserObject2 = object of TBase
+    y: int
+
+proc foo(o: var TUserObject1): int =
+  echo "OBJ 1 foo"
+  return 10
+
+proc bar(o: var TUserObject1) =
+  echo "OBJ 1 bar"
+
+proc foo(o: var TUserObject2): int =
+  echo "OBJ 2 foo"
+  return 5
+
+proc bar(o: var TUserObject2) =
+  echo "OBJ 2 bar"
+
+proc getVTable(T: typedesc): ptr VTable =
+  # pay attention to what's going on here
+  # this will initialize the vtable for each type at program start-up
+  #
+  # fooProc[T](foo) is a type coercion - it looks for a proc named foo
+  # matching the signature fooProc[T] (e.g. proc (o: var TUserObject1): int)
+  var vtbl {.global.} = [
+    cast[pointer](fooProc[T](foo)),
+    cast[pointer](barProc[T](bar))
+  ]
+
+  return vtbl.addr
+
+proc create(T: typedesc): T =
+  result.vtbl = getVTable(T)
+
+proc baseFoo(o: var TBase): int =
+  return cast[fooProc[TBase]](o.vtbl[0])(o)
+
+proc baseBar(o: var TBase) =
+  cast[barProc[TBase]](o.vtbl[1])(o)
+
+var a = TUserObject1.create
+var b = TUserObject2.create
+
+echo a.baseFoo
+a.baseBar
+
+echo b.baseFoo
+b.baseBar
+
diff --git a/tests/macros/twrapiterator.nim b/tests/macros/twrapiterator.nim
new file mode 100644
index 000000000..e153ae980
--- /dev/null
+++ b/tests/macros/twrapiterator.nim
@@ -0,0 +1,19 @@
+
+import macros
+
+# bug #7093
+
+macro foobar(arg: untyped): untyped =
+  let procDef = quote do:
+    proc foo(): void =
+      echo "bar"
+
+
+  result = newStmtList(
+    arg, procDef
+  )
+
+  echo result.repr
+
+iterator bar(): int {.foobar.} =
+  discard
diff --git a/tests/macros/typesafeprintf.nim b/tests/macros/typesafeprintf.nim
new file mode 100644
index 000000000..daf213bd3
--- /dev/null
+++ b/tests/macros/typesafeprintf.nim
@@ -0,0 +1,49 @@
+discard """
+  output: '''test 10'''
+"""
+
+# bug #1152
+
+import macros, typetraits
+proc printfImpl(formatstr: cstring) {.importc: "printf", varargs.}
+
+iterator tokenize(format: string): char =
+  var i = 0
+  while i < format.len:
+    case format[i]
+    of '%':
+      case format[i+1]
+      of '\0': break
+      else: yield format[i+1]
+      i.inc
+    of '\0': break
+    else: discard
+    i.inc
+
+macro printf(formatString: string{lit}, args: varargs[typed]): untyped =
+  var i = 0
+  let err = getType(bindSym"ValueError")
+  for c in tokenize(formatString.strVal):
+    var expectedType = case c
+      of 'c': getType(bindSym"char")
+      of 'd', 'i', 'x', 'X': getType(bindSym"int")
+      of 'f', 'e', 'E', 'g', 'G': getType(bindSym"float")
+      of 's': getType(bindSym"string")
+      of 'p': getType(bindSym"pointer")
+      else: err
+
+    var actualType = getType(args[i])
+    inc i
+
+    if sameType(expectedType, err):
+      error c & " is not a valid format character"
+    elif not sameType(expectedType, actualType):
+      error "type mismatch for argument " & $i & ". expected type: " &
+            $expectedType & ", actual type: " & $actualType
+
+  # keep the original callsite, but use cprintf instead
+  result = newCall(bindSym"printfImpl")
+  result.add formatString
+  for a in args: result.add a
+
+printf("test %d\n", 10)
diff --git a/tests/macros/typesapi2.nim b/tests/macros/typesapi2.nim
new file mode 100644
index 000000000..0130049c0
--- /dev/null
+++ b/tests/macros/typesapi2.nim
@@ -0,0 +1,48 @@
+# tests to see if a symbol returned from macros.getType() can
+# be used as a type
+import macros
+
+macro testTypesym (t:typed): untyped =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    assert ty[0].kind == nnkSym
+    result = ty[0]
+    return
+
+type TestFN = proc(a,b:int):int
+var iii: testTypesym(TestFN)
+static: assert iii is TestFN
+
+proc foo11 : testTypesym(void) =
+    echo "HI!"
+static: assert foo11 is (proc():void {.nimcall.})
+
+var sss: testTypesym(seq[int])
+static: assert sss is seq[int]
+# very nice :>
+
+static: assert array[2,int] is testTypesym(array[2,int])
+static: assert(ref int is testTypesym(ref int))
+static: assert(void is testTypesym(void))
+
+
+macro tts2 (t:typed, idx:int): untyped =
+    var ty = t.getType
+    if ty.typekind == ntyTypedesc:
+        # skip typedesc get to the real type
+        ty = ty[1].getType
+
+    if ty.kind == nnkSym: return ty
+    assert ty.kind == nnkBracketExpr
+    return ty[idx.intval.int]
+type TestFN2 = proc(a:int,b:float):string
+static:
+    assert(tts2(TestFN2, 0) is TestFN2)
+    assert(tts2(TestFN2, 1) is string)
+    assert(tts2(TestFN2, 2) is int)
+    assert(tts2(TestFN2, 3) is float)
diff --git a/tests/manyloc/argument_parser/argument_parser.nim b/tests/manyloc/argument_parser/argument_parser.nim
new file mode 100644
index 000000000..0ad57167b
--- /dev/null
+++ b/tests/manyloc/argument_parser/argument_parser.nim
@@ -0,0 +1,493 @@
+## Command line parsing module for Nim.
+##
+## `Nim <http://nim-lang.org>`_ provides the `parseopt module
+## <http://nim-lang.org/parseopt.html>`_ to parse options from the
+## commandline. This module tries to provide functionality to prevent you from
+## writing commandline parsing and let you concentrate on providing the best
+## possible experience for your users.
+##
+## Source code for this module can be found at
+## https://github.com/gradha/argument_parser.
+
+import os, strutils, tables, math, parseutils, sequtils, sets, algorithm,
+  unicode
+
+const
+  VERSION_STR* = "0.1.2" ## Module version as a string.
+  VERSION_INT* = (major: 0, minor: 1, maintenance: 2) ## \
+  ## Module version as an integer tuple.
+  ##
+  ## Major versions changes mean a break in API backwards compatibility, either
+  ## through removal of symbols or modification of their purpose.
+  ##
+  ## Minor version changes can add procs (and maybe default parameters). Minor
+  ## odd versions are development/git/unstable versions. Minor even versions
+  ## are public stable releases.
+  ##
+  ## Maintenance version changes mean bugfixes or non API changes.
+
+# - Types
+
+type
+  Tparam_kind* = enum ## Different types of results for parameter parsing.
+    PK_EMPTY, PK_INT, PK_FLOAT, PK_STRING, PK_BOOL,
+    PK_BIGGEST_INT, PK_BIGGEST_FLOAT, PK_HELP
+
+  Tparameter_callback* =
+    proc (parameter: string; value: var Tparsed_parameter): string ## \
+    ## Prototype of parameter callbacks
+    ##
+    ## A parameter callback is just a custom proc you provide which is invoked
+    ## after a parameter is parsed passing the basic type validation. The
+    ## `parameter` parameter is the string which triggered the option. The
+    ## `value` parameter contains the string passed by the user already parsed
+    ## into the basic type you specified for it.
+    ##
+    ## The callback proc has modification access to the Tparsed_parameter
+    ## `value` parameter that will be put into Tcommandline_results: you can
+    ## read it and also modify it, maybe changing its type. In fact, if you
+    ## need special parsing, most likely you will end up specifying PK_STRING
+    ## in the parameter input specification so that the parse() proc doesn't
+    ## *mangle* the string before you can process it yourself.
+    ##
+    ## If the callback decides to abort the validation of the parameter, it has
+    ## to put into result a non zero length string with a message for the user
+    ## explaining why the validation failed, and maybe offer a hint as to what
+    ## can be done to pass validation.
+
+  Tparameter_specification* = object ## \
+    ## Holds the expectations of a parameter.
+    ##
+    ## You create these objects and feed them to the parse() proc, which then
+    ## uses them to detect parameters and turn them into something uself.
+    names*: seq[string]  ## List of possible parameters to catch for this.
+    consumes*: Tparam_kind ## Expected type of the parameter (empty for none)
+    custom_validator*: Tparameter_callback  ## Optional custom callback
+                                            ## to run after type conversion.
+    help_text*: string    ## Help for this group of parameters.
+
+  Tparsed_parameter* = object ## \
+    ## Contains the parsed value from the user.
+    ##
+    ## This implements an object variant through the kind field. You can 'case'
+    ## this field to write a generic proc to deal with parsed parameters, but
+    ## nothing prevents you from accessing directly the type of field you want
+    ## if you expect only one kind.
+    case kind*: Tparam_kind
+    of PK_EMPTY: discard
+    of PK_INT: int_val*: int
+    of PK_BIGGEST_INT: big_int_val*: BiggestInt
+    of PK_FLOAT: float_val*: float
+    of PK_BIGGEST_FLOAT: big_float_val*: BiggestFloat
+    of PK_STRING: str_val*: string
+    of PK_BOOL: bool_val*: bool
+    of PK_HELP: discard
+
+  Tcommandline_results* = object of RootObj ## \
+    ## Contains the results of the parsing.
+    ##
+    ## Usually this is the result of the parse() call, but you can inherit from
+    ## it to add your own fields for convenience.
+    ##
+    ## Note that you always have to access the ``options`` ordered table with
+    ## the first variant of a parameter name. For instance, if you have an
+    ## option specified like ``@["-s", "--silent"]`` and the user types
+    ## ``--silent`` at the commandline, you have to use
+    ## ``options.hasKey("-s")`` to test for it. This standarizes access through
+    ## the first name variant for all options to avoid you repeating the test
+    ## with different keys.
+    positional_parameters*: seq[Tparsed_parameter]
+    options*: OrderedTable[string, Tparsed_parameter]
+
+
+# - Tparam_kind procs
+
+proc `$`*(value: Tparam_kind): string =
+  ## Stringifies the type, used to generate help texts.
+  case value:
+  of PK_EMPTY: result = ""
+  of PK_INT: result = "INT"
+  of PK_BIGGEST_INT: result = "BIG_INT"
+  of PK_FLOAT: result = "FLOAT"
+  of PK_BIGGEST_FLOAT: result = "BIG_FLOAG"
+  of PK_STRING: result = "STRING"
+  of PK_BOOL: result = "BOOL"
+  of PK_HELP: result = ""
+
+# - Tparameter_specification procs
+
+proc init*(param: var Tparameter_specification, consumes = PK_EMPTY,
+    custom_validator: Tparameter_callback = nil, help_text = "",
+    names: varargs[string]) =
+  ## Initialization helper with default parameters.
+  ##
+  ## You can decide to miss some if you like the defaults, reducing code. You
+  ## can also use new_parameter_specification() for single assignment
+  ## variables.
+  param.names = @names
+  param.consumes = consumes
+  param.custom_validator = custom_validator
+  param.help_text = help_text
+
+proc new_parameter_specification*(consumes = PK_EMPTY,
+    custom_validator: Tparameter_callback = nil, help_text = "",
+    names: varargs[string]): Tparameter_specification =
+  ## Initialization helper for single assignment variables.
+  result.init(consumes, custom_validator, help_text, names)
+
+# - Tparsed_parameter procs
+
+proc `$`*(data: Tparsed_parameter): string =
+  ## Stringifies the value, mostly for debug purposes.
+  ##
+  ## The proc will display the value followed by non string type in brackets.
+  ## The non string types would be PK_INT (i), PK_BIGGEST_INT (I), PK_FLOAT
+  ## (f), PK_BIGGEST_FLOAT (F), PK_BOOL (b). The string type would be enclosed
+  ## inside quotes. PK_EMPTY produces the word `nil`, and PK_HELP produces the
+  ## world `help`.
+  case data.kind:
+  of PK_EMPTY: result = "nil"
+  of PK_INT: result = "$1(i)" % $data.int_val
+  of PK_BIGGEST_INT: result = "$1(I)" % $data.big_int_val
+  of PK_FLOAT: result = "$1(f)" % $data.float_val
+  of PK_BIGGEST_FLOAT: result = "$1(F)" % $data.big_float_val
+  of PK_STRING: result = "\"" & $data.str_val & "\""
+  of PK_BOOL: result = "$1(b)" % $data.bool_val
+  of PK_HELP: result = "help"
+
+
+template new_parsed_parameter*(tkind: Tparam_kind, expr): Tparsed_parameter =
+  ## Handy compile time template to build Tparsed_parameter object variants.
+  ##
+  ## The problem with object variants is that you first have to initialise them
+  ## to a kind, then assign values to the correct variable, and it is a little
+  ## bit annoying.
+  ##
+  ## Through this template you specify as the first parameter the kind of the
+  ## Tparsed_parameter you want to build, and directly the value it will be
+  ## initialised with. The template figures out at compile time what field to
+  ## assign the variable to, and thus you reduce code clutter and may use this
+  ## to initialise single assignments variables in `let` blocks. Example:
+  ##   ```nim
+  ##   let
+  ##     parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41)
+  ##     parsed_param2 = new_parsed_parameter(PK_BIGGEST_INT, 2358123 * 23123)
+  ##     # The following line doesn't compile due to
+  ##     # type mismatch: got <string> but expected 'int'
+  ##     #parsed_param3 = new_parsed_parameter(PK_INT, "231")
+  ##   ```
+  var result {.gensym.}: Tparsed_parameter
+  result.kind = tkind
+  when tkind == PK_EMPTY: discard
+  elif tkind == PK_INT: result.int_val = expr
+  elif tkind == PK_BIGGEST_INT: result.big_int_val = expr
+  elif tkind == PK_FLOAT: result.float_val = expr
+  elif tkind == PK_BIGGEST_FLOAT: result.big_float_val = expr
+  elif tkind == PK_STRING: result.str_val = expr
+  elif tkind == PK_BOOL: result.bool_val = expr
+  elif tkind == PK_HELP: discard
+  else: {.error: "unknown kind".}
+  result
+
+# - Tcommandline_results procs
+
+proc init*(param: var Tcommandline_results;
+    positional_parameters: seq[Tparsed_parameter] = @[];
+    options: OrderedTable[string, Tparsed_parameter] =
+      initOrderedTable[string, Tparsed_parameter](4)) =
+  ## Initialization helper with default parameters.
+  param.positional_parameters = positional_parameters
+  param.options = options
+
+proc `$`*(data: Tcommandline_results): string =
+  ## Stringifies a Tcommandline_results structure for debug output
+  var dict: seq[string] = @[]
+  for key, value in data.options:
+    dict.add("$1: $2" % [escape(key), $value])
+  result = "Tcommandline_result{positional_parameters:[$1], options:{$2}}" % [
+    join(map(data.positional_parameters, `$`), ", "), join(dict, ", ")]
+
+# - Parse code
+
+template raise_or_quit(exception, message: untyped) =
+  ## Avoids repeating if check based on the default quit_on_failure variable.
+  ##
+  ## As a special case, if message has a zero length the call to quit won't
+  ## generate any messages or errors (used by the mechanism to echo help to the
+  ## user).
+  if quit_on_failure:
+    if len(message) > 0:
+      quit(message)
+    else:
+      quit()
+  else:
+    raise newException(exception, message)
+
+template run_custom_proc(parsed_parameter: Tparsed_parameter,
+    custom_validator: Tparameter_callback,
+    parameter: string) =
+  ## Runs the custom validator if it is not nil.
+  ##
+  ## Pass in the string of the parameter triggering the call. If the
+  if not custom_validator.isNil:
+    try:
+      let message = custom_validator(parameter, parsed_parameter)
+      if message.len > 0:
+        raise_or_quit(ValueError, ("Failed to validate value for " &
+          "parameter $1:\n$2" % [escape(parameter), message]))
+    except:
+      raise_or_quit(ValueError, ("Couldn't run custom proc for " &
+        "parameter $1:\n$2" % [escape(parameter),
+        getCurrentExceptionMsg()]))
+
+proc parse_parameter(quit_on_failure: bool, param, value: string,
+    param_kind: Tparam_kind): Tparsed_parameter =
+  ## Tries to parse a text according to the specified type.
+  ##
+  ## Pass the parameter string which requires a value and the text the user
+  ## passed in for it. It will be parsed according to the param_kind. This proc
+  ## will raise (ValueError, EOverflow) if something can't be parsed.
+  result.kind = param_kind
+  case param_kind:
+  of PK_INT:
+    try: result.int_val = value.parseInt
+    except OverflowDefect:
+      raise_or_quit(OverflowDefect, ("parameter $1 requires an " &
+        "integer, but $2 is too large to fit into one") % [param,
+        escape(value)])
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires an " &
+        "integer, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_STRING:
+    result.str_val = value
+  of PK_FLOAT:
+    try: result.float_val = value.parseFloat
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires a " &
+        "float, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_BOOL:
+    try: result.bool_val = value.parseBool
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires a " &
+        "boolean, but $2 can't be parsed into one. Valid values are: " &
+        "y, yes, true, 1, on, n, no, false, 0, off") % [param, escape(value)])
+  of PK_BIGGEST_INT:
+    try:
+      let parsed_len = parseBiggestInt(value, result.big_int_val)
+      if value.len != parsed_len or parsed_len < 1:
+        raise_or_quit(ValueError, ("parameter $1 requires an " &
+          "integer, but $2 can't be parsed completely into one") % [
+          param, escape(value)])
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires an " &
+        "integer, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_BIGGEST_FLOAT:
+    try:
+      let parsed_len = parseBiggestFloat(value, result.big_float_val)
+      if value.len != parsed_len or parsed_len < 1:
+        raise_or_quit(ValueError, ("parameter $1 requires a " &
+          "float, but $2 can't be parsed completely into one") % [
+          param, escape(value)])
+    except ValueError:
+      raise_or_quit(ValueError, ("parameter $1 requires a " &
+        "float, but $2 can't be parsed into one") % [param, escape(value)])
+  of PK_EMPTY:
+    discard
+  of PK_HELP:
+    discard
+
+
+template build_specification_lookup():
+    OrderedTable[string, ptr Tparameter_specification] =
+  ## Returns the table used to keep pointers to all of the specifications.
+  var result {.gensym.}: OrderedTable[string, ptr Tparameter_specification]
+  result = initOrderedTable[string, ptr Tparameter_specification](expected.len)
+  for i in 0..expected.len-1:
+    for param_to_detect in expected[i].names:
+      if result.hasKey(param_to_detect):
+        raise_or_quit(KeyError,
+          "Parameter $1 repeated in input specification" % param_to_detect)
+      else:
+        result[param_to_detect] = addr(expected[i])
+  result
+
+
+proc echo_help*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING,
+    bad_prefixes = @["-", "--"], end_of_options = "--")
+
+
+proc parse*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING, args: seq[string] = @[],
+    bad_prefixes = @["-", "--"], end_of_options = "--",
+    quit_on_failure = true): Tcommandline_results =
+  ## Parses parameters and returns results.
+  ##
+  ## The expected array should contain a list of the parameters you want to
+  ## detect, which can capture additional values. Uncaptured parameters are
+  ## considered positional parameters for which you can specify a type with
+  ## type_of_positional_parameters.
+  ##
+  ## Before accepting a positional parameter, the list of bad_prefixes is
+  ## compared against it. If the positional parameter starts with any of them,
+  ## an error is displayed to the user due to ambiguity. The user can overcome
+  ## the ambiguity by typing the special string specified by end_of_options.
+  ## Note that values captured by parameters are not checked against bad
+  ## prefixes, otherwise it would be a problem to specify the dash as synonim
+  ## for standard input for many programs.
+  ##
+  ## The args sequence should be the list of parameters passed to your program
+  ## without the program binary (usually OSes provide the path to the binary as
+  ## the zeroth parameter). If args is empty, the list will be retrieved from the
+  ## OS.
+  ##
+  ## If there is any kind of error and quit_on_failure is true, the quit proc
+  ## will be called with a user error message. If quit_on_failure is false
+  ## errors will raise exceptions (usually ValueError or EOverflow) instead
+  ## for you to catch and handle.
+
+  assert type_of_positional_parameters != PK_EMPTY and
+    type_of_positional_parameters != PK_HELP
+  for bad_prefix in bad_prefixes:
+    assert bad_prefix.len > 0, "Can't pass in a bad prefix of zero length"
+  var
+    expected = expected
+    adding_options = true
+  result.init()
+
+  # Prepare the input parameter list, maybe get it from the OS if not available.
+  var args = args
+  if args.len == 0:
+    let total_params = paramCount()
+    #echo "Got no explicit args, retrieving from OS. Count: ", total_params
+    newSeq(args, total_params)
+    for i in 0..total_params - 1:
+      #echo ($i)
+      args[i] = paramStr(i + 1)
+
+  # Generate lookup table for each type of parameter based on strings.
+  var lookup = build_specification_lookup()
+
+  # Loop through the input arguments detecting their type and doing stuff.
+  var i = 0
+  while i < args.len:
+    let arg = args[i]
+    block adding_positional_parameter:
+      if arg.len > 0 and adding_options:
+        if arg == end_of_options:
+          # Looks like we found the end_of_options marker, disable options.
+          adding_options = false
+          break adding_positional_parameter
+        elif lookup.hasKey(arg):
+          var parsed: Tparsed_parameter
+          let param = lookup[arg]
+
+          # Insert check here for help, which aborts parsing.
+          if param.consumes == PK_HELP:
+            echo_help(expected, type_of_positional_parameters,
+              bad_prefixes, end_of_options)
+            raise_or_quit(KeyError, "")
+
+          if param.consumes != PK_EMPTY:
+            if i + 1 < args.len:
+              parsed = parse_parameter(quit_on_failure,
+                arg, args[i + 1], param.consumes)
+              run_custom_proc(parsed, param.custom_validator, arg)
+              i += 1
+            else:
+              raise_or_quit(ValueError, ("parameter $1 requires a " &
+                "value, but none was provided") % [arg])
+          result.options[param.names[0]] = parsed
+          break adding_positional_parameter
+        else:
+          for bad_prefix in bad_prefixes:
+            if arg.startsWith(bad_prefix):
+              raise_or_quit(ValueError, ("Found ambiguos parameter '$1' " &
+                "starting with '$2', put '$3' as the previous parameter " &
+                "if you want to force it as positional parameter.") % [arg,
+                bad_prefix, end_of_options])
+
+      # Unprocessed, add the parameter to the list of positional parameters.
+      result.positional_parameters.add(parse_parameter(quit_on_failure,
+        $(1 + i), arg, type_of_positional_parameters))
+
+    i += 1
+
+
+proc toString(runes: seq[Rune]): string =
+  result = ""
+  for rune in runes: result.add(rune.toUTF8)
+
+
+proc ascii_cmp(a, b: string): int =
+  ## Comparison ignoring non ascii characters, for better switch sorting.
+  let a = filterIt(toSeq(runes(a)), it.isAlpha())
+  # Can't use filterIt twice, github bug #351.
+  let b = filter(toSeq(runes(b)), proc(x: Rune): bool = x.isAlpha())
+  return system.cmp(toString(a), toString(b))
+
+
+proc build_help*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING,
+    bad_prefixes = @["-", "--"], end_of_options = "--"): seq[string] =
+  ## Builds basic help text and returns it as a sequence of strings.
+  ##
+  ## Note that this proc doesn't do as much sanity checks as the normal parse()
+  ## proc, though it's unlikely you will be using one without the other, so if
+  ## you had a parameter specification problem you would find out soon.
+  result = @["Usage parameters: "]
+
+  # Generate lookup table for each type of parameter based on strings.
+  let quit_on_failure = false
+  var
+    expected = expected
+    lookup = build_specification_lookup()
+    keys = toSeq(lookup.keys())
+
+  # First generate the joined version of input parameters in a list.
+  var
+    seen = initHashSet[string]()
+    prefixes: seq[string] = @[]
+    helps: seq[string] = @[]
+  for key in keys:
+    if seen.contains(key):
+      continue
+
+    # Add the joined string to the list.
+    let param = lookup[key][]
+    var param_names = param.names
+    sort(param_names, ascii_cmp)
+    var prefix = join(param_names, ", ")
+    # Don't forget about the type, if the parameter consumes values
+    if param.consumes != PK_EMPTY and param.consumes != PK_HELP:
+      prefix &= " " & $param.consumes
+    prefixes.add(prefix)
+    helps.add(param.help_text)
+    # Ignore future elements.
+    for name in param.names: seen.incl(name)
+
+  # Calculate the biggest width and try to use that
+  let width = prefixes.map(proc (x: string): int = 3 + len(x)).max
+
+  for line in zip(prefixes, helps):
+    result.add(line[0] & spaces(width - line[0].len) & line[1])
+
+
+proc echo_help*(expected: seq[Tparameter_specification] = @[],
+    type_of_positional_parameters = PK_STRING,
+    bad_prefixes = @["-", "--"], end_of_options = "--") =
+  ## Prints out help on the terminal.
+  ##
+  ## This is just a wrapper around build_help. Note that calling this proc
+  ## won't exit your program, you should call quit() yourself.
+  for line in build_help(expected,
+      type_of_positional_parameters, bad_prefixes, end_of_options):
+    echo line
+
+
+when true:
+  # Simply tests code embedded in docs.
+  let
+    parsed_param1 = new_parsed_parameter(PK_FLOAT, 3.41)
+    parsed_param2 = new_parsed_parameter(PK_BIGGEST_INT, 2358123 * 23123)
+    #parsed_param3 = new_parsed_parameter(PK_INT, "231")
diff --git a/tests/manyloc/argument_parser/ex_wget.nim b/tests/manyloc/argument_parser/ex_wget.nim
new file mode 100644
index 000000000..ebbf1933f
--- /dev/null
+++ b/tests/manyloc/argument_parser/ex_wget.nim
@@ -0,0 +1,87 @@
+import argument_parser, tables, strutils, parseutils
+
+## Example defining a subset of wget's functionality
+
+const
+  PARAM_VERSION = @["-V", "--version"]
+  PARAM_HELP = @["-h", "--help"]
+  PARAM_BACKGROUND = @["-b", "--background"]
+  PARAM_OUTPUT = @["-o", "--output"]
+  PARAM_NO_CLOBBER = @["-nc", "--no-clobber"]
+  PARAM_PROGRESS = @["--progress"]
+  PARAM_NO_PROXY = @["--no-proxy"]
+
+
+template P(tnames: varargs[string], thelp: string, ttype = PK_EMPTY,
+    tcallback: Tparameter_callback = nil) =
+  ## Helper to avoid repetition of parameter adding boilerplate.
+  params.add(new_parameter_specification(ttype, custom_validator = tcallback,
+    help_text = thelp, names = tnames))
+
+
+template got(param: varargs[string]) =
+  ## Just dump the detected options on output.
+  if result.options.hasKey(param[0]): echo("Found option '$1'." % [param[0]])
+
+
+proc parse_progress(parameter: string; value: var Tparsed_parameter): string =
+  ## Custom parser and validator of progress types for PARAM_PROGRESS.
+  ##
+  ## If the user specifies the PARAM_PROGRESS option this proc will be called
+  ## so we can validate the input. The proc returns a non empty string if
+  ## something went wrong with the description of the error, otherwise
+  ## execution goes ahead.
+  ##
+  ## This validator only accepts values without changing the final output.
+  if value.str_val == "bar" or value.str_val == "dot":
+    return
+
+  result = "The string $1 is not valid, use bar or dot." % [value.str_val]
+
+
+proc process_commandline(): Tcommandline_results =
+  ## Parses the commandline.
+  ##
+  ## Returns a Tcommandline_results with at least two positional parameter,
+  ## where the last parameter is implied to be the destination of the copying.
+  var params: seq[Tparameter_specification] = @[]
+
+  P(PARAM_VERSION, "Shows the version of the program")
+  P(PARAM_HELP, "Shows this help on the commandline", PK_HELP)
+  P(PARAM_BACKGROUND, "Continues execution in the background")
+  P(PARAM_OUTPUT, "Specifies a specific output file name", PK_STRING)
+  P(PARAM_NO_CLOBBER, "Skip downloads that would overwrite existing files")
+  P(PARAM_PROGRESS, "Select progress look (bar or dot)",
+    PK_STRING, parse_progress)
+  P(PARAM_NO_PROXY, "Don't use proxies even if available")
+
+  result = parse(params)
+
+  if result.positional_parameters.len < 1:
+    echo "Missing URL(s) to download"
+    echo_help(params)
+    quit()
+
+  got(PARAM_NO_CLOBBER)
+  got(PARAM_BACKGROUND)
+  got(PARAM_NO_PROXY)
+
+  if result.options.hasKey(PARAM_VERSION[0]):
+    echo "Version 3.1415"
+    quit()
+
+  if result.options.hasKey(PARAM_OUTPUT[0]):
+    if result.positional_parameters.len > 1:
+      echo "Error: can't use $1 option with multiple URLs" % [PARAM_OUTPUT[0]]
+      echo_help(params)
+      quit()
+    echo "Will download to $1" % [result.options[PARAM_OUTPUT[0]].str_val]
+
+  if result.options.hasKey(PARAM_PROGRESS[0]):
+    echo "Will use progress type $1" % [result.options[PARAM_PROGRESS[0]].str_val]
+
+
+when true:
+  let args = process_commandline()
+  for param in args.positional_parameters:
+    echo "Downloading $1" % param.str_val
diff --git a/tests/manyloc/argument_parser/ex_wget.nim.cfg b/tests/manyloc/argument_parser/ex_wget.nim.cfg
new file mode 100644
index 000000000..4ea571d31
--- /dev/null
+++ b/tests/manyloc/argument_parser/ex_wget.nim.cfg
@@ -0,0 +1 @@
+# This file exists only to mark 'ex_wget' as the project file
diff --git a/tests/manyloc/keineschweine/README.md b/tests/manyloc/keineschweine/README.md
new file mode 100644
index 000000000..20facbced
--- /dev/null
+++ b/tests/manyloc/keineschweine/README.md
@@ -0,0 +1,26 @@
+keineSchweine
+========================
+Just a dumb little game
+
+### Dependencies
+
+* nim 0.8.15, Until this version is released I'm working off nim HEAD: https://github.com/Araq/nim
+* SFML 2.0 (git), https://github.com/LaurentGomila/SFML
+* CSFML 2.0 (git), https://github.com/LaurentGomila/CSFML
+* Chipmunk 6.1.1 http://chipmunk-physics.net/downloads.php
+
+### How to build?
+
+* `git clone --recursive https://github.com/fowlmouth/keineSchweine.git somedir`
+* `cd somedir`
+*  `nim c -r nakefile test` or `nim c -r keineschweine && ./keineschweine`
+
+### Download the game data
+
+You need to download the game data before you can play:
+http://dl.dropbox.com/u/37533467/data-08-01-2012.7z
+
+Unpack it to the root directory. You can use the nakefile to do this easily: 
+
+* `nim c -r nakefile`
+* `./nakefile download`
diff --git a/tests/manyloc/keineschweine/TODO.md b/tests/manyloc/keineschweine/TODO.md
new file mode 100644
index 000000000..1145949aa
--- /dev/null
+++ b/tests/manyloc/keineschweine/TODO.md
@@ -0,0 +1,21 @@
+##Main State
+* Add GUI:
+  * Player list
+  * Chat box
+  * Escape menu
+
+##Lobby
+* Add GUI: 
+  * options menu
+  * key configuration
+
+## Animations
+* Need one-shot explosion animations
+  * Thrusters (maybe a particle system instead)
+
+## Networking
+* zone server should verify users through the dir server or handle its own users
+* directory server should handle asset patching
+
+## Genpacket
+* add support for branching types with case
diff --git a/tests/manyloc/keineschweine/client_settings.json b/tests/manyloc/keineschweine/client_settings.json
new file mode 100644
index 000000000..59facf1ad
--- /dev/null
+++ b/tests/manyloc/keineschweine/client_settings.json
@@ -0,0 +1,10 @@
+{
+ "resolution": [800,600,32],
+ "default-file": "alphazone.json",
+ "alias": "foo",
+ "directory-server":{
+  "host":"localhost",
+  "port":8024
+ },
+ "website":"https://github.com/fowlmouth/keineSchweine"
+}
diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
new file mode 100644
index 000000000..6eb1b3844
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
@@ -0,0 +1,1514 @@
+# Copyright (c) 2007 Scott Lembcke
+#
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to deal
+#  in the Software without restriction, including without limitation the rights
+#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+#  SOFTWARE.
+#
+
+const Lib = "libchipmunk.so.6.1.1"
+
+when defined(MoreNim):
+  {.hint: "MoreNim defined; some Chipmunk functions replaced in Nim".}
+from math import sqrt, sin, cos, arctan2
+when defined(CpUseFloat):
+  {.hint: "CpUseFloat defined; using float32 as float".}
+  type CpFloat* = cfloat
+else:
+  type CpFloat* = cdouble
+const
+  CP_BUFFER_BYTES* = (32 * 1024)
+  CP_MAX_CONTACTS_PER_ARBITER* = 4
+  CpInfinity*: CpFloat = 1.0/0
+{.pragma: pf, pure, final.}
+type
+  Bool32* = cint  #replace one day with cint-compatible bool
+  CpDataPointer* = pointer
+  TVector* {.final, pure.} = object
+    x*, y*: CpFloat
+  TTimestamp* = cuint
+  TBodyVelocityFunc* = proc(body: PBody, gravity: TVector,
+                            damping: CpFloat; dt: CpFloat){.cdecl.}
+  TBodyPositionFunc* = proc(body: PBody; dt: CpFloat){.cdecl.}
+  TComponentNode*{.pf.} = object
+    root*: PBody
+    next*: PBody
+    idleTime*: CpFloat
+
+  THashValue = cuint  # uintptr_t
+  TCollisionType* = cuint #uintptr_t
+  TGroup * = cuint #uintptr_t
+  TLayers* = cuint
+  PArray = ptr TArray
+  TArray{.pure,final.} = object
+  PHashSet = ptr THashSet
+  THashSet{.pf.} = object
+  PContact* = ptr TContact
+  TContact*{.pure,final.} = object
+  PArbiter* = ptr TArbiter
+  TArbiter*{.pf.} = object
+    e*: CpFloat
+    u*: CpFloat
+    surface_vr*: TVector
+    a*: PShape
+    b*: PShape
+    body_a*: PBody
+    body_b*: PBody
+    thread_a*: TArbiterThread
+    thread_b*: TArbiterThread
+    numContacts*: cint
+    contacts*: PContact
+    stamp*: TTimestamp
+    handler*: PCollisionHandler
+    swappedColl*: Bool32
+    state*: TArbiterState
+  PCollisionHandler* = ptr TCollisionHandler
+  TCollisionHandler*{.pf.} = object
+    a*: TCollisionType
+    b*: TCollisionType
+    begin*: TCollisionBeginFunc
+    preSolve*: TCollisionPreSolveFunc
+    postSolve*: TCollisionPostSolveFunc
+    separate*: TCollisionSeparateFunc
+    data*: pointer
+  TArbiterState*{.size: sizeof(cint).} = enum
+    ArbiterStateFirstColl,    # Arbiter is active and its not the first collision.
+    ArbiterStateNormal,       # Collision has been explicitly ignored.
+                              # Either by returning false from a begin collision handler or calling cpArbiterIgnore().
+    ArbiterStateIgnore,       # Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.
+    ArbiterStateCached
+  TArbiterThread*{.pf.} = object
+    next*: PArbiter        # Links to next and previous arbiters in the contact graph.
+    prev*: PArbiter
+
+  TContactPoint*{.pf.} = object
+    point*: TVector    #/ The position of the contact point.
+    normal*: TVector   #/ The normal of the contact point.
+    dist*: CpFloat     #/ The depth of the contact point.
+  #/ A struct that wraps up the important collision data for an arbiter.
+  PContactPointSet* = ptr TContactPointSet
+  TContactPointSet*{.pf.} = object
+    count*: cint              #/ The number of contact points in the set.
+    points*: array[0..CP_MAX_CONTACTS_PER_ARBITER - 1, TContactPoint] #/ The array of contact points.
+
+  #/ Collision begin event function callback type.
+  #/ Returning false from a begin callback causes the collision to be ignored until
+  #/ the separate callback is called when the objects stop colliding.
+  TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): bool{.
+      cdecl.}
+  #/ Collision pre-solve event function callback type.
+  #/ Returning false from a pre-step callback causes the collision to be ignored until the next step.
+  TCollisionPreSolveFunc* = proc (arb: PArbiter; space: PSpace;
+                                  data: pointer): bool {.cdecl.}
+  #/ Collision post-solve event function callback type.
+  TCollisionPostSolveFunc* = proc (arb: PArbiter; space: PSpace;
+                                   data: pointer){.cdecl.}
+  #/ Collision separate event function callback type.
+  TCollisionSeparateFunc* = proc (arb: PArbiter; space: PSpace;
+                                  data: pointer){.cdecl.}
+
+  #/ Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top)
+  PBB* = ptr TBB
+  TBB* {.pf.} = object
+    l*, b*, r*, t*: CpFloat
+
+  #/ Spatial index bounding box callback function type.
+  #/ The spatial index calls this function and passes you a pointer to an object you added
+  #/ when it needs to get the bounding box associated with that object.
+  TSpatialIndexBBFunc* = proc (obj: pointer): TBB{.cdecl.}
+  #/ Spatial index/object iterator callback function type.
+  TSpatialIndexIteratorFunc* = proc (obj: pointer; data: pointer){.cdecl.}
+  #/ Spatial query callback function type.
+  TSpatialIndexQueryFunc* = proc (obj1: pointer; obj2: pointer; data: pointer){.
+      cdecl.}
+  #/ Spatial segment query callback function type.
+  TSpatialIndexSegmentQueryFunc* = proc (obj1: pointer; obj2: pointer;
+      data: pointer): CpFloat {.cdecl.}
+  #/ private
+  PSpatialIndex = ptr TSpatialIndex
+  TSpatialIndex{.pf.} = object
+    klass: PSpatialIndexClass
+    bbfun: TSpatialIndexBBFunc
+    staticIndex: PSpatialIndex
+    dynamicIndex: PSpatialIndex
+
+  TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.}
+  TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.}
+  TSpatialIndexEachImpl* = proc (index: PSpatialIndex;
+                                 fun: TSpatialIndexIteratorFunc; data: pointer){.
+      cdecl.}
+  TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer;
+                                     hashid: THashValue): Bool32 {.cdecl.}
+  TSpatialIndexInsertImpl* = proc (index: PSpatialIndex; obj: pointer;
+                                   hashid: THashValue){.cdecl.}
+  TSpatialIndexRemoveImpl* = proc (index: PSpatialIndex; obj: pointer;
+                                   hashid: THashValue){.cdecl.}
+  TSpatialIndexReindexImpl* = proc (index: PSpatialIndex){.cdecl.}
+  TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex;
+      obj: pointer; hashid: THashValue){.cdecl.}
+  TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex;
+      fun: TSpatialIndexQueryFunc; data: pointer){.cdecl.}
+  TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector;
+                                       fun: TSpatialIndexQueryFunc;
+                                       data: pointer){.cdecl.}
+  TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer;
+      a: TVector; b: TVector; t_exit: CpFloat; fun: TSpatialIndexSegmentQueryFunc;
+      data: pointer){.cdecl.}
+  TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer;
+                                  bb: TBB; fun: TSpatialIndexQueryFunc;
+                                  data: pointer){.cdecl.}
+  PSpatialIndexClass* = ptr TSpatialIndexClass
+  TSpatialIndexClass*{.pf.} = object
+    destroy*: TSpatialIndexDestroyImpl
+    count*: TSpatialIndexCountImpl
+    each*: TSpatialIndexEachImpl
+    contains*: TSpatialIndexContainsImpl
+    insert*: TSpatialIndexInsertImpl
+    remove*: TSpatialIndexRemoveImpl
+    reindex*: TSpatialIndexReindexImpl
+    reindexObject*: TSpatialIndexReindexObjectImpl
+    reindexQuery*: TSpatialIndexReindexQueryImpl
+    pointQuery*: TSpatialIndexPointQueryImpl
+    segmentQuery*: TSpatialIndexSegmentQueryImpl
+    query*: TSpatialIndexQueryImpl
+
+  PSpaceHash* = ptr TSpaceHash
+  TSpaceHash* {.pf.} = object
+  PBBTree* = ptr TBBTree
+  TBBTree* {.pf.} = object
+  PSweep1D* = ptr TSweep1D
+  TSweep1D* {.pf.} = object
+
+  #/ Bounding box tree velocity callback function.
+  #/ This function should return an estimate for the object's velocity.
+  TBBTreeVelocityFunc* = proc (obj: pointer): TVector {.cdecl.}
+
+  PContactBufferHeader* = ptr TContentBufferHeader
+  TContentBufferHeader* {.pf.} = object
+  TSpaceArbiterApplyImpulseFunc* = proc (arb: PArbiter){.cdecl.}
+
+  PSpace* = ptr TSpace
+  TSpace* {.pf.} = object
+    iterations*: cint
+    gravity*: TVector
+    damping*: CpFloat
+    idleSpeedThreshold*: CpFloat
+    sleepTimeThreshold*: CpFloat
+    collisionSlop*: CpFloat
+    collisionBias*: CpFloat
+    collisionPersistence*: TTimestamp
+    enableContactGraph*: cint ##BOOL
+    data*: pointer
+    staticBody*: PBody
+    stamp: TTimestamp
+    currDT: CpFloat
+    bodies: PArray
+    rousedBodies: PArray
+    sleepingComponents: PArray
+    staticShapes: PSpatialIndex
+    activeShapes: PSpatialIndex
+    arbiters: PArray
+    contactBuffersHead: PContactBufferHeader
+    cachedArbiters: PHashSet
+    pooledArbiters: PArray
+    constraints: PArray
+    allocatedBuffers: PArray
+    locked: cint
+    collisionHandlers: PHashSet
+    defaultHandler: TCollisionHandler
+    postStepCallbacks: PHashSet
+    arbiterApplyImpulse: TSpaceArbiterApplyImpulseFunc
+    staticBody2: TBody  #_staticBody
+  PBody* = ptr TBody
+  TBody*{.pf.} = object
+    velocityFunc*: TBodyVelocityFunc
+    positionFunc*: TBodyPositionFunc
+    m*: CpFloat
+    mInv*: CpFloat
+    i*: CpFloat
+    iInv*: CpFloat
+    p*: TVector
+    v*: TVector
+    f*: TVector
+    a*: CpFloat
+    w*: CpFloat
+    t*: CpFloat
+    rot*: TVector
+    data*: pointer
+    vLimit*: CpFloat
+    wLimit*: CpFloat
+    vBias*: TVector
+    wBias*: CpFloat
+    space*: PSpace
+    shapeList*: PShape
+    arbiterList*: PArbiter
+    constraintList*: PConstraint
+    node*: TComponentNode
+  #/ Body/shape iterator callback function type.
+  TBodyShapeIteratorFunc* = proc (body: PBody; shape: PShape;
+                                   data: pointer) {.cdecl.}
+  #/ Body/constraint iterator callback function type.
+  TBodyConstraintIteratorFunc* = proc (body: PBody;
+                                        constraint: PConstraint;
+                                        data: pointer) {.cdecl.}
+  #/ Body/arbiter iterator callback function type.
+  TBodyArbiterIteratorFunc* = proc (body: PBody; arbiter: PArbiter;
+                                     data: pointer) {.cdecl.}
+
+  PNearestPointQueryInfo* = ptr TNearestPointQueryInfo
+  #/ Nearest point query info struct.
+  TNearestPointQueryInfo*{.pf.} = object
+    shape: PShape  #/ The nearest shape, NULL if no shape was within range.
+    p: TVector     #/ The closest point on the shape's surface. (in world space coordinates)
+    d: CpFloat      #/ The distance to the point. The distance is negative if the point is inside the shape.
+
+  PSegmentQueryInfo* = ptr TSegmentQueryInfo
+  #/ Segment query info struct.
+  TSegmentQueryInfo*{.pf.} = object
+    shape*: PShape         #/ The shape that was hit, NULL if no collision occurred.
+    t*: CpFloat            #/ The normalized distance along the query segment in the range [0, 1].
+    n*: TVector            #/ The normal of the surface hit.
+  TShapeType*{.size: sizeof(cint).} = enum
+    CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES
+  TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.}
+  TShapeDestroyImpl* = proc (shape: PShape){.cdecl.}
+  TShapePointQueryImpl* = proc (shape: PShape; p: TVector): Bool32 {.cdecl.}
+  TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector;
+                                  info: PSegmentQueryInfo){.cdecl.}
+  PShapeClass* = ptr TShapeClass
+  TShapeClass*{.pf.} = object
+    kind*: TShapeType
+    cacheData*: TShapeCacheDataImpl
+    destroy*: TShapeDestroyImpl
+    pointQuery*: TShapePointQueryImpl
+    segmentQuery*: TShapeSegmentQueryImpl
+  PShape* = ptr TShape
+  TShape*{.pf.} = object
+    klass: PShapeClass   #/ PRIVATE
+    body*: PBody           #/ The rigid body this collision shape is attached to.
+    bb*: TBB               #/ The current bounding box of the shape.
+    sensor*: Bool32        #/ Sensor flag.
+                           #/ Sensor shapes call collision callbacks but don't produce collisions.
+    e*: CpFloat            #/ Coefficient of restitution. (elasticity)
+    u*: CpFloat            #/ Coefficient of friction.
+    surface_v*: TVector    #/ Surface velocity used when solving for friction.
+    data*: pointer        #/ User definable data pointer. Generally this points to your the game object class so you can access it when given a cpShape reference in a callback.
+    collision_type*: TCollisionType #/ Collision type of this shape used when picking collision handlers.
+    group*: TGroup      #/ Group of this shape. Shapes in the same group don't collide.
+    layers*: TLayers   #/ Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero.
+    space: PSpace        #PRIVATE
+    next: PShape         #PRIVATE
+    prev: PShape         #PRIVATE
+    hashid: THashValue  #PRIVATE
+  PCircleShape* = ptr TCircleShape
+  TCircleShape*{.pf.} = object
+    shape: PShape
+    c, tc: TVector
+    r: CpFloat
+  PPolyShape* = ptr TPolyShape
+  TPolyShape*{.pf.} = object
+    shape: PShape
+    numVerts: cint
+    verts, tVerts: TVector
+    planes, tPlanes: PSplittingPlane
+  PSegmentShape* = ptr TSegmentShape
+  TSegmentShape*{.pf.} = object
+    shape: PShape
+    a, b, n: TVector
+    ta, tb, tn: TVector
+    r: CpFloat
+    aTangent, bTangent: TVector
+  PSplittingPlane* = ptr TSplittingPlane
+  TSplittingPlane*{.pf.} = object
+    n: TVector
+    d: CpFloat
+
+  #/ Post Step callback function type.
+  TPostStepFunc* = proc (space: PSpace; obj: pointer; data: pointer){.cdecl.}
+  #/ Point query callback function type.
+  TSpacePointQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Segment query callback function type.
+  TSpaceSegmentQueryFunc* = proc (shape: PShape; t: CpFloat; n: TVector;
+                                  data: pointer){.cdecl.}
+  #/ Rectangle Query callback function type.
+  TSpaceBBQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Shape query callback function type.
+  TSpaceShapeQueryFunc* = proc (shape: PShape; points: PContactPointSet;
+                                data: pointer){.cdecl.}
+  #/ Space/body iterator callback function type.
+  TSpaceBodyIteratorFunc* = proc (body: PBody; data: pointer){.cdecl.}
+  #/ Space/body iterator callback function type.
+  TSpaceShapeIteratorFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Space/constraint iterator callback function type.
+  TSpaceConstraintIteratorFunc* = proc (constraint: PConstraint;
+                                        data: pointer){.cdecl.}
+  #/ Opaque cpConstraint struct.
+  PConstraint* = ptr TConstraint
+  TConstraint*{.pf.} = object
+    klass: PConstraintClass #/PRIVATE
+    a*: PBody            #/ The first body connected to this constraint.
+    b*: PBody              #/ The second body connected to this constraint.
+    space: PSpace         #/PRIVATE
+    next_a: PConstraint  #/PRIVATE
+    next_b: PConstraint #/PRIVATE
+    maxForce*: CpFloat  #/ The maximum force that this constraint is allowed to use. Defaults to infinity.
+    errorBias*: CpFloat #/ The rate at which joint error is corrected. Defaults to pow(1.0 - 0.1, 60.0) meaning that it will correct 10% of the error every 1/60th of a second.
+    maxBias*: CpFloat    #/ The maximum rate at which joint error is corrected. Defaults to infinity.
+    preSolve*: TConstraintPreSolveFunc  #/ Function called before the solver runs. Animate your joint anchors, update your motor torque, etc.
+    postSolve*: TConstraintPostSolveFunc #/ Function called after the solver runs. Use the applied impulse to perform effects like breakable joints.
+    data*: CpDataPointer  # User definable data pointer. Generally this points to your the game object class so you can access it when given a cpConstraint reference in a callback.
+  TConstraintPreStepImpl = proc (constraint: PConstraint; dt: CpFloat){.cdecl.}
+  TConstraintApplyCachedImpulseImpl = proc (constraint: PConstraint; dt_coef: CpFloat){.cdecl.}
+  TConstraintApplyImpulseImpl = proc (constraint: PConstraint){.cdecl.}
+  TConstraintGetImpulseImpl = proc (constraint: PConstraint): CpFloat{.cdecl.}
+  PConstraintClass = ptr TConstraintClass
+  TConstraintClass{.pf.} = object
+    preStep*: TConstraintPreStepImpl
+    applyCachedImpulse*: TConstraintApplyCachedImpulseImpl
+    applyImpulse*: TConstraintApplyImpulseImpl
+    getImpulse*: TConstraintGetImpulseImpl
+  #/ Callback function type that gets called before solving a joint.
+  TConstraintPreSolveFunc* = proc (constraint: PConstraint; space: PSpace){.
+    cdecl.}
+  #/ Callback function type that gets called after solving a joint.
+  TConstraintPostSolveFunc* = proc (constraint: PConstraint; space: PSpace){.
+    cdecl.}
+
+##cp property emulators
+template defGetter(otype: typedesc, memberType: typedesc, memberName, procName: untyped) =
+  proc `get procName`*(obj: otype): memberType {.cdecl.} =
+    return obj.memberName
+template defSetter(otype: typedesc, memberType: typedesc, memberName, procName: untyped) =
+  proc `set procName`*(obj: otype, value: memberType) {.cdecl.} =
+    obj.memberName = value
+template defProp(otype: typedesc, memberType: typedesc, memberName, procName: untyped) =
+  defGetter(otype, memberType, memberName, procName)
+  defSetter(otype, memberType, memberName, procName)
+
+
+##cpspace.h
+proc allocSpace*(): PSpace {.
+  importc: "cpSpaceAlloc", dynlib: Lib.}
+proc Init*(space: PSpace): PSpace {.
+  importc: "cpSpaceInit", dynlib: Lib.}
+proc newSpace*(): PSpace {.
+  importc: "cpSpaceNew", dynlib: Lib.}
+proc destroy*(space: PSpace) {.
+  importc: "cpSpaceDestroy", dynlib: Lib.}
+proc free*(space: PSpace) {.
+  importc: "cpSpaceFree", dynlib: Lib.}
+
+defProp(PSpace, cint, iterations, Iterations)
+defProp(PSpace, TVector, gravity, Gravity)
+defProp(PSpace, CpFloat, damping, Damping)
+defProp(PSpace, CpFloat, idleSpeedThreshold, IdleSpeedThreshold)
+defProp(PSpace, CpFloat, sleepTimeThreshold, SleepTimeThreshold)
+defProp(PSpace, CpFloat, collisionSlop, CollisionSlop)
+defProp(PSpace, CpFloat, collisionBias, CollisionBias)
+defProp(PSpace, TTimestamp, collisionPersistence, CollisionPersistence)
+defProp(PSpace, Bool32, enableContactGraph, EnableContactGraph)
+defProp(PSpace, pointer, data, UserData)
+defGetter(PSpace, PBody, staticBody, StaticBody)
+defGetter(PSpace, CpFloat, currDt, CurrentTimeStep)
+
+
+#/ returns true from inside a callback and objects cannot be added/removed.
+proc isLocked*(space: PSpace): bool{.inline.} =
+  result = space.locked.bool
+
+#/ Set a default collision handler for this space.
+#/ The default collision handler is invoked for each colliding pair of shapes
+#/ that isn't explicitly handled by a specific collision handler.
+#/ You can pass NULL for any function you don't want to implement.
+proc setDefaultCollisionHandler*(space: PSpace; begin: TCollisionBeginFunc;
+                                  preSolve: TCollisionPreSolveFunc;
+                                  postSolve: TCollisionPostSolveFunc;
+                                  separate: TCollisionSeparateFunc;
+                                  data: pointer){.
+  cdecl, importc: "cpSpaceSetDefaultCollisionHandler", dynlib: Lib.}
+#/ Set a collision handler to be used whenever the two shapes with the given collision types collide.
+#/ You can pass NULL for any function you don't want to implement.
+proc addCollisionHandler*(space: PSpace; a, b: TCollisionType;
+                           begin: TCollisionBeginFunc;
+                           preSolve: TCollisionPreSolveFunc;
+                           postSolve: TCollisionPostSolveFunc;
+                           separate: TCollisionSeparateFunc; data: pointer){.
+  cdecl, importc: "cpSpaceAddCollisionHandler", dynlib: Lib.}
+#/ Unset a collision handler.
+proc removeCollisionHandler*(space: PSpace; a: TCollisionType;
+                                  b: TCollisionType){.
+  cdecl, importc: "cpSpaceRemoveCollisionHandler", dynlib: Lib.}
+#/ Add a collision shape to the simulation.
+#/ If the shape is attached to a static body, it will be added as a static shape.
+proc addShape*(space: PSpace; shape: PShape): PShape{.
+  cdecl, importc: "cpSpaceAddShape", dynlib: Lib.}
+#/ Explicitly add a shape as a static shape to the simulation.
+proc addStaticShape*(space: PSpace; shape: PShape): PShape{.
+  cdecl, importc: "cpSpaceAddStaticShape", dynlib: Lib.}
+#/ Add a rigid body to the simulation.
+proc addBody*(space: PSpace; body: PBody): PBody{.
+  cdecl, importc: "cpSpaceAddBody", dynlib: Lib.}
+#/ Add a constraint to the simulation.
+proc addConstraint*(space: PSpace; constraint: PConstraint): PConstraint{.
+    cdecl, importc: "cpSpaceAddConstraint", dynlib: Lib.}
+#/ Remove a collision shape from the simulation.
+proc removeShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceRemoveShape", dynlib: Lib.}
+#/ Remove a collision shape added using cpSpaceAddStaticShape() from the simulation.
+proc removeStaticShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceRemoveStaticShape", dynlib: Lib.}
+#/ Remove a rigid body from the simulation.
+proc removeBody*(space: PSpace; body: PBody){.
+  cdecl, importc: "cpSpaceRemoveBody", dynlib: Lib.}
+#/ Remove a constraint from the simulation.
+proc RemoveConstraint*(space: PSpace; constraint: PConstraint){.
+  cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.}
+#/ Test if a collision shape has been added to the space.
+proc containsShape*(space: PSpace; shape: PShape): bool{.
+  cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.}
+#/ Test if a rigid body has been added to the space.
+proc containsBody*(space: PSpace; body: PBody): bool{.
+  cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.}
+#/ Test if a constraint has been added to the space.
+
+proc containsConstraint*(space: PSpace; constraint: PConstraint): bool{.
+  cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.}
+#/ Schedule a post-step callback to be called when cpSpaceStep() finishes.
+#/ @c obj is used a key, you can only register one callback per unique value for @c obj
+proc addPostStepCallback*(space: PSpace; fun: TPostStepFunc;
+                               obj: pointer; data: pointer){.
+  cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.}
+
+#/ Query the space at a point and call @c func for each shape found.
+proc pointQuery*(space: PSpace; point: TVector; layers: TLayers;
+                      group: TGroup; fun: TSpacePointQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpacePointQuery", dynlib: Lib.}
+
+#/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
+proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers;
+                       group: TGroup): PShape{.
+  cdecl, importc: "cpSpacePointQueryFirst", dynlib: Lib.}
+
+#/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.
+proc segmentQuery*(space: PSpace; start: TVector; to: TVector;
+                    layers: TLayers; group: TGroup;
+                    fun: TSpaceSegmentQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.}
+#/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.
+proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector;
+                         layers: TLayers; group: TGroup;
+                         res: PSegmentQueryInfo): PShape{.
+  cdecl, importc: "cpSpaceSegmentQueryFirst", dynlib: Lib.}
+
+#/ Perform a fast rectangle query on the space calling @c func for each shape found.
+#/ Only the shape's bounding boxes are checked for overlap, not their full shape.
+proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup;
+                   fun: TSpaceBBQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.}
+
+#/ Query a space for any shapes overlapping the given shape and call @c func for each shape found.
+proc shapeQuery*(space: PSpace; shape: PShape; fun: TSpaceShapeQueryFunc; data: pointer): bool {.
+  cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.}
+#/ Call cpBodyActivate() for any shape that is overlaps the given shape.
+proc activateShapesTouchingShape*(space: PSpace; shape: PShape){.
+    cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.}
+
+#/ Call @c func for each body in the space.
+proc eachBody*(space: PSpace; fun: TSpaceBodyIteratorFunc; data: pointer){.
+  cdecl, importc: "cpSpaceEachBody", dynlib: Lib.}
+
+#/ Call @c func for each shape in the space.
+proc eachShape*(space: PSpace; fun: TSpaceShapeIteratorFunc;
+                     data: pointer){.
+  cdecl, importc: "cpSpaceEachShape", dynlib: Lib.}
+#/ Call @c func for each shape in the space.
+proc eachConstraint*(space: PSpace; fun: TSpaceConstraintIteratorFunc;
+                          data: pointer){.
+  cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.}
+#/ Update the collision detection info for the static shapes in the space.
+proc reindexStatic*(space: PSpace){.
+  cdecl, importc: "cpSpaceReindexStatic", dynlib: Lib.}
+#/ Update the collision detection data for a specific shape in the space.
+proc reindexShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceReindexShape", dynlib: Lib.}
+#/ Update the collision detection data for all shapes attached to a body.
+proc reindexShapesForBody*(space: PSpace; body: PBody){.
+  cdecl, importc: "cpSpaceReindexShapesForBody", dynlib: Lib.}
+#/ Switch the space to use a spatial has as it's spatial index.
+proc SpaceUseSpatialHash*(space: PSpace; dim: CpFloat; count: cint){.
+  cdecl, importc: "cpSpaceUseSpatialHash", dynlib: Lib.}
+#/ Step the space forward in time by @c dt.
+proc step*(space: PSpace; dt: CpFloat) {.
+  cdecl, importc: "cpSpaceStep", dynlib: Lib.}
+
+
+#/ Convenience constructor for cpVect structs.
+proc vector*(x, y: CpFloat): TVector {.inline.} =
+  result.x = x
+  result.y = y
+proc newVector*(x, y: CpFloat): TVector {.inline.} =
+  return vector(x, y)
+#let VectorZero* = newVector(0.0, 0.0)
+var VectorZero* = newVector(0.0, 0.0)
+
+#/ Vector dot product.
+proc dot*(v1, v2: TVector): CpFloat {.inline.} =
+  result = v1.x * v2.x + v1.y * v2.y
+
+#/ Returns the length of v.
+#proc len*(v: TVector): CpFloat {.
+#  cdecl, importc: "cpvlength", dynlib: Lib.}
+proc len*(v: TVector): CpFloat {.inline.} =
+  result = v.dot(v).sqrt
+#/ Spherical linearly interpolate between v1 and v2.
+proc slerp*(v1, v2: TVector; t: CpFloat): TVector {.
+  cdecl, importc: "cpvslerp", dynlib: Lib.}
+#/ Spherical linearly interpolate between v1 towards v2 by no more than angle a radians
+proc slerpconst*(v1, v2: TVector; a: CpFloat): TVector {.
+  cdecl, importc: "cpvslerpconst", dynlib: Lib.}
+#/ Returns the unit length vector for the given angle (in radians).
+#proc vectorForAngle*(a: CpFloat): TVector {.
+#  cdecl, importc: "cpvforangle", dynlib: Lib.}
+proc vectorForAngle*(a: CpFloat): TVector {.inline.} =
+  result = newVector(math.cos(a), math.sin(a))
+#/ Returns the angular direction v is pointing in (in radians).
+proc toAngle*(v: TVector): CpFloat {.inline.} =
+  result = math.arctan2(v.y, v.x)
+#/	Returns a string representation of v. Intended mostly for debugging purposes and not production use.
+#/	@attention The string points to a static local and is reset every time the function is called.
+#/	If you want to print more than one vector you will have to split up your printing onto separate lines.
+proc `$`*(v: TVector): cstring {.cdecl, importc: "cpvstr", dynlib: Lib.}
+
+
+#/ Check if two vectors are equal. (Be careful when comparing floating point numbers!)
+proc `==`*(v1, v2: TVector): bool {.inline.} =
+  result = v1.x == v2.x and v1.y == v2.y
+
+#/ Add two vectors
+proc `+`*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x + v2.x, v1.y + v2.y)
+proc `+=`*(v1: var TVector; v2: TVector) =
+  v1.x = v1.x + v2.x
+  v1.y = v1.y + v2.y
+
+#/ Subtract two vectors.
+proc `-`*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x - v2.x, v1.y - v2.y)
+proc `-=`*(v1: var TVector; v2: TVector) =
+  v1.x = v1.x - v2.x
+  v1.y = v1.y - v2.y
+
+#/ Negate a vector.
+proc `-`*(v: TVector): TVector {.inline.} =
+  result = newVector(- v.x, - v.y)
+
+#/ Scalar multiplication.
+proc `*`*(v: TVector, s: CpFloat): TVector {.inline.} =
+  result.x = v.x * s
+  result.y = v.y * s
+proc `*=`*(v: var TVector; s: CpFloat) =
+  v.x = v.x * s
+  v.y = v.y * s
+
+#/ 2D vector cross product analog.
+#/ The cross product of 2D vectors results in a 3D vector with only a z component.
+#/ This function returns the magnitude of the z value.
+proc cross*(v1, v2: TVector): CpFloat {.inline.} =
+  result = v1.x * v2.y - v1.y * v2.x
+
+#/ Returns a perpendicular vector. (90 degree rotation)
+proc perp*(v: TVector): TVector {.inline.} =
+  result = newVector(- v.y, v.x)
+
+#/ Returns a perpendicular vector. (-90 degree rotation)
+proc rperp*(v: TVector): TVector {.inline.} =
+  result = newVector(v.y, - v.x)
+
+#/ Returns the vector projection of v1 onto v2.
+proc project*(v1,v2: TVector): TVector {.inline.} =
+  result = v2 * (v1.dot(v2) / v2.dot(v2))
+
+#/ Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
+
+proc rotate*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x)
+#/ Inverse of cpvrotate().
+proc unrotate*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y)
+#/ Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
+proc lenSq*(v: TVector): CpFloat {.inline.} =
+  result = v.dot(v)
+#/ Linearly interpolate between v1 and v2.
+proc lerp*(v1, v2: TVector; t: CpFloat): TVector {.inline.} =
+  result = (v1 * (1.0 - t)) + (v2 * t)
+#/ Returns a normalized copy of v.
+proc normalize*(v: TVector): TVector {.inline.} =
+  result = v * (1.0 / v.len)
+#/ Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
+proc normalizeSafe*(v: TVector): TVector {.inline.} =
+  result = if v.x == 0.0 and v.y == 0.0: VectorZero else: v.normalize
+#/ Clamp v to length len.
+proc clamp*(v: TVector; len: CpFloat): TVector {.inline.} =
+  result = if v.dot(v) > len * len: v.normalize * len else: v
+#/ Linearly interpolate between v1 towards v2 by distance d.
+proc lerpconst*(v1, v2: TVector; d: CpFloat): TVector {.inline.} =
+  result = v1 + clamp(v2 - v1, d)             #vadd(v1 + vclamp(vsub(v2, v1), d))
+#/ Returns the distance between v1 and v2.
+proc dist*(v1, v2: TVector): CpFloat {.inline.} =
+  result = (v1 - v2).len #vlength(vsub(v1, v2))
+#/ Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
+proc distsq*(v1, v2: TVector): CpFloat {.inline.} =
+  result = (v1 - v2).lenSq  #vlengthsq(vsub(v1, v2))
+#/ Returns true if the distance between v1 and v2 is less than dist.
+proc near*(v1, v2: TVector; dist: CpFloat): bool{.inline.} =
+  result = v1.distSq(v2) < dist * dist
+
+
+
+##cpBody.h
+proc allocBody*(): PBody {.importc: "cpBodyAlloc", dynlib: Lib.}
+proc init*(body: PBody; m: CpFloat; i: CpFloat): PBody {.
+  importc: "cpBodyInit", dynlib: Lib.}
+proc newBody*(m: CpFloat; i: CpFloat): PBody {.
+  importc: "cpBodyNew", dynlib: Lib.}
+
+proc initStaticBody*(body: PBody): PBody{.
+  importc: "cpBodyInitStatic", dynlib: Lib.}
+#/ Allocate and initialize a static cpBody.
+proc newStatic*(): PBody{.importc: "cpBodyNewStatic", dynlib: Lib.}
+#/ Destroy a cpBody.
+proc destroy*(body: PBody){.importc: "cpBodyDestroy", dynlib: Lib.}
+#/ Destroy and free a cpBody.
+proc free*(body: PBody){.importc: "cpBodyFree", dynlib: Lib.}
+
+#/ Wake up a sleeping or idle body.
+proc activate*(body: PBody){.importc: "cpBodyActivate", dynlib: Lib.}
+#/ Wake up any sleeping or idle bodies touching a static body.
+proc activateStatic*(body: PBody; filter: PShape){.
+    importc: "cpBodyActivateStatic", dynlib: Lib.}
+#/ Force a body to fall asleep immediately.
+proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.}
+#/ Force a body to fall asleep immediately along with other bodies in a group.
+proc SleepWithGroup*(body: PBody; group: PBody){.
+    importc: "cpBodySleepWithGroup", dynlib: Lib.}
+#/ Returns true if the body is sleeping.
+proc isSleeping*(body: PBody): bool {.inline.} =
+  return body.node.root != nil
+#/ Returns true if the body is static.
+proc isStatic*(body: PBody): bool {.inline.} =
+  return body.node.idleTime == CpInfinity
+#/ Returns true if the body has not been added to a space.
+proc isRogue*(body: PBody): bool {.inline.} =
+  return body.space == nil
+
+# #define CP_DefineBodyStructGetter(type, member, name) \
+# static inline type cpBodyGet##name(const cpBody *body){return body->member;}
+# #define CP_DefineBodyStructSetter(type, member, name) \
+# static inline void cpBodySet##name(cpBody *body, const type value){ \
+# 	cpBodyActivate(body); \
+# 	cpBodyAssertSane(body); \
+# 	body->member = value; \
+# }
+# #define CP_DefineBodyStructProperty(type, member, name) \
+# CP_DefineBodyStructGetter(type, member, name) \
+# CP_DefineBodyStructSetter(type, member, name)
+
+defGetter(PBody, CpFloat, m, Mass)
+#/ Set the mass of a body.
+when defined(MoreNim):
+  defSetter(PBody, CpFloat, m, Mass)
+else:
+  proc setMass*(body: PBody; m: CpFloat){.
+    cdecl, importc: "cpBodySetMass", dynlib: Lib.}
+
+#/ Get the moment of a body.
+defGetter(PBody, CpFloat, i, Moment)
+#/ Set the moment of a body.
+when defined(MoreNim):
+  defSetter(PBody, CpFloat, i, Moment)
+else:
+  proc SetMoment*(body: PBody; i: CpFloat) {.
+    cdecl, importc: "cpBodySetMoment", dynlib: Lib.}
+
+#/ Get the position of a body.
+defGetter(PBody, TVector, p, Pos)
+#/ Set the position of a body.
+when defined(MoreNim):
+  defSetter(PBody, TVector, p, Pos)
+else:
+  proc setPos*(body: PBody; pos: TVector) {.
+    cdecl, importc: "cpBodySetPos", dynlib: Lib.}
+
+defProp(PBody, TVector, v, Vel)
+defProp(PBody, TVector, f, Force)
+
+#/ Get the angle of a body.
+defGetter(PBody, CpFloat, a, Angle)
+#/ Set the angle of a body.
+proc setAngle*(body: PBody; a: CpFloat){.
+  cdecl, importc: "cpBodySetAngle", dynlib: Lib.}
+
+defProp(PBody, CpFloat, w, AngVel)
+defProp(PBody, CpFloat, t, Torque)
+defGetter(PBody, TVector, rot, Rot)
+defProp(PBody, CpFloat, v_limit, VelLimit)
+defProp(PBody, CpFloat, w_limit, AngVelLimit)
+defProp(PBody, pointer, data, UserData)
+
+#/ Default Integration functions.
+proc UpdateVelocity*(body: PBody; gravity: TVector; damping: CpFloat; dt: CpFloat){.
+  cdecl, importc: "cpBodyUpdateVelocity", dynlib: Lib.}
+proc UpdatePosition*(body: PBody; dt: CpFloat){.
+  cdecl, importc: "cpBodyUpdatePosition", dynlib: Lib.}
+#/ Convert body relative/local coordinates to absolute/world coordinates.
+proc Local2World*(body: PBody; v: TVector): TVector{.inline.} =
+  result = body.p + v.rotate(body.rot) ##return cpvadd(body.p, cpvrotate(v, body.rot))
+#/ Convert body absolute/world coordinates to  relative/local coordinates.
+proc world2Local*(body: PBody; v: TVector): TVector{.inline.} =
+  result = (v - body.p).unrotate(body.rot)
+#/ Set the forces and torque or a body to zero.
+proc resetForces*(body: PBody){.
+  cdecl, importc: "cpBodyResetForces", dynlib: Lib.}
+#/ Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
+proc applyForce*(body: PBody; f, r: TVector){.
+  cdecl, importc: "cpBodyApplyForce", dynlib: Lib.}
+#/ Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
+proc applyImpulse*(body: PBody; j, r: TVector){.
+  cdecl, importc: "cpBodyApplyImpulse", dynlib: Lib.}
+#/ Get the velocity on a body (in world units) at a point on the body in world coordinates.
+
+proc getVelAtWorldPoint*(body: PBody; point: TVector): TVector{.
+  cdecl, importc: "cpBodyGetVelAtWorldPoint", dynlib: Lib.}
+#/ Get the velocity on a body (in world units) at a point on the body in local coordinates.
+proc getVelAtLocalPoint*(body: PBody; point: TVector): TVector{.
+  cdecl, importc: "cpBodyGetVelAtLocalPoint", dynlib: Lib.}
+#/ Get the kinetic energy of a body.
+# static inline CpFloat cpBodyKineticEnergy(const cpBody *body)
+# {
+# 	// Need to do some fudging to avoid NaNs
+# 	cpFloat vsq = cpvdot(body->v, body->v);
+# 	cpFloat wsq = body->w*body->w;
+# 	return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f);
+# }
+proc kineticEnergy*(body: PBOdy): CpFloat =
+  result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i)
+
+#/ Call @c func once for each shape attached to @c body and added to the space.
+proc eachShape*(body: PBody; fun: TBodyShapeIteratorFunc;
+                      data: pointer){.
+  cdecl, importc: "cpBodyEachShape", dynlib: Lib.}
+#/ Call @c func once for each constraint attached to @c body and added to the space.
+proc eachConstraint*(body: PBody; fun: TBodyConstraintIteratorFunc;
+                           data: pointer) {.
+  cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.}
+#/ Call @c func once for each arbiter that is currently active on the body.
+proc eachArbiter*(body: PBody; fun: TBodyArbiterIteratorFunc;
+                        data: pointer){.
+  cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.}
+#/ Allocate a spatial hash.
+proc SpaceHashAlloc*(): PSpaceHash{.
+  cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.}
+#/ Initialize a spatial hash.
+proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint;
+                    bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+  cdecl, importc: "cpSpaceHashInit", dynlib: Lib.}
+#/ Allocate and initialize a spatial hash.
+proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfun: TSpatialIndexBBFunc;
+                   staticIndex: PSpatialIndex): PSpatialIndex{.
+  cdecl, importc: "cpSpaceHashNew", dynlib: Lib.}
+#/ Change the cell dimensions and table size of the spatial hash to tune it.
+#/ The cell dimensions should roughly match the average size of your objects
+#/ and the table size should be ~10 larger than the number of objects inserted.
+#/ Some trial and error is required to find the optimum numbers for efficiency.
+proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){.
+  cdecl, importc: "cpSpaceHashResize", dynlib: Lib.}
+#MARK: AABB Tree
+
+
+#/ Allocate a bounding box tree.
+proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.}
+#/ Initialize a bounding box tree.
+proc BBTreeInit*(tree: PBBTree; bbfun: TSpatialIndexBBFunc;
+                 staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl,
+    importc: "cpBBTreeInit", dynlib: Lib.}
+#/ Allocate and initialize a bounding box tree.
+proc BBTreeNew*(bbfun: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+    cdecl, importc: "cpBBTreeNew", dynlib: Lib.}
+#/ Perform a static top down optimization of the tree.
+proc BBTreeOptimize*(index: PSpatialIndex){.
+  cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.}
+#/ Set the velocity function for the bounding box tree to enable temporal coherence.
+
+proc BBTreeSetVelocityFunc*(index: PSpatialIndex; fun: TBBTreeVelocityFunc){.
+    cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.}
+#MARK: Single Axis Sweep
+
+
+#/ Allocate a 1D sort and sweep broadphase.
+
+proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc",
+                                    dynlib: Lib.}
+#/ Initialize a 1D sort and sweep broadphase.
+
+proc Sweep1DInit*(sweep: ptr TSweep1D; bbfun: TSpatialIndexBBFunc;
+                  staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl,
+    importc: "cpSweep1DInit", dynlib: Lib.}
+#/ Allocate and initialize a 1D sort and sweep broadphase.
+
+proc Sweep1DNew*(bbfun: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.
+    cdecl, importc: "cpSweep1DNew", dynlib: Lib.}
+
+
+
+defProp(PArbiter, CpFloat, e, Elasticity)
+defProp(PArbiter, CpFloat, u, Friction)
+defProp(PArbiter, TVector, surface_vr, SurfaceVelocity)
+
+#/ Calculate the total impulse that was applied by this
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalImpulse*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulse", dynlib: Lib.}
+
+#/ Calculate the total impulse including the friction that was applied by this arbiter.
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalImpulseWithFriction*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulseWithFriction", dynlib: Lib.}
+
+#/ Calculate the amount of energy lost in a collision including static, but not dynamic friction.
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalKE*(obj: PArbiter): CpFloat {.cdecl, importc: "cpArbiterTotalKE", dynlib: Lib.}
+
+
+#/ Causes a collision pair to be ignored as if you returned false from a begin callback.
+#/ If called from a pre-step callback, you will still need to return false
+#/ if you want it to be ignored in the current step.
+proc ignore*(arb: PArbiter) {.cdecl, importc: "cpArbiterIgnore", dynlib: Lib.}
+
+#/ Return the colliding shapes involved for this arbiter.
+#/ The order of their cpSpace.collision_type values will match
+#/ the order set when the collision handler was registered.
+proc getShapes*(arb: PArbiter, a, b: var PShape) {.inline.} =
+  if arb.swappedColl.bool:
+    a = arb.b
+    b = arb.a
+  else:
+    a = arb.a
+    b = arb.b
+
+#/ A macro shortcut for defining and retrieving the shapes from an arbiter.
+#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
+template getShapes*(arb: PArbiter, name1, name2: untyped) =
+  var name1, name2: PShape
+  getShapes(arb, name1, name2)
+
+
+#/ Return the colliding bodies involved for this arbiter.
+#/ The order of the cpSpace.collision_type the bodies are associated with values will match
+#/ the order set when the collision handler was registered.
+#proc getBodies*(arb: PArbiter, a, b: var PBody) {.inline.} =
+#  getShapes(arb, shape1, shape2)
+#  a = shape1.body
+#  b = shape2.body
+
+#/ A macro shortcut for defining and retrieving the bodies from an arbiter.
+#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
+template getBodies*(arb: PArbiter, name1, name2: untyped) =
+  var name1, name2: PBOdy
+  getBodies(arb, name1, name2)
+
+proc isFirstContact*(arb: PArbiter): bool {.inline.} =
+  result = arb.state == ArbiterStateFirstColl
+
+proc getCount*(arb: PArbiter): cint {.inline.} =
+  result = arb.numContacts
+
+#/ Return a contact set from an arbiter.
+proc getContactPointSet*(arb: PArbiter): TContactPointSet {.
+  cdecl, importc: "cpArbiterGetContactPointSet", dynlib: Lib.}
+#/ Get the normal of the @c ith contact point.
+proc getNormal*(arb: PArbiter; i: cint): TVector {.
+  cdecl, importc: "cpArbiterGetNormal", dynlib: Lib.}
+#/ Get the position of the @c ith contact point.
+proc getPoint*(arb: PArbiter; i: cint): TVector {.
+  cdecl, importc: "cpArbiterGetPoint", dynlib: Lib.}
+#/ Get the depth of the @c ith contact point.
+proc getDepth*(arb: PArbiter; i: cint): CpFloat {.
+  cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.}
+
+##Shapes
+template defShapeSetter(memberType: typedesc, memberName: untyped, procName: untyped, activates: bool) =
+  proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} =
+    if activates and obj.body != nil: obj.body.activate()
+    obj.memberName = value
+template defShapeProp(memberType: typedesc, memberName: untyped, procName: untyped, activates: bool) =
+  defGetter(PShape, memberType, memberName, procName)
+  defShapeSetter(memberType, memberName, procName, activates)
+
+#/ Destroy a shape.
+proc destroy*(shape: PShape) {.
+  cdecl, importc: "cpShapeDestroy", dynlib: Lib.}
+#/ Destroy and Free a shape.
+proc free*(shape: PShape){.
+  cdecl, importc: "cpShapeFree", dynlib: Lib.}
+#/ Update, cache and return the bounding box of a shape based on the body it's attached to.
+proc cacheBB*(shape: PShape): TBB{.
+  cdecl, importc: "cpShapeCacheBB", dynlib: Lib.}
+#/ Update, cache and return the bounding box of a shape with an explicit transformation.
+proc update*(shape: PShape; pos: TVector; rot: TVector): TBB {.
+  cdecl, importc: "cpShapeUpdate", dynlib: Lib.}
+#/ Test if a point lies within a shape.
+proc pointQuery*(shape: PShape; p: TVector): Bool32 {.
+  cdecl, importc: "cpShapePointQuery", dynlib: Lib.}
+
+#/ Perform a nearest point query. It finds the closest point on the surface of shape to a specific point.
+#/ The value returned is the distance between the points. A negative distance means the point is inside the shape.
+proc nearestPointQuery*(shape: PShape; p: TVector; res: PNearestPointQueryInfo): CpFloat {.
+  cdecl, importc: "cpShapeNearestPointQuery", dynlib: Lib.}
+#/ Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure.
+proc segmentQuery*(shape: PShape, a, b: TVector, info: PSegmentQueryInfo): bool {.
+  cdecl, importc: "cpShapeSegmentQuery", dynlib: Lib.}
+
+#/ Get the hit point for a segment query.
+## Possibly change; info to PSegmentQueryInfo
+proc queryHitPoint*(start, to: TVector, info: TSegmentQueryInfo): TVector {.inline.} =
+  result = start.lerp(to, info.t)
+
+#/ Get the hit distance for a segment query.
+proc queryHitDist*(start, to: TVector, info: TSegmentQueryInfo): CpFloat {.inline.} =
+  result = start.dist(to) * info.t
+
+defGetter(PShape, PSpace, space, Space)
+
+defGetter(PShape, PBody, body, Body)
+proc setBody*(shape: PShape, value: PBody) {.
+  cdecl, importc: "cpShapeSetBody", dynlib: Lib.}
+
+
+defGetter(PShape, TBB, bb, BB)
+defShapeProp(Bool32, sensor, Sensor, true)
+defShapeProp(CpFloat, e, Elasticity, false)
+defShapeProp(CpFloat, u, Friction, true)
+defShapeProp(TVector, surface_v, SurfaceVelocity, true)
+defShapeProp(pointer, data, UserData, false)
+defShapeProp(TCollisionType, collision_type, CollisionType, true)
+defShapeProp(TGroup, group, Group, true)
+defShapeProp(TLayers, layers, Layers, true)
+
+#/ When initializing a shape, it's hash value comes from a counter.
+#/ Because the hash value may affect iteration order, you can reset the shape ID counter
+#/ when recreating a space. This will make the simulation be deterministic.
+proc resetShapeIdCounter*(): void {.cdecl, importc: "cpResetShapeIdCounter", dynlib: Lib.}
+#/ Allocate a circle shape.
+proc CircleShapeAlloc*(): PCircleShape {.cdecl, importc: "cpCircleShapeAlloc", dynlib: Lib.}
+#/ Initialize a circle shape.
+proc init*(circle: PCircleShape, body: PBody, radius: CpFloat, offset: TVector): PCircleShape {.
+  cdecl, importc: "cpCircleShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a circle shape.
+proc newCircleShape*(body: PBody, radius: CpFloat, offset: TVector): PShape {.
+  cdecl, importc: "cpCircleShapeNew", dynlib: Lib.}
+
+proc getCircleOffset*(shape: PShape): TVector {.
+  cdecl, importc: "cpCircleShapeGetOffset", dynlib: Lib.}
+proc getCircleRadius*(shape: PShape): CpFloat {.
+  cdecl, importc: "cpCircleShapeGetRadius", dynlib: Lib.}
+
+
+#/ Allocate a polygon shape.
+proc allocPolyShape*(): PPolyShape {.
+  cdecl, importc: "cpPolyShapeAlloc", dynlib: Lib.}
+#/ Initialize a polygon shape.
+#/ A convex hull will be created from the vertices.
+proc init*(poly: PPolyShape; body: PBody, numVerts: cint;
+            verts: ptr TVector; offset: TVector): PPolyShape {.
+  cdecl, importc: "cpPolyShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a polygon shape.
+#/ A convex hull will be created from the vertices.
+proc newPolyShape*(body: PBody; numVerts: cint; verts: ptr TVector;
+                    offset: TVector): PShape {.
+  cdecl, importc: "cpPolyShapeNew", dynlib: Lib.}
+#/ Initialize a box shaped polygon shape.
+proc init*(poly: PPolyShape; body: PBody; width, height: CpFloat): PPolyShape {.
+  cdecl, importc: "cpBoxShapeInit", dynlib: Lib.}
+#/ Initialize an offset box shaped polygon shape.
+proc init*(poly: PPolyShape; body: PBody; box: TBB): PPolyShape {.
+  cdecl, importc: "cpBoxShapeInit2", dynlib: Lib.}
+#/ Allocate and initialize a box shaped polygon shape.
+proc newBoxShape*(body: PBody; width, height: CpFloat): PShape {.
+  cdecl, importc: "cpBoxShapeNew", dynlib: Lib.}
+#/ Allocate and initialize an offset box shaped polygon shape.
+proc newBoxShape*(body: PBody; box: TBB): PShape {.
+  cdecl, importc: "cpBoxShapeNew2", dynlib: Lib.}
+
+#/ Check that a set of vertices is convex and has a clockwise winding.
+#/ NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
+proc validatePoly*(verts: ptr TVector; numVerts: cint): bool {.
+  cdecl, importc: "cpPolyValidate", dynlib: Lib.}
+#/ Get the number of verts in a polygon shape.
+proc getNumVerts*(shape: PShape): cint {.
+  cdecl, importc: "cpPolyShapeGetNumVerts", dynlib: Lib.}
+#/ Get the @c ith vertex of a polygon shape.
+proc getVert*(shape: PShape; index: cint): TVector {.
+  cdecl, importc: "cpPolyShapeGetVert", dynlib: Lib.}
+
+#/ Allocate a segment shape.
+proc allocSegmentShape*(): PSegmentShape {.
+  cdecl, importc: "cpSegmentShapeAlloc", dynlib: Lib.}
+#/ Initialize a segment shape.
+proc init*(seg: PSegmentShape, body: PBody, a, b: TVector, radius: CpFloat): PSegmentShape {.
+  cdecl, importc: "cpSegmentShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a segment shape.
+proc newSegmentShape*(body: PBody, a, b: TVector, radius: CpFloat): PShape {.
+  cdecl, importc: "cpSegmentShapeNew", dynlib: Lib.}
+
+proc setSegmentNeighbors*(shape: PShape, prev, next: TVector) {.
+  cdecl, importc: "cpSegmentShapeSetNeighbors", dynlib: Lib.}
+proc getSegmentA*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetA", dynlib: Lib.}
+proc getSegmentB*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetB", dynlib: Lib.}
+proc getSegmentNormal*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetNormal", dynlib: Lib.}
+proc getSegmentRadius*(shape: PShape): CpFloat {.
+  cdecl, importc: "cpSegmentShapeGetRadius", dynlib: Lib.}
+
+
+#/ Version string.
+#var VersionString*{.importc: "cpVersionString", dynlib: Lib.}: cstring
+#/ Calculate the moment of inertia for a circle.
+#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+when defined(MoreNim):
+  proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.cdecl.} =
+    result = m * (0.5 * (r1 * r1 + r2 * r2) + lenSq(offset))
+else:
+  proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.
+    cdecl, importc: "cpMomentForCircle", dynlib: Lib.}
+
+#/ Calculate area of a hollow circle.
+#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+proc AreaForCircle*(r1: CpFloat; r2: CpFloat): CpFloat {.
+  cdecl, importc: "cpAreaForCircle", dynlib: Lib.}
+#/ Calculate the moment of inertia for a line segment.
+#/ Beveling radius is not supported.
+proc MomentForSegment*(m: CpFloat; a, b: TVector): CpFloat {.
+  cdecl, importc: "cpMomentForSegment", dynlib: Lib.}
+#/ Calculate the area of a fattened (capsule shaped) line segment.
+proc AreaForSegment*(a, b: TVector; r: CpFloat): CpFloat {.
+  cdecl, importc: "cpAreaForSegment", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex.
+proc MomentForPoly*(m: CpFloat; numVerts: cint; verts: ptr TVector; offset: TVector): CpFloat {.
+  cdecl, importc: "cpMomentForPoly", dynlib: Lib.}
+#/ Calculate the signed area of a polygon. A Clockwise winding gives positive area.
+#/ This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes.
+proc AreaForPoly*(numVerts: cint; verts: ptr TVector): CpFloat {.
+  cdecl, importc: "cpAreaForPoly", dynlib: Lib.}
+#/ Calculate the natural centroid of a polygon.
+proc CentroidForPoly*(numVerts: cint; verts: ptr TVector): TVector {.
+  cdecl, importc: "cpCentroidForPoly", dynlib: Lib.}
+#/ Center the polygon on the origin. (Subtracts the centroid of the polygon from each vertex)
+proc RecenterPoly*(numVerts: cint; verts: ptr TVector) {.
+  cdecl, importc: "cpRecenterPoly", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid box.
+proc MomentForBox*(m, width, height: CpFloat): CpFloat {.
+  cdecl, importc: "cpMomentForBox", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid box.
+proc MomentForBox2*(m: CpFloat; box: TBB): CpFloat {.
+  cdecl, importc: "cpMomentForBox2", dynlib: Lib.}
+
+
+
+##constraints
+type
+  #TODO: all these are private
+  #TODO: defConstraintProp()
+  PPinJoint = ptr TPinJoint
+  TPinJoint{.pf.} = object
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    dist: CpFloat
+    r1: TVector
+    r2: TVector
+    n: TVector
+    nMass: CpFloat
+    jnAcc: CpFloat
+    jnMax: CpFloat
+    bias: CpFloat
+  PSlideJoint = ptr TSlideJoint
+  TSlideJoint{.pf.} = object
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    min: CpFloat
+    max: CpFloat
+    r1: TVector
+    r2: TVector
+    n: TVector
+    nMass: CpFloat
+    jnAcc: CpFloat
+    jnMax: CpFloat
+    bias: CpFloat
+  PPivotJoint = ptr TPivotJoint
+  TPivotJoint{.pf.} = object
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    r1: TVector
+    r2: TVector
+    k1: TVector
+    k2: TVector
+    jAcc: TVector
+    jMaxLen: CpFloat
+    bias: TVector
+  PGrooveJoint = ptr TGrooveJoint
+  TGrooveJoint{.pf.} = object
+    constraint: PConstraint
+    grv_n: TVector
+    grv_a: TVector
+    grv_b: TVector
+    anchr2: TVector
+    grv_tn: TVector
+    clamp: CpFloat
+    r1: TVector
+    r2: TVector
+    k1: TVector
+    k2: TVector
+    jAcc: TVector
+    jMaxLen: CpFloat
+    bias: TVector
+  PDampedSpring = ptr TDampedSpring
+  TDampedSpring{.pf.} = object
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    restLength: CpFloat
+    stiffness: CpFloat
+    damping: CpFloat
+    springForceFunc: TDampedSpringForceFunc
+    target_vrn: CpFloat
+    v_coef: CpFloat
+    r1: TVector
+    r2: TVector
+    nMass: CpFloat
+    n: TVector
+  PDampedRotarySpring = ptr TDampedRotarySpring
+  TDampedRotarySpring{.pf.} = object
+    constraint: PConstraint
+    restAngle: CpFloat
+    stiffness: CpFloat
+    damping: CpFloat
+    springTorqueFunc: TDampedRotarySpringTorqueFunc
+    target_wrn: CpFloat
+    w_coef: CpFloat
+    iSum: CpFloat
+  PRotaryLimitJoint = ptr TRotaryLimitJoint
+  TRotaryLimitJoint{.pf.} = object
+    constraint: PConstraint
+    min: CpFloat
+    max: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PRatchetJoint = ptr TRatchetJoint
+  TRatchetJoint{.pf.} = object
+    constraint: PConstraint
+    angle: CpFloat
+    phase: CpFloat
+    ratchet: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PGearJoint = ptr TGearJoint
+  TGearJoint{.pf.} = object
+    constraint: PConstraint
+    phase: CpFloat
+    ratio: CpFloat
+    ratio_inv: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PSimpleMotor = ptr TSimpleMotor
+  TSimpleMotor{.pf.} = object
+    constraint: PConstraint
+    rate: CpFloat
+    iSum: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  TDampedSpringForceFunc* = proc (spring: PConstraint; dist: CpFloat): CpFloat{.
+    cdecl.}
+  TDampedRotarySpringTorqueFunc* = proc (spring: PConstraint;
+      relativeAngle: CpFloat): CpFloat {.cdecl.}
+#/ Destroy a constraint.
+proc destroy*(constraint: PConstraint){.
+  cdecl, importc: "cpConstraintDestroy", dynlib: Lib.}
+#/ Destroy and free a constraint.111
+proc free*(constraint: PConstraint){.
+  cdecl, importc: "cpConstraintFree", dynlib: Lib.}
+
+#/ @private
+proc activateBodies(constraint: PConstraint) {.inline.} =
+  if not constraint.a.isNil: constraint.a.activate()
+  if not constraint.b.isNil: constraint.b.activate()
+
+# /// @private
+# #define CP_DefineConstraintStructGetter(type, member, name) \
+# static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;}
+# /// @private
+# #define CP_DefineConstraintStructSetter(type, member, name) \
+# static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \
+# 	cpConstraintActivateBodies(constraint); \
+# 	constraint->member = value; \
+# }
+template defConstraintSetter(memberType: typedesc, member, name: untyped) =
+  proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
+    activateBodies(constraint)
+    constraint.member = value
+template defConstraintProp(memberType: typedesc, member, name: untyped) =
+  defGetter(PConstraint, memberType, member, name)
+  defConstraintSetter(memberType, member, name)
+# CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
+defGetter(PConstraint, PSpace, space, Space)
+defGetter(PConstraint, PBody, a, A)
+defGetter(PConstraint, PBody, a, B)
+defGetter(PConstraint, CpFloat, maxForce, MaxForce)
+defGetter(PConstraint, CpFloat, errorBias, ErrorBias)
+defGetter(PConstraint, CpFloat, maxBias, MaxBias)
+defGetter(PConstraint, TConstraintPreSolveFunc, preSolve, PreSolveFunc)
+defGetter(PConstraint, TConstraintPostSolveFunc, postSolve, PostSolveFunc)
+defGetter(PConstraint, CpDataPointer, data, UserData)
+# Get the last impulse applied by this constraint.
+proc getImpulse*(constraint: PConstraint): CpFloat {.inline.} =
+  return constraint.klass.getImpulse(constraint)
+
+# #define cpConstraintCheckCast(constraint, struct) \
+# 	cpAssertHard(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct)
+# #define CP_DefineConstraintGetter(struct, type, member, name) \
+# static inline type struct##Get##name(const cpConstraint *constraint){ \
+# 	cpConstraintCheckCast(constraint, struct); \
+# 	return ((struct *)constraint)->member; \
+# }
+# #define CP_DefineConstraintSetter(struct, type, member, name) \
+# static inline void struct##Set##name(cpConstraint *constraint, type value){ \
+# 	cpConstraintCheckCast(constraint, struct); \
+# 	cpConstraintActivateBodies(constraint); \
+# 	((struct *)constraint)->member = value; \
+# }
+template constraintCheckCast(constraint: PConstraint, ctype: untyped) =
+  assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class")
+template defCGetter(ctype: untyped, memberType: typedesc, member, name: untyped) =
+  proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} =
+    constraintCheckCast(constraint, ctype)
+    result = cast[`P ctype`](constraint).member
+template defCSetter(ctype: untyped, memberType: typedesc, member, name: untyped) =
+  proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
+    constraintCheckCast(constraint, ctype)
+    activateBodies(constraint)
+    cast[`P ctype`](constraint).member = value
+template defCProp(ctype: untyped, memberType: typedesc, member, name: untyped) =
+  defCGetter(ctype, memberType, member, name)
+  defCSetter(ctype, memberType, member, name)
+
+proc PinJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpPinJointGetClass", dynlib: Lib.}
+#/ @private
+
+#/ Allocate a pin joint.
+proc AllocPinJoint*(): PPinJoint{.
+  cdecl, importc: "cpPinJointAlloc", dynlib: Lib.}
+#/ Initialize a pin joint.
+proc PinJointInit*(joint: PPinJoint; a: PBody; b: PBody; anchr1: TVector;
+                   anchr2: TVector): PPinJoint{.
+  cdecl, importc: "cpPinJointInit", dynlib: Lib.}
+#/ Allocate and initialize a pin joint.
+proc newPinJoint*(a: PBody; b: PBody; anchr1: TVector; anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpPinJointNew", dynlib: Lib.}
+# CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1)
+defCProp(PinJoint, TVector, anchr1, Anchr1)
+defCProp(PinJoint, TVector, anchr2, Anchr2)
+defCProp(PinJoint, CpFloat, dist, Dist)
+
+proc SlideJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpSlideJointGetClass", dynlib: Lib.}
+#/ Allocate a slide joint.
+proc AllocSlideJoint*(): PSlideJoint{.
+  cdecl, importc: "cpSlideJointAlloc", dynlib: Lib.}
+#/ Initialize a slide joint.
+proc init*(joint: PSlideJoint; a, b: PBody; anchr1, anchr2: TVector;
+            min, max: CpFloat): PSlideJoint{.
+  cdecl, importc: "cpSlideJointInit", dynlib: Lib.}
+#/ Allocate and initialize a slide joint.
+proc newSlideJoint*(a, b: PBody; anchr1, anchr2: TVector; min, max: CpFloat): PConstraint{.
+  cdecl, importc: "cpSlideJointNew", dynlib: Lib.}
+
+defCProp(SlideJoint, TVector, anchr1, Anchr1)
+defCProp(SlideJoint, TVector, anchr2, Anchr2)
+defCProp(SlideJoint, CpFloat, min, Min)
+defCProp(SlideJoint, CpFloat, max, Max)
+
+proc PivotJointGetClass*(): PConstraintClass {.
+  cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.}
+
+#/ Allocate a pivot joint
+proc allocPivotJoint*(): PPivotJoint{.
+  cdecl, importc: "cpPivotJointAlloc", dynlib: Lib.}
+#/ Initialize a pivot joint.
+proc init*(joint: PPivotJoint; a, b: PBody; anchr1, anchr2: TVector): PPivotJoint{.
+  cdecl, importc: "cpPivotJointInit", dynlib: Lib.}
+#/ Allocate and initialize a pivot joint.
+proc newPivotJoint*(a, b: PBody; pivot: TVector): PConstraint{.
+  cdecl, importc: "cpPivotJointNew", dynlib: Lib.}
+#/ Allocate and initialize a pivot joint with specific anchors.
+proc newPivotJoint*(a, b: PBody; anchr1, anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpPivotJointNew2", dynlib: Lib.}
+
+defCProp(PivotJoint, TVector, anchr1, Anchr1)
+defCProp(PivotJoint, TVector, anchr2, Anchr2)
+
+
+proc GrooveJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpGrooveJointGetClass", dynlib: Lib.}
+#/ Allocate a groove joint.
+proc GrooveJointAlloc*(): ptr TGrooveJoint{.
+  cdecl, importc: "cpGrooveJointAlloc", dynlib: Lib.}
+#/ Initialize a groove joint.
+proc Init*(joint: PGrooveJoint; a, b: PBody; groove_a, groove_b, anchr2: TVector): PGrooveJoint{.
+  cdecl, importc: "cpGrooveJointInit", dynlib: Lib.}
+#/ Allocate and initialize a groove joint.
+proc newGrooveJoint*(a, b: PBody; groove_a, groove_b, anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpGrooveJointNew", dynlib: Lib.}
+
+defCGetter(GrooveJoint, TVector, grv_a, GrooveA)
+defCGetter(GrooveJoint, TVector, grv_b, GrooveB)
+# /// Set endpoint a of a groove joint's groove
+proc SetGrooveA*(constraint: PConstraint, value: TVector) {.
+  cdecl, importc: "cpGrooveJointSetGrooveA", dynlib: Lib.}
+# /// Set endpoint b of a groove joint's groove
+proc SetGrooveB*(constraint: PConstraint, value: TVector) {.
+  cdecl, importc: "cpGrooveJointSetGrooveB", dynlib: Lib.}
+defCProp(GrooveJoint, TVector, anchr2, Anchr2)
+
+proc DampedSpringGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpDampedSpringGetClass", dynlib: Lib.}
+#/ Allocate a damped spring.
+proc AllocDampedSpring*(): PDampedSpring{.
+  cdecl, importc: "cpDampedSpringAlloc", dynlib: Lib.}
+#/ Initialize a damped spring.
+proc init*(joint: PDampedSpring; a, b: PBody; anchr1, anchr2: TVector;
+            restLength, stiffness, damping: CpFloat): PDampedSpring{.
+  cdecl, importc: "cpDampedSpringInit", dynlib: Lib.}
+#/ Allocate and initialize a damped spring.
+proc newDampedSpring*(a, b: PBody; anchr1, anchr2: TVector;
+                      restLength, stiffness, damping: CpFloat): PConstraint{.
+  cdecl, importc: "cpDampedSpringNew", dynlib: Lib.}
+
+# CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1)
+defCProp(DampedSpring, TVector, anchr1, Anchr1)
+defCProp(DampedSpring, TVector, anchr2, Anchr2)
+defCProp(DampedSpring, CpFloat, restLength, RestLength)
+defCProp(DampedSpring, CpFloat, stiffness, Stiffness)
+defCProp(DampedSpring, CpFloat, damping, Damping)
+defCProp(DampedSpring, TDampedSpringForceFunc, springForceFunc, SpringForceFunc)
+
+
+proc DampedRotarySpringGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpDampedRotarySpringGetClass", dynlib: Lib.}
+
+#/ Allocate a damped rotary spring.
+proc DampedRotarySpringAlloc*(): PDampedRotarySpring{.
+  cdecl, importc: "cpDampedRotarySpringAlloc", dynlib: Lib.}
+#/ Initialize a damped rotary spring.
+proc init*(joint: PDampedRotarySpring; a, b: PBody;
+            restAngle, stiffness, damping: CpFloat): PDampedRotarySpring{.
+  cdecl, importc: "cpDampedRotarySpringInit", dynlib: Lib.}
+#/ Allocate and initialize a damped rotary spring.
+proc DampedRotarySpringNew*(a, b: PBody; restAngle, stiffness, damping: CpFloat): PConstraint{.
+  cdecl, importc: "cpDampedRotarySpringNew", dynlib: Lib.}
+
+defCProp(DampedRotarySpring, CpFloat, restAngle, RestAngle)
+defCProp(DampedRotarySpring, CpFloat, stiffness, Stiffness)
+defCProp(DampedRotarySpring, CpFloat, damping, Damping)
+defCProp(DampedRotarySpring, TDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc)
+
+
+proc RotaryLimitJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpRotaryLimitJointGetClass", dynlib: Lib.}
+#/ Allocate a damped rotary limit joint.
+proc allocRotaryLimitJoint*(): PRotaryLimitJoint{.
+  cdecl, importc: "cpRotaryLimitJointAlloc", dynlib: Lib.}
+#/ Initialize a damped rotary limit joint.
+proc init*(joint: PRotaryLimitJoint; a, b: PBody; min, max: CpFloat): PRotaryLimitJoint{.
+  cdecl, importc: "cpRotaryLimitJointInit", dynlib: Lib.}
+#/ Allocate and initialize a damped rotary limit joint.
+proc newRotaryLimitJoint*(a, b: PBody; min, max: CpFloat): PConstraint{.
+  cdecl, importc: "cpRotaryLimitJointNew", dynlib: Lib.}
+
+defCProp(RotaryLimitJoint, CpFloat, min, Min)
+defCProp(RotaryLimitJoint, CpFloat, max, Max)
+
+
+proc RatchetJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpRatchetJointGetClass", dynlib: Lib.}
+#/ Allocate a ratchet joint.
+proc AllocRatchetJoint*(): PRatchetJoint{.
+  cdecl, importc: "cpRatchetJointAlloc", dynlib: Lib.}
+#/ Initialize a ratched joint.
+proc init*(joint: PRatchetJoint; a, b: PBody; phase, ratchet: CpFloat): PRatchetJoint{.
+  cdecl, importc: "cpRatchetJointInit", dynlib: Lib.}
+#/ Allocate and initialize a ratchet joint.
+proc NewRatchetJoint*(a, b: PBody; phase, ratchet: CpFloat): PConstraint{.
+  cdecl, importc: "cpRatchetJointNew", dynlib: Lib.}
+
+defCProp(RatchetJoint, CpFloat, angle, Angle)
+defCProp(RatchetJoint, CpFloat, phase, Phase)
+defCProp(RatchetJoint, CpFloat, ratchet, Ratchet)
+
+
+proc GearJointGetClass*(): PConstraintClass{.cdecl,
+    importc: "cpGearJointGetClass", dynlib: Lib.}
+#/ Allocate a gear joint.
+proc AllocGearJoint*(): PGearJoint{.
+  cdecl, importc: "cpGearJointAlloc", dynlib: Lib.}
+#/ Initialize a gear joint.
+proc init*(joint: PGearJoint; a, b: PBody, phase, ratio: CpFloat): PGearJoint{.
+  cdecl, importc: "cpGearJointInit", dynlib: Lib.}
+#/ Allocate and initialize a gear joint.
+proc NewGearJoint*(a, b: PBody; phase, ratio: CpFloat): PConstraint{.
+  cdecl, importc: "cpGearJointNew", dynlib: Lib.}
+
+defCProp(GearJoint, CpFloat, phase, Phase)
+defCGetter(GearJoint, CpFloat, ratio, Ratio)
+#/ Set the ratio of a gear joint.
+proc GearJointSetRatio*(constraint: PConstraint; value: CpFloat){.
+  cdecl, importc: "cpGearJointSetRatio", dynlib: Lib.}
+
+
+proc SimpleMotorGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpSimpleMotorGetClass", dynlib: Lib.}
+#/ Allocate a simple motor.
+proc AllocSimpleMotor*(): PSimpleMotor{.
+  cdecl, importc: "cpSimpleMotorAlloc", dynlib: Lib.}
+#/ initialize a simple motor.
+proc init*(joint: PSimpleMotor; a, b: PBody;
+                      rate: CpFloat): PSimpleMotor{.
+  cdecl, importc: "cpSimpleMotorInit", dynlib: Lib.}
+#/ Allocate and initialize a simple motor.
+proc newSimpleMotor*(a, b: PBody; rate: CpFloat): PConstraint{.
+  cdecl, importc: "cpSimpleMotorNew", dynlib: Lib.}
+
+defCProp(SimpleMotor, CpFloat, rate, Rate)
+
+
+
diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
new file mode 100644
index 000000000..5dee6ae9c
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
@@ -0,0 +1,611 @@
+discard """Copyright (c) 2002-2012 Lee Salzman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+
+const Lib = "libenet.so.1(|.0.3)"
+
+const
+  ENET_VERSION_MAJOR* = 1
+  ENET_VERSION_MINOR* = 3
+  ENET_VERSION_PATCH* = 3
+template ENET_VERSION_CREATE(major, minor, patch: untyped): untyped =
+  (((major) shl 16) or ((minor) shl 8) or (patch))
+
+const
+  ENET_VERSION* = ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR,
+                                      ENET_VERSION_PATCH)
+type
+  TVersion* = cuint
+  TSocketType*{.size: sizeof(cint).} = enum
+    ENET_SOCKET_TYPE_STREAM = 1, ENET_SOCKET_TYPE_DATAGRAM = 2
+  TSocketWait*{.size: sizeof(cint).} = enum
+    ENET_SOCKET_WAIT_NONE = 0, ENET_SOCKET_WAIT_SEND = (1 shl 0),
+    ENET_SOCKET_WAIT_RECEIVE = (1 shl 1)
+  TSocketOption*{.size: sizeof(cint).} = enum
+    ENET_SOCKOPT_NONBLOCK = 1, ENET_SOCKOPT_BROADCAST = 2,
+    ENET_SOCKOPT_RCVBUF = 3, ENET_SOCKOPT_SNDBUF = 4,
+    ENET_SOCKOPT_REUSEADDR = 5
+const
+  ENET_HOST_ANY* = 0
+  ENET_HOST_BROADCAST* = 0xFFFFFFFF
+  ENET_PORT_ANY* = 0
+
+  ENET_PROTOCOL_MINIMUM_MTU* = 576
+  ENET_PROTOCOL_MAXIMUM_MTU* = 4096
+  ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS* = 32
+  ENET_PROTOCOL_MINIMUM_WINDOW_SIZE* = 4096
+  ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE* = 32768
+  ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT* = 1
+  ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT* = 255
+  ENET_PROTOCOL_MAXIMUM_PEER_ID* = 0x00000FFF
+type
+  PAddress* = ptr TAddress
+  TAddress*{.pure, final.} = object
+    host*: cuint
+    port*: cushort
+
+  TPacketFlag*{.size: sizeof(cint).} = enum
+    FlagReliable = (1 shl 0),
+    FlagUnsequenced = (1 shl 1),
+    NoAllocate = (1 shl 2),
+    UnreliableFragment = (1 shl 3)
+
+  TENetListNode*{.pure, final.} = object
+      next*: ptr T_ENetListNode
+      previous*: ptr T_ENetListNode
+
+  PENetListIterator* = ptr TENetListNode
+  TENetList*{.pure, final.} = object
+    sentinel*: TENetListNode
+
+  T_ENetPacket*{.pure, final.} = object
+  TPacketFreeCallback* = proc (a2: ptr T_ENetPacket){.cdecl.}
+
+  PPacket* = ptr TPacket
+  TPacket*{.pure, final.} = object
+    referenceCount: csize_t
+    flags*: cint
+    data*: cstring#ptr cuchar
+    dataLength*: csize_t
+    freeCallback*: TPacketFreeCallback
+
+  PAcknowledgement* = ptr TAcknowledgement
+  TAcknowledgement*{.pure, final.} = object
+    acknowledgementList*: TEnetListNode
+    sentTime*: cuint
+    command*: TEnetProtocol
+
+  POutgoingCommand* = ptr TOutgoingCommand
+  TOutgoingCommand*{.pure, final.} = object
+    outgoingCommandList*: TEnetListNode
+    reliableSequenceNumber*: cushort
+    unreliableSequenceNumber*: cushort
+    sentTime*: cuint
+    roundTripTimeout*: cuint
+    roundTripTimeoutLimit*: cuint
+    fragmentOffset*: cuint
+    fragmentLength*: cushort
+    sendAttempts*: cushort
+    command*: TEnetProtocol
+    packet*: PPacket
+
+  PIncomingCommand* = ptr TIncomingCommand
+  TIncomingCommand*{.pure, final.} = object
+    incomingCommandList*: TEnetListNode
+    reliableSequenceNumber*: cushort
+    unreliableSequenceNumber*: cushort
+    command*: TEnetProtocol
+    fragmentCount*: cuint
+    fragmentsRemaining*: cuint
+    fragments*: ptr cuint
+    packet*: ptr TPacket
+
+  TPeerState*{.size: sizeof(cint).} = enum
+    ENET_PEER_STATE_DISCONNECTED = 0, ENET_PEER_STATE_CONNECTING = 1,
+    ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2,
+    ENET_PEER_STATE_CONNECTION_PENDING = 3,
+    ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, ENET_PEER_STATE_CONNECTED = 5,
+    ENET_PEER_STATE_DISCONNECT_LATER = 6, ENET_PEER_STATE_DISCONNECTING = 7,
+    ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, ENET_PEER_STATE_ZOMBIE = 9
+
+  TENetProtocolCommand*{.size: sizeof(cint).} = enum
+    ENET_PROTOCOL_COMMAND_NONE = 0, ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1,
+    ENET_PROTOCOL_COMMAND_CONNECT = 2,
+    ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3,
+    ENET_PROTOCOL_COMMAND_DISCONNECT = 4, ENET_PROTOCOL_COMMAND_PING = 5,
+    ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6,
+    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7,
+    ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8,
+    ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9,
+    ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10,
+    ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11,
+    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12,
+    ENET_PROTOCOL_COMMAND_COUNT = 13, ENET_PROTOCOL_COMMAND_MASK = 0x0000000F
+  TENetProtocolFlag*{.size: sizeof(cint).} = enum
+    ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12,
+    ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 shl 6),
+    ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 shl 7),
+    ENET_PROTOCOL_HEADER_SESSION_MASK = (3 shl 12),
+    ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 shl 14),
+    ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 shl 15),
+    ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED.cint or
+        ENET_PROTOCOL_HEADER_FLAG_SENT_TIME.cint
+
+  TENetProtocolHeader*{.pure, final.} = object
+    peerID*: cushort
+    sentTime*: cushort
+
+  TENetProtocolCommandHeader*{.pure, final.} = object
+    command*: cuchar
+    channelID*: cuchar
+    reliableSequenceNumber*: cushort
+
+  TENetProtocolAcknowledge*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    receivedReliableSequenceNumber*: cushort
+    receivedSentTime*: cushort
+
+  TENetProtocolConnect*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    outgoingPeerID*: cushort
+    incomingSessionID*: cuchar
+    outgoingSessionID*: cuchar
+    mtu*: cuint
+    windowSize*: cuint
+    channelCount*: cuint
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    connectID*: cuint
+    data*: cuint
+
+  TENetProtocolVerifyConnect*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    outgoingPeerID*: cushort
+    incomingSessionID*: cuchar
+    outgoingSessionID*: cuchar
+    mtu*: cuint
+    windowSize*: cuint
+    channelCount*: cuint
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    connectID*: cuint
+
+  TENetProtocolBandwidthLimit*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+
+  TENetProtocolThrottleConfigure*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+
+  TENetProtocolDisconnect*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    data*: cuint
+
+  TENetProtocolPing*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+
+  TENetProtocolSendReliable*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    dataLength*: cushort
+
+  TENetProtocolSendUnreliable*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    unreliableSequenceNumber*: cushort
+    dataLength*: cushort
+
+  TENetProtocolSendUnsequenced*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    unsequencedGroup*: cushort
+    dataLength*: cushort
+
+  TENetProtocolSendFragment*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+    startSequenceNumber*: cushort
+    dataLength*: cushort
+    fragmentCount*: cuint
+    fragmentNumber*: cuint
+    totalLength*: cuint
+    fragmentOffset*: cuint
+
+  ## this is incomplete; need helper templates or something
+  ## ENetProtocol
+  TENetProtocol*{.pure, final.} = object
+    header*: TENetProtocolCommandHeader
+const
+  ENET_BUFFER_MAXIMUM* = (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
+  ENET_HOST_RECEIVE_BUFFER_SIZE          = 256 * 1024
+  ENET_HOST_SEND_BUFFER_SIZE             = 256 * 1024
+  ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL  = 1000
+  ENET_HOST_DEFAULT_MTU                  = 1400
+
+  ENET_PEER_DEFAULT_ROUND_TRIP_TIME      = 500
+  ENET_PEER_DEFAULT_PACKET_THROTTLE      = 32
+  ENET_PEER_PACKET_THROTTLE_SCALE        = 32
+  ENET_PEER_PACKET_THROTTLE_COUNTER      = 7
+  ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2
+  ENET_PEER_PACKET_THROTTLE_DECELERATION = 2
+  ENET_PEER_PACKET_THROTTLE_INTERVAL     = 5000
+  ENET_PEER_PACKET_LOSS_SCALE            = (1 shl 16)
+  ENET_PEER_PACKET_LOSS_INTERVAL         = 10000
+  ENET_PEER_WINDOW_SIZE_SCALE            = 64 * 1024
+  ENET_PEER_TIMEOUT_LIMIT                = 32
+  ENET_PEER_TIMEOUT_MINIMUM              = 5000
+  ENET_PEER_TIMEOUT_MAXIMUM              = 30000
+  ENET_PEER_PING_INTERVAL                = 500
+  ENET_PEER_UNSEQUENCED_WINDOWS          = 64
+  ENET_PEER_UNSEQUENCED_WINDOW_SIZE      = 1024
+  ENET_PEER_FREE_UNSEQUENCED_WINDOWS     = 32
+  ENET_PEER_RELIABLE_WINDOWS             = 16
+  ENET_PEER_RELIABLE_WINDOW_SIZE         = 0x1000
+  ENET_PEER_FREE_RELIABLE_WINDOWS        = 8
+
+when defined(linux) or true:
+  import posix
+  const
+    ENET_SOCKET_NULL*: cint = -1
+  type
+    TENetSocket* = cint
+    PEnetBuffer* = ptr object
+    TENetBuffer*{.pure, final.} = object
+      data*: pointer
+      dataLength*: csize_t
+    TENetSocketSet* = Tfd_set
+  ## see if these are different on win32, if not then get rid of these
+  template ENET_HOST_TO_NET_16*(value: untyped): untyped =
+    (htons(value))
+  template ENET_HOST_TO_NET_32*(value: untyped): untyped =
+    (htonl(value))
+  template ENET_NET_TO_HOST_16*(value: untyped): untyped =
+    (ntohs(value))
+  template ENET_NET_TO_HOST_32*(value: untyped): untyped =
+    (ntohl(value))
+
+  template ENET_SOCKETSET_EMPTY*(sockset: untyped): untyped =
+    FD_ZERO(addr((sockset)))
+  template ENET_SOCKETSET_ADD*(sockset, socket: untyped): untyped =
+    FD_SET(socket, addr((sockset)))
+  template ENET_SOCKETSET_REMOVE*(sockset, socket: untyped): untyped =
+    FD_CLEAR(socket, addr((sockset)))
+  template ENET_SOCKETSET_CHECK*(sockset, socket: untyped): untyped =
+    FD_ISSET(socket, addr((sockset)))
+
+when defined(windows):
+  ## put the content of win32.h in here
+
+
+type
+  PChannel* = ptr TChannel
+  TChannel*{.pure, final.} = object
+    outgoingReliableSequenceNumber*: cushort
+    outgoingUnreliableSequenceNumber*: cushort
+    usedReliableWindows*: cushort
+    reliableWindows*: array[0..ENET_PEER_RELIABLE_WINDOWS - 1, cushort]
+    incomingReliableSequenceNumber*: cushort
+    incomingUnreliableSequenceNumber*: cushort
+    incomingReliableCommands*: TENetList
+    incomingUnreliableCommands*: TENetList
+
+  PPeer* = ptr TPeer
+  TPeer*{.pure, final.} = object
+    dispatchList*: TEnetListNode
+    host*: ptr THost
+    outgoingPeerID*: cushort
+    incomingPeerID*: cushort
+    connectID*: cuint
+    outgoingSessionID*: cuchar
+    incomingSessionID*: cuchar
+    address*: TAddress
+    data*: pointer
+    state*: TPeerState
+    channels*: PChannel
+    channelCount*: csize_t
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    incomingBandwidthThrottleEpoch*: cuint
+    outgoingBandwidthThrottleEpoch*: cuint
+    incomingDataTotal*: cuint
+    outgoingDataTotal*: cuint
+    lastSendTime*: cuint
+    lastReceiveTime*: cuint
+    nextTimeout*: cuint
+    earliestTimeout*: cuint
+    packetLossEpoch*: cuint
+    packetsSent*: cuint
+    packetsLost*: cuint
+    packetLoss*: cuint
+    packetLossVariance*: cuint
+    packetThrottle*: cuint
+    packetThrottleLimit*: cuint
+    packetThrottleCounter*: cuint
+    packetThrottleEpoch*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    packetThrottleInterval*: cuint
+    lastRoundTripTime*: cuint
+    lowestRoundTripTime*: cuint
+    lastRoundTripTimeVariance*: cuint
+    highestRoundTripTimeVariance*: cuint
+    roundTripTime*: cuint
+    roundTripTimeVariance*: cuint
+    mtu*: cuint
+    windowSize*: cuint
+    reliableDataInTransit*: cuint
+    outgoingReliableSequenceNumber*: cushort
+    acknowledgements*: TENetList
+    sentReliableCommands*: TENetList
+    sentUnreliableCommands*: TENetList
+    outgoingReliableCommands*: TENetList
+    outgoingUnreliableCommands*: TENetList
+    dispatchedCommands*: TENetList
+    needsDispatch*: cint
+    incomingUnsequencedGroup*: cushort
+    outgoingUnsequencedGroup*: cushort
+    unsequencedWindow*: array[0..ENET_PEER_UNSEQUENCED_WINDOW_SIZE div 32 - 1,
+                              cuint]
+    eventData*: cuint
+
+  PCompressor* = ptr TCompressor
+  TCompressor*{.pure, final.} = object
+    context*: pointer
+    compress*: proc (context: pointer; inBuffers: ptr TEnetBuffer;
+                     inBufferCount: csize_t; inLimit: csize_t;
+                     outData: ptr cuchar; outLimit: csize_t): csize_t{.cdecl.}
+    decompress*: proc (context: pointer; inData: ptr cuchar; inLimit: csize_t;
+                       outData: ptr cuchar; outLimit: csize_t): csize_t{.cdecl.}
+    destroy*: proc (context: pointer){.cdecl.}
+
+  TChecksumCallback* = proc (buffers: ptr TEnetBuffer; bufferCount: csize_t): cuint{.
+      cdecl.}
+
+  PHost* = ptr THost
+  THost*{.pure, final.} = object
+    socket*: TEnetSocket
+    address*: TAddress
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    bandwidthThrottleEpoch*: cuint
+    mtu*: cuint
+    randomSeed*: cuint
+    recalculateBandwidthLimits*: cint
+    peers*: ptr TPeer
+    peerCount*: csize_t
+    channelLimit*: csize_t
+    serviceTime*: cuint
+    dispatchQueue*: TEnetList
+    continueSending*: cint
+    packetSize*: csize_t
+    headerFlags*: cushort
+    commands*: array[0..ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS - 1,
+                     TEnetProtocol]
+    commandCount*: csize_t
+    buffers*: array[0..ENET_BUFFER_MAXIMUM - 1, TEnetBuffer]
+    bufferCount*: csize_t
+    checksum*: TChecksumCallback
+    compressor*: TCompressor
+    packetData*: array[0..ENET_PROTOCOL_MAXIMUM_MTU - 1,
+                       array[0..2 - 1, cuchar]]
+    receivedAddress*: TAddress
+    receivedData*: ptr cuchar
+    receivedDataLength*: csize_t
+    totalSentData*: cuint
+    totalSentPackets*: cuint
+    totalReceivedData*: cuint
+    totalReceivedPackets*: cuint
+
+  TEventType*{.size: sizeof(cint).} = enum
+    EvtNone = 0, EvtConnect = 1,
+    EvtDisconnect = 2, EvtReceive = 3
+  PEvent* = ptr TEvent
+  TEvent*{.pure, final.} = object
+    kind*: TEventType
+    peer*: ptr TPeer
+    channelID*: cuchar
+    data*: cuint
+    packet*: ptr TPacket
+
+  TENetCallbacks*{.pure, final.} = object
+    malloc*: proc (size: csize_t): pointer{.cdecl.}
+    free*: proc (memory: pointer){.cdecl.}
+    no_memory*: proc (){.cdecl.}
+
+{.push callConv:cdecl.}
+proc enet_malloc*(a2: csize_t): pointer{.
+  importc: "enet_malloc", dynlib: Lib.}
+proc enet_free*(a2: pointer){.
+  importc: "enet_free", dynlib: Lib.}
+
+proc enetInit*(): cint{.
+  importc: "enet_initialize", dynlib: Lib.}
+proc enetInit*(version: TVersion; inits: ptr TENetCallbacks): cint{.
+  importc: "enet_initialize_with_callbacks", dynlib: Lib.}
+proc enetDeinit*(){.
+  importc: "enet_deinitialize", dynlib: Lib.}
+proc enet_time_get*(): cuint{.
+  importc: "enet_time_get", dynlib: Lib.}
+proc enet_time_set*(a2: cuint){.
+  importc: "enet_time_set", dynlib: Lib.}
+
+#enet docs are pretty lacking, i'm not sure what the names of these arguments should be
+proc createSocket*(kind: TSocketType): TEnetSocket{.
+  importc: "enet_socket_create", dynlib: Lib.}
+proc bindTo*(socket: TEnetSocket; address: var TAddress): cint{.
+  importc: "enet_socket_bind", dynlib: Lib.}
+proc bindTo*(socket: TEnetSocket; address: ptr TAddress): cint{.
+  importc: "enet_socket_bind", dynlib: Lib.}
+proc listen*(socket: TEnetSocket; a3: cint): cint{.
+  importc: "enet_socket_listen", dynlib: Lib.}
+proc accept*(socket: TEnetSocket; address: var TAddress): TEnetSocket{.
+  importc: "enet_socket_accept", dynlib: Lib.}
+proc accept*(socket: TEnetSocket; address: ptr TAddress): TEnetSocket{.
+  importc: "enet_socket_accept", dynlib: Lib.}
+proc connect*(socket: TEnetSocket; address: var TAddress): cint{.
+  importc: "enet_socket_connect", dynlib: Lib.}
+proc connect*(socket: TEnetSocket; address: ptr TAddress): cint{.
+  importc: "enet_socket_connect", dynlib: Lib.}
+proc send*(socket: TEnetSocket; address: var TAddress; buffer: ptr TEnetBuffer; size: csize_t): cint{.
+  importc: "enet_socket_send", dynlib: Lib.}
+proc send*(socket: TEnetSocket; address: ptr TAddress; buffer: ptr TEnetBuffer; size: csize_t): cint{.
+  importc: "enet_socket_send", dynlib: Lib.}
+proc receive*(socket: TEnetSocket; address: var TAddress;
+               buffer: ptr TEnetBuffer; size: csize_t): cint{.
+  importc: "enet_socket_receive", dynlib: Lib.}
+proc receive*(socket: TEnetSocket; address: ptr TAddress;
+               buffer: ptr TEnetBuffer; size: csize_t): cint{.
+  importc: "enet_socket_receive", dynlib: Lib.}
+proc wait*(socket: TEnetSocket; a3: ptr cuint; a4: cuint): cint{.
+  importc: "enet_socket_wait", dynlib: Lib.}
+proc setOption*(socket: TEnetSocket; a3: TSocketOption; a4: cint): cint{.
+  importc: "enet_socket_set_option", dynlib: Lib.}
+proc destroy*(socket: TEnetSocket){.
+  importc: "enet_socket_destroy", dynlib: Lib.}
+proc select*(socket: TEnetSocket; a3: ptr TENetSocketSet;
+              a4: ptr TENetSocketSet; a5: cuint): cint{.
+  importc: "enet_socketset_select", dynlib: Lib.}
+
+proc setHost*(address: PAddress; hostName: cstring): cint{.
+  importc: "enet_address_set_host", dynlib: Lib.}
+proc setHost*(address: var TAddress; hostName: cstring): cint{.
+  importc: "enet_address_set_host", dynlib: Lib.}
+proc getHostIP*(address: var TAddress; hostName: cstring; nameLength: csize_t): cint{.
+  importc: "enet_address_get_host_ip", dynlib: Lib.}
+proc getHost*(address: var TAddress; hostName: cstring; nameLength: csize_t): cint{.
+  importc: "enet_address_get_host", dynlib: Lib.}
+
+## Call the above two funcs but trim the result string
+proc getHostIP*(address: var TAddress; hostName: var string; nameLength: csize_t): cint{.inline.} =
+  hostName.setLen nameLength
+  result = getHostIP(address, cstring(hostName), nameLength)
+  if result == 0:
+    hostName.setLen(len(cstring(hostName)))
+proc getHost*(address: var TAddress; hostName: var string; nameLength: csize_t): cint{.inline.} =
+  hostName.setLen nameLength
+  result = getHost(address, cstring(hostName), nameLength)
+  if result == 0:
+    hostName.setLen(len(cstring(hostName)))
+
+proc createPacket*(data: pointer; len: csize_t; flag: TPacketFlag): PPacket{.
+  importc: "enet_packet_create", dynlib: Lib.}
+proc destroy*(packet: PPacket){.
+  importc: "enet_packet_destroy", dynlib: Lib.}
+proc resize*(packet: PPacket; dataLength: csize_t): cint{.
+  importc: "enet_packet_resize", dynlib: Lib.}
+
+proc crc32*(buffers: ptr TEnetBuffer; bufferCount: csize_t): cuint{.
+  importc: "enet_crc32", dynlib: Lib.}
+
+proc createHost*(address: ptr TAddress; maxConnections, maxChannels: csize_t; downSpeed, upSpeed: cuint): PHost{.
+  importc: "enet_host_create", dynlib: Lib.}
+proc createHost*(address: var TAddress; maxConnections, maxChannels: csize_t; downSpeed, upSpeed: cuint): PHost{.
+  importc: "enet_host_create", dynlib: Lib.}
+proc destroy*(host: PHost){.
+  importc: "enet_host_destroy", dynlib: Lib.}
+proc connect*(host: PHost; address: ptr TAddress; channelCount: csize_t; data: cuint): PPeer{.
+  importc: "enet_host_connect", dynlib: Lib.}
+proc connect*(host: PHost; address: var TAddress; channelCount: csize_t; data: cuint): PPeer{.
+  importc: "enet_host_connect", dynlib: Lib.}
+
+proc checkEvents*(host: PHost; event: var TEvent): cint{.
+  importc: "enet_host_check_events", dynlib: Lib.}
+proc checkEvents*(host: PHost; event: ptr TEvent): cint{.
+  importc: "enet_host_check_events", dynlib: Lib.}
+proc hostService*(host: PHost; event: var TEvent; timeout: cuint): cint{.
+  importc: "enet_host_service", dynlib: Lib.}
+proc hostService*(host: PHost; event: ptr TEvent; timeout: cuint): cint{.
+  importc: "enet_host_service", dynlib: Lib.}
+proc flush*(host: PHost){.
+  importc: "enet_host_flush", dynlib: Lib.}
+proc broadcast*(host: PHost; channelID: cuchar; packet: PPacket){.
+  importc: "enet_host_broadcast", dynlib: Lib.}
+proc compress*(host: PHost; compressor: PCompressor){.
+  importc: "enet_host_compress", dynlib: Lib.}
+proc compressWithRangeCoder*(host: PHost): cint{.
+  importc: "enet_host_compress_with_range_coder", dynlib: Lib.}
+proc channelLimit*(host: PHost; channelLimit: csize_t){.
+  importc: "enet_host_channel_limit", dynlib: Lib.}
+proc bandwidthLimit*(host: PHost; incoming, outgoing: cuint){.
+  importc: "enet_host_bandwidth_limit", dynlib: Lib.}
+proc bandwidthThrottle*(host: PHost){.
+  importc: "enet_host_bandwidth_throttle", dynlib: Lib.}
+
+
+proc send*(peer: PPeer; channel: cuchar; packet: PPacket): cint{.
+  importc: "enet_peer_send", dynlib: Lib.}
+proc receive*(peer: PPeer; channelID: ptr cuchar): PPacket{.
+  importc: "enet_peer_receive", dynlib: Lib.}
+proc ping*(peer: PPeer){.
+  importc: "enet_peer_ping", dynlib: Lib.}
+proc reset*(peer: PPeer){.
+  importc: "enet_peer_reset", dynlib: Lib.}
+proc disconnect*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect", dynlib: Lib.}
+proc disconnectNow*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect_now", dynlib: Lib.}
+proc disconnectLater*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect_later", dynlib: Lib.}
+proc throttleConfigure*(peer: PPeer; interval, acceleration, deceleration: cuint){.
+  importc: "enet_peer_throttle_configure", dynlib: Lib.}
+proc throttle*(peer: PPeer; rtt: cuint): cint{.
+  importc: "enet_peer_throttle", dynlib: Lib.}
+proc resetQueues*(peer: PPeer){.
+  importc: "enet_peer_reset_queues", dynlib: Lib.}
+proc setupOutgoingCommand*(peer: PPeer; outgoingCommand: POutgoingCommand){.
+  importc: "enet_peer_setup_outgoing_command", dynlib: Lib.}
+
+proc queueOutgoingCommand*(peer: PPeer; command: ptr TEnetProtocol;
+          packet: PPacket; offset: cuint; length: cushort): POutgoingCommand{.
+  importc: "enet_peer_queue_outgoing_command", dynlib: Lib.}
+proc queueIncomingCommand*(peer: PPeer; command: ptr TEnetProtocol;
+                    packet: PPacket; fragmentCount: cuint): PIncomingCommand{.
+  importc: "enet_peer_queue_incoming_command", dynlib: Lib.}
+proc queueAcknowledgement*(peer: PPeer; command: ptr TEnetProtocol;
+                            sentTime: cushort): PAcknowledgement{.
+  importc: "enet_peer_queue_acknowledgement", dynlib: Lib.}
+proc dispatchIncomingUnreliableCommands*(peer: PPeer; channel: PChannel){.
+  importc: "enet_peer_dispatch_incoming_unreliable_commands", dynlib: Lib.}
+proc dispatchIncomingReliableCommands*(peer: PPeer; channel: PChannel){.
+  importc: "enet_peer_dispatch_incoming_reliable_commands", dynlib: Lib.}
+
+proc createRangeCoder*(): pointer{.
+  importc: "enet_range_coder_create", dynlib: Lib.}
+proc rangeCoderDestroy*(context: pointer){.
+  importc: "enet_range_coder_destroy", dynlib: Lib.}
+proc rangeCoderCompress*(context: pointer; inBuffers: PEnetBuffer; inLimit,
+               bufferCount: csize_t; outData: cstring; outLimit: csize_t): csize_t{.
+  importc: "enet_range_coder_compress", dynlib: Lib.}
+proc rangeCoderDecompress*(context: pointer; inData: cstring; inLimit: csize_t;
+                            outData: cstring; outLimit: csize_t): csize_t{.
+  importc: "enet_range_coder_decompress", dynlib: Lib.}
+proc protocolCommandSize*(commandNumber: cuchar): csize_t{.
+  importc: "enet_protocol_command_size", dynlib: Lib.}
+
+{.pop.}
+
+from hashes import `!$`, `!&`, Hash, hash
+proc hash*(x: TAddress): Hash {.nimcall, noSideEffect.} =
+  result = !$(hash(x.host.int32) !& hash(x.port.int16))
diff --git a/tests/manyloc/keineschweine/dependencies/enet/testclient.nim b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim
new file mode 100644
index 000000000..2447a1fb5
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim
@@ -0,0 +1,49 @@
+import enet, strutils
+
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+var
+  address: enet.TAddress
+  event: TEvent
+  peer: PPeer
+  client: PHost
+
+client = createHost(nil, 1, 2, 0, 0)
+if client == nil:
+  quit "Could not create client!"
+
+if setHost(addr address, "localhost") != 0:
+  quit "Could not set host"
+address.port = 8024
+
+peer = client.connect(addr address, 2, 0)
+if peer == nil:
+  quit "No available peers"
+
+block:
+  var bConnected = false
+  while not bConnected:
+    if client.hostService(event, 5000) > 0 and event.kind == EvtConnect:
+      echo "Connected"
+      bConnected = true
+    else:
+      echo "Connection failed"
+      quit 0
+
+var runServer = true
+while client.hostService(event, 1000) >= 0 and runServer:
+  case event.kind
+  of EvtReceive:
+    echo "Recvd ($1) $2 ".format(
+      event.packet.dataLength,
+      event.packet.data)
+  of EvtDisconnect:
+    echo "Disconnected"
+    event.peer.data = nil
+    runServer = false
+  of EvtNone: discard
+  else:
+    echo repr(event)
+
+
+client.destroy()
diff --git a/tests/manyloc/keineschweine/dependencies/enet/testserver.nim b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim
new file mode 100644
index 000000000..6d6de90c1
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim
@@ -0,0 +1,45 @@
+import enet, strutils
+var
+  address: enet.TAddress
+  server: PHost
+  event: TEvent
+
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+
+address.host = EnetHostAny
+address.port = 8024
+
+server = enet.createHost(
+  addr address, 32, 2,  0,  0)
+if server == nil:
+  quit "Could not create the server!"
+
+while server.hostService(addr event, 2500) >= 0:
+  case event.kind
+  of EvtConnect:
+    echo "New client from $1:$2".format(event.peer.address.host, event.peer.address.port)
+
+    var
+      msg = "hello"
+      resp = createPacket(cstring(msg), msg.len + 1, FlagReliable)
+
+    if event.peer.send(0.cuchar, resp) < 0:
+      echo "FAILED"
+    else:
+      echo "Replied"
+  of EvtReceive:
+    echo "Recvd ($1) $2 ".format(
+      event.packet.dataLength,
+      event.packet.data)
+
+    destroy(event.packet)
+
+  of EvtDisconnect:
+    echo "Disconnected"
+    event.peer.data = nil
+  else:
+    discard
+
+server.destroy()
+enetDeinit()
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
new file mode 100644
index 000000000..d91f1cb35
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
@@ -0,0 +1,287 @@
+import macros, macro_dsl, estreams
+from strutils import format
+
+template newLenName() =
+  let lenName {.inject.} = ^("len" & $lenNames)
+  inc(lenNames)
+
+template defPacketImports*() {.dirty.} =
+  import macros, macro_dsl, estreams
+  from strutils import format
+
+macro defPacket*(typeNameN: untyped, typeFields: untyped): untyped =
+  result = newNimNode(nnkStmtList)
+  let
+    typeName = quoted2ident(typeNameN)
+    packetID = ^"p"
+    streamID = ^"s"
+  var
+    constructorParams = newNimNode(nnkFormalParams).und(typeName)
+    constructor = newNimNode(nnkProcDef).und(
+      postfix(^("new" & $typeName.ident), "*"),
+      emptyNode(),
+      emptyNode(),
+      constructorParams,
+      emptyNode(),
+      emptyNode())
+    pack = newNimNode(nnkProcDef).und(
+      postfix(^"pack", "*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        emptyNode(),   # : void
+        newNimNode(nnkIdentDefs).und(
+          streamID,    # s: PBuffer
+          ^"PBuffer",
+          newNimNode(nnkNilLit)),
+        newNimNode(nnkIdentDefs).und(
+          packetID,    # p: var typeName
+          newNimNode(nnkVarTy).und(typeName),
+          emptyNode())),
+      emptyNode(),
+      emptyNode())
+    read = newNimNode(nnkProcDef).und(
+      newIdentNode("read" & $typeName.ident).postfix("*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        typeName,   #result type
+        newNimNode(nnkIdentDefs).und(
+          streamID, # s: PBuffer = nil
+          ^"PBuffer",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    constructorBody = newNimNode(nnkStmtList)
+    packBody = newNimNode(nnkStmtList)
+    readBody = newNimNode(nnkStmtList)
+    lenNames = 0
+  for i in 0.. typeFields.len - 1:
+    let
+      name = typeFields[i][0]
+      dotName = packetID.dot(name)
+      resName = newIdentNode("result").dot(name)
+    case typeFields[i][1].kind
+    of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
+      case $typeFields[i][1][0].ident
+      of "seq":
+        ## let lenX = readInt16(s)
+        newLenName()
+        let
+          item = ^"item"  ## item name in our iterators
+          seqType = typeFields[i][1][1] ## type of seq
+          readName = newIdentNode("read" & $seqType.ident)
+        readBody.add(newNimNode(nnkLetSection).und(
+          newNimNode(nnkIdentDefs).und(
+            lenName,
+            newNimNode(nnkEmpty),
+            newCall("readInt16", streamID))))
+        readBody.add(      ## result.name = @[]
+          resName := ("@".prefix(newNimNode(nnkBracket))),
+          newNimNode(nnkForStmt).und(  ## for item in 1..len:
+            item,
+            infix(1.lit, "..", lenName),
+            newNimNode(nnkStmtList).und(
+              newCall(  ## add(result.name, unpack[seqType](stream))
+                "add", resName, newNimNode(nnkCall).und(readName, streamID)
+        ) ) ) )
+        packbody.add(
+          newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
+            lenName,  ## var lenName = int16(len(p.name))
+            newIdentNode("int16"),
+            newCall("int16", newCall("len", dotName)))),
+          newCall("writeBE", streamID, lenName),
+          newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
+            item,
+            infix(0.lit, "..", infix(lenName, "-", 1.lit)),
+            newNimNode(nnkStmtList).und(
+              newCall("echo", item, ": ".lit),
+              newCall("pack", streamID, dotName[item]))))
+        #set the default value to @[] (new sequence)
+        typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
+      else:
+        error("Unknown type: " & treeRepr(typeFields[i]))
+    of nnkIdent: ##normal type
+      case $typeFields[i][1].ident
+      of "string": # length encoded string
+        packBody.add(newCall("write", streamID, dotName))
+        readBody.add(resName := newCall("readStr", streamID))
+      of "int8", "int16", "int32", "float32", "float64", "char", "bool":
+        packBody.add(newCall(
+          "writeBE", streamID, dotName))
+        readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
+      else:  ## hopefully the type you specified was another defpacket() type
+        packBody.add(newCall("pack", streamID, dotName))
+        readBody.add(resName := newCall("read" & $typeFields[i][1].ident, streamID))
+    else:
+      error("I don't know what to do with: " & treerepr(typeFields[i]))
+
+  var
+    toStringFunc = newNimNode(nnkProcDef).und(
+      newNimNode(nnkPostfix).und(
+        ^"*",
+        newNimNode(nnkAccQuoted).und(^"$")),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        ^"string",
+        newNimNode(nnkIdentDefs).und(
+          packetID, # p: typeName
+          typeName,
+          emptyNode())),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkStmtList).und(# [6]
+        newNimNode(nnkAsgn).und(
+          ^"result",                  ## result =
+          newNimNode(nnkCall).und(# [6][0][1]
+            ^"format",  ## format
+            emptyNode()))))  ## "[TypeName   $1   $2]"
+    formatStr = "[" & $typeName.ident
+
+  const emptyFields = {nnkEmpty, nnkNilLit}
+  var objFields = newNimNode(nnkRecList)
+  for i in 0 ..< len(typeFields):
+    let fname = typeFields[i][0]
+    constructorParams.add(newNimNode(nnkIdentDefs).und(
+      fname,
+      typeFields[i][1],
+      typeFields[i][2]))
+    constructorBody.add((^"result").dot(fname) := fname)
+    #export the name
+    typeFields[i][0] = fname.postfix("*")
+    if not(typeFields[i][2].kind in emptyFields):
+      ## empty the type default for the type def
+      typeFields[i][2] = newNimNode(nnkEmpty)
+    objFields.add(typeFields[i])
+    toStringFunc[6][0][1].add(
+      prefix("$", packetID.dot(fname)))
+    formatStr.add "   $"
+    formatStr.add($(i + 1))
+
+  formatStr.add ']'
+  toStringFunc[6][0][1][1] = formatStr.lit()
+
+  result.add(
+    newNimNode(nnkTypeSection).und(
+      newNimNode(nnkTypeDef).und(
+        typeName.postfix("*"),
+        newNimNode(nnkEmpty),
+        newNimNode(nnkObjectTy).und(
+          newNimNode(nnkEmpty), #not sure what this is
+          newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
+          objFields))))
+  result.add(constructor.und(constructorBody))
+  result.add(pack.und(packBody))
+  result.add(read.und(readBody))
+  result.add(toStringFunc)
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+proc newProc*(name: NimNode; params: varargs[NimNode]; resultType: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkProcDef).und(
+    name,
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkFormalParams).und(resultType),
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkStmtList))
+  result[3].add(params)
+
+proc body*(procNode: NimNode): NimNode {.compileTime.} =
+  assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
+  result = procNode[6]
+
+proc iddefs*(a, b: string; c: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
+proc iddefs*(a: string; b: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
+proc varTy*(a: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkVarTy).und(a)
+
+macro forwardPacket*(typeName: untyped, underlyingType: untyped): untyped =
+  var
+    packetID = ^"p"
+    streamID = ^"s"
+  result = newNimNode(nnkStmtList).und(
+    newProc(
+      (^("read" & $typeName.ident)).postfix("*"),
+      [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
+      typeName),
+    newProc(
+      (^"pack").postfix("*"),
+      [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)),
+        iddefs("p", varTy(typeName)) ],
+      emptyNode()))
+  var
+    readBody = result[0][6]
+    packBody = result[1][6]
+    resName = ^"result"
+
+  case underlyingType.kind
+  of nnkBracketExpr:
+    case $underlyingType[0].ident
+    of "array":
+      for i in underlyingType[1][1].intval.int .. underlyingType[1][2].intval.int:
+        readBody.add(
+          newCall("read", ^"s", resName[lit(i)]))
+        packBody.add(
+          newCall("writeBE", ^"s", packetID[lit(i)]))
+    else:
+      echo "Unknown type: ", repr(underlyingtype)
+  else:
+    echo "unknown type:", repr(underlyingtype)
+  echo(repr(result))
+
+template forwardPacketT*(typeName: untyped; underlyingType: untyped) {.dirty.} =
+  proc `read typeName`*(buffer: PBuffer): typeName =
+    #discard readData(s, addr result, sizeof(result))
+    var res: underlyingType
+    buffer.read(res)
+    result = typeName(res)
+  proc `pack`*(buffer: PBuffer; ord: var typeName) =
+    #writeData(s, addr p, sizeof(p))
+    buffer.write(underlyingType(ord))
+
+when false:
+  type
+    SomeEnum = enum
+      A = 0'i8,
+      B, C
+  forwardPacket(SomeEnum, int8)
+
+
+  defPacket(Foo, tuple[x: array[0..4, int8]])
+  var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
+  var s2 = newStringStream("")
+  f.pack(s2)
+  assert s2.data == "\4\3\2\1\0"
+
+  var s = newStringStream()
+  s.flushImpl = proc(s: PStream) =
+    var z = PStringStream(s)
+    z.setPosition(0)
+    z.data.setLen(0)
+
+
+  s.setPosition(0)
+  s.data.setLen(0)
+  var o = B
+  o.pack(s)
+  o = A
+  o.pack(s)
+  o = C
+  o.pack(s)
+  assert s.data == "\1\0\2"
+  s.flush
+
+  defPacket(Y, tuple[z: int8])
+  proc `$`(z: Y): string = result = "Y(" & $z.z & ")"
+  defPacket(TestPkt, tuple[x: seq[Y]])
+  var test = newTestPkt()
+  test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
+  for itm in test.x:
+    echo(itm)
+  test.pack(s)
+  echo(repr(s.data))
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
new file mode 100644
index 000000000..3341f42c2
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
@@ -0,0 +1,64 @@
+import macros
+
+#Inline macro.add() to allow for easier nesting
+proc und*(a: NimNode; b: NimNode): NimNode {.compileTime.} =
+  a.add(b)
+  result = a
+proc und*(a: NimNode; b: varargs[NimNode]): NimNode {.compileTime.} =
+  a.add(b)
+  result = a
+
+proc `^`*(a: string): NimNode {.compileTime.} =
+  ## new ident node
+  result = newIdentNode(a)
+proc `[]`*(a, b: NimNode): NimNode {.compileTime.} =
+  ## new bracket expression: node[node] not to be confused with node[indx]
+  result = newNimNode(nnkBracketExpr).und(a, b)
+proc `:=`*(left, right: NimNode): NimNode {.compileTime.} =
+  ## new Asgn node:  left = right
+  result = newNimNode(nnkAsgn).und(left, right)
+
+proc lit*(a: string): NimNode {.compileTime.} =
+  result = newStrLitNode(a)
+proc lit*(a: int): NimNode {.compileTime.} =
+  result = newIntLitNode(a)
+proc lit*(a: float): NimNode {.compileTime.} =
+  result = newFloatLitNode(a)
+proc lit*(a: char): NimNode {.compileTime.} =
+  result = newNimNode(nnkCharLit)
+  result.intval = a.ord
+
+proc emptyNode*(): NimNode {.compileTime.} =
+  result = newNimNode(nnkEmpty)
+
+proc dot*(left, right: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkDotExpr).und(left, right)
+proc prefix*(a: string, b: NimNode): NimNode {.compileTime.} =
+  result = newNimNode(nnkPrefix).und(newIdentNode(a), b)
+
+proc quoted2ident*(a: NimNode): NimNode {.compileTime.} =
+  if a.kind != nnkAccQuoted:
+    return a
+  var pname = ""
+  for piece in 0..a.len - 1:
+    pname.add($a[piece].ident)
+  result = ^pname
+
+
+macro `?`(a: untyped): untyped =
+  ## Character literal ?A #=> 'A'
+  result = ($a[1].ident)[0].lit
+## echo(?F,?a,?t,?t,?y)
+
+when false:
+  macro foo(x: untyped) =
+    result = newNimNode(nnkStmtList)
+    result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit))
+    result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit))))
+    let stmtlist = x[1]
+    for i in countdown(len(stmtlist)-1, 0):
+      result.add(stmtlist[i])
+  foo:
+    echo y, " * 2 = ", y * 2
+    let y = 320
+
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
new file mode 100644
index 000000000..a0c8a7a3c
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
@@ -0,0 +1,47 @@
+import streams
+from strutils import repeat
+
+proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): string =
+  var lastChr = length
+  result = s.readStr(length)
+  while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr)
+  result.setLen(lastChr)
+
+proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
+  if str.len < length:
+    s.write(str)
+    s.write(repeat(padChar, length - str.len))
+  elif str.len > length:
+    s.write(str.substr(0, length - 1))
+  else:
+    s.write(str)
+
+proc readLEStr*(s: PStream): string =
+  var len = s.readInt16()
+  result = s.readStr(len)
+
+proc writeLEStr*(s: PStream, str: string) =
+  s.write(str.len.int16)
+  s.write(str)
+
+when true:
+  var testStream = newStringStream()
+
+  testStream.writeLEStr("Hello")
+  doAssert testStream.data == "\5\0Hello"
+
+  testStream.setPosition 0
+  var res = testStream.readLEStr()
+  doAssert res == "Hello"
+
+  testStream.setPosition 0
+  testStream.writePaddedStr("Sup", 10)
+  echo(repr(testStream), testStream.data.len)
+  doAssert testStream.data == "Sup"&repeat('\0', 7)
+
+  testStream.setPosition 0
+  res = testStream.readPaddedStr(10)
+  doAssert res == "Sup"
+
+  testStream.close()
+
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
new file mode 100644
index 000000000..36538097e
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
@@ -0,0 +1,88 @@
+discard """
+DO AS THOU WILST PUBLIC LICENSE
+
+Whoever should stumble upon this document is henceforth and forever
+entitled to DO AS THOU WILST with aforementioned document and the
+contents thereof.
+
+As said in the Olde Country, `Keepe it Gangster'."""
+
+#[
+xxx remove this? seems mostly duplicate of: tests/manyloc/nake/nake.nim
+]#
+
+import strutils, parseopt, tables, os
+
+type
+  PTask* = ref object
+    desc*: string
+    action*: TTaskFunction
+  TTaskFunction* = proc() {.closure.}
+var
+  tasks* = initTable[string, PTask](16)
+
+proc newTask*(desc: string; action: TTaskFunction): PTask
+proc runTask*(name: string) {.inline.}
+proc shell*(cmd: varargs[string, `$`]): int {.discardable.}
+proc cd*(dir: string) {.inline.}
+
+template nakeImports*(): stmt {.immediate.} =
+  import tables, parseopt, strutils, os
+
+template task*(name: string; description: string; body: stmt): stmt {.dirty, immediate.} =
+  block:
+    var t = newTask(description, proc() {.closure.} =
+      body)
+    tasks[name] = t
+
+proc newTask*(desc: string; action: TTaskFunction): PTask =
+  new(result)
+  result.desc = desc
+  result.action = action
+proc runTask*(name: string) = tasks[name].action()
+
+proc shell*(cmd: varargs[string, `$`]): int =
+  result = execShellCmd(cmd.join(" "))
+proc cd*(dir: string) = setCurrentDir(dir)
+template withDir*(dir: string; body: stmt): stmt =
+  ## temporary cd
+  ## withDir "foo":
+  ##   # inside foo
+  ## #back to last dir
+  var curDir = getCurrentDir()
+  cd(dir)
+  body
+  cd(curDir)
+
+when true:
+  if not fileExists("nakefile.nim"):
+    echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
+    quit 1
+  var args = ""
+  for i in 1..paramCount():
+    args.add paramStr(i)
+    args.add " "
+  quit(shell("nim", "c", "-r", "nakefile.nim", args))
+else:
+  import std/exitprocs
+  addExitProc(proc() {.noconv.} =
+    var
+      task: string
+      printTaskList: bool
+    for kind, key, val in getopt():
+      case kind
+      of cmdLongOption, cmdShortOption:
+        case key.tolower
+        of "tasks", "t":
+          printTaskList = true
+        else:
+          echo "Unknown option: ", key, ": ", val
+      of cmdArgument:
+        task = key
+      else: nil
+    if printTaskList or task.isNil or not(tasks.hasKey(task)):
+      echo "Available tasks:"
+      for name, task in pairs(tasks):
+        echo name, " - ", task.desc
+      quit 0
+    tasks[task].action())
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim
new file mode 100644
index 000000000..5490211de
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim
@@ -0,0 +1,23 @@
+import nake
+nakeImports
+
+task "install", "compile and install nake binary":
+  if shell("nim", "c", "nake") == 0:
+    let path = getEnv("PATH").split(PathSep)
+    for index, dir in pairs(path):
+      echo "  ", index, ". ", dir
+    echo "Where to install nake binary? (quit with ^C or quit or exit)"
+    let ans = stdin.readLine().toLowerAscii
+    var index = 0
+    case ans
+    of "q", "quit", "x", "exit":
+      quit 0
+    else:
+      index = parseInt(ans)
+    if index > path.len or index < 0:
+      echo "Invalid index."
+      quit 1
+    moveFile "nake", path[index]/"nake"
+    echo "Great success!"
+
+
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/README.md b/tests/manyloc/keineschweine/dependencies/sfml/README.md
new file mode 100644
index 000000000..bd9b3d0e7
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/README.md
@@ -0,0 +1,13 @@
+sfml-nimrod
+===========
+
+Nimrod binding of SFML 2.0
+
+This is only tested for Linux at the moment
+
+### What is needed for Windows / OS X?
+
+* The library names need filling in
+* TWindowHandle is handled differently on those platforms
+
+I believe that is it
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
new file mode 100644
index 000000000..0060bf12b
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
@@ -0,0 +1,1121 @@
+import
+  strutils, math
+when defined(linux):
+  const
+    LibG = "libcsfml-graphics.so.2.0"
+    LibS = "libcsfml-system.so.2.0"
+    LibW = "libcsfml-window.so.2.0"
+else:
+  # We only compile for testing here, so it doesn't matter it's not supported
+  const
+    LibG = "libcsfml-graphics.so.2.0"
+    LibS = "libcsfml-system.so.2.0"
+    LibW = "libcsfml-window.so.2.0"
+  #{.error: "Platform unsupported".}
+
+{.pragma: pf, pure, final.}
+type
+  PClock* = ptr TClock
+  TClock* {.pf.} = object
+  TTime* {.pf.} = object
+    microseconds*: int64
+  TVector2i* {.pf.} = object
+    x*, y*: cint
+  TVector2f* {.pf.} = object
+    x*, y*: cfloat
+  TVector3f* {.pf.} = object
+    x*, y*, z*: cfloat
+
+  PInputStream* = ptr TInputStream
+  TInputStream* {.pf.} = object
+    read*: TInputStreamReadFunc
+    seek*: TInputStreamSeekFunc
+    tell*: TInputStreamTellFunc
+    getSize*: TInputStreamGetSizeFunc
+    userData*: pointer
+  TInputStreamReadFunc* = proc (data: pointer, size: int64, userData: pointer): int64{.
+    cdecl.}
+  TInputStreamSeekFunc* = proc (position: int16, userData: pointer): int64{.
+    cdecl.}
+  TInputStreamTellFunc* = proc (userData: pointer): int64 {.cdecl.}
+  TInputStreamGetSizeFunc* = proc (userData: pointer): int64 {.cdecl.}
+  PWindow* = ptr TWindow
+  TWindow* {.pf.} = object
+  PContextSettings* = ptr TContextSettings
+  TContextSettings*{.pf.} = object
+    depthBits: cint
+    stencilBits: cint
+    antialiasingLevel: cint
+    majorVersion: cint
+    minorVersion: cint
+  TVideoMode* {.pf.} = object
+    width*: cint
+    height*: cint
+    bitsPerPixel*: cint
+  TEventType*{.size: sizeof(cint).} = enum
+    EvtClosed, EvtResized, EvtLostFocus, EvtGainedFocus,
+    EvtTextEntered, EvtKeyPressed, EvtKeyReleased, EvtMouseWheelMoved,
+    EvtMouseButtonPressed, EvtMouseButtonReleased, EvtMouseMoved,
+    EvtMouseEntered, EvtMouseLeft, EvtJoystickButtonPressed,
+    EvtJoystickButtonReleased, EvtJoystickMoved, EvtJoystickConnected,
+    EvtJoystickDisconnected
+  TKeyEvent*{.pf.} = object
+    code*: TKeyCode
+    alt*    : bool
+    control*: bool
+    shift*  : bool
+    system* : bool
+  TJoystickConnectEvent*{.pf.} = object
+    joystickId*: cint
+  TJoystickButtonEvent*{.pf.} = object
+    joystickId*: cint
+    button*: cint
+  TJoystickMoveEvent*{.pf.} = object
+    joystickId*: cint
+    axis*: TJoystickAxis
+    position*: cfloat
+  TMouseWheelEvent*{.pf.} = object
+    delta*: cint
+    x*: cint
+    y*: cint
+  TMouseButtonEvent*{.pf.} = object
+    button*: TMouseButton
+    x*: cint
+    y*: cint
+  TMouseMoveEvent*{.pf.} = object
+    x*: cint
+    y*: cint
+  TTextEvent*{.pf.} = object
+    unicode*: cint
+  PEvent* = ptr TEvent
+  TEvent*{.pf.} = object
+    case kind*: TEventType
+    of EvtKeyPressed, EvtKeyReleased:
+      key*: TKeyEvent
+    of EvtMouseButtonPressed, EvtMouseButtonReleased:
+      mouseButton*: TMouseButtonEvent
+    of EvtTextEntered:
+      text*: TTextEvent
+    of EvtJoystickConnected, EvtJoystickDisconnected:
+      joystickConnect*: TJoystickConnectEvent
+    of EvtJoystickMoved:
+      joystickMove*: TJoystickMoveEvent
+    of EvtJoystickButtonPressed, EvtJoystickButtonReleased:
+      joystickButton*: TJoystickButtonEvent
+    of EvtResized:
+      size*: TSizeEvent
+    of EvtMouseMoved, EvtMouseEntered, EvtMouseLeft:
+      mouseMove*: TMouseMoveEvent
+    of EvtMouseWheelMoved:
+      mouseWheel*: TMouseWheelEvent
+    else: nil
+  TJoystickAxis*{.size: sizeof(cint).} = enum
+    JoystickX, JoystickY, JoystickZ, JoystickR,
+    JoystickU, JoystickV, JoystickPovX, JoystickPovY
+  TSizeEvent*{.pf.} = object
+    width*: cint
+    height*: cint
+  TMouseButton*{.size: sizeof(cint).} = enum
+    MouseLeft, MouseRight, MouseMiddle,
+    MouseXButton1, MouseXButton2, MouseButtonCount
+  TKeyCode*{.size: sizeof(cint).} = enum
+    KeyUnknown = - 1, KeyA, KeyB, KeyC, KeyD, KeyE,
+    KeyF, KeyG, KeyH, KeyI, KeyJ, KeyK, KeyL, KeyM,                 #/< The M key
+    KeyN, KeyO, KeyP, KeyQ, KeyR, KeyS, KeyT, KeyU,                 #/< The U key
+    KeyV, KeyW, KeyX, KeyY, KeyZ, KeyNum0, KeyNum1,              #/< The 1 key
+    KeyNum2, KeyNum3, KeyNum4, KeyNum5, KeyNum6,              #/< The 6 key
+    KeyNum7, KeyNum8, KeyNum9, KeyEscape, KeyLControl,          #/< The left Control key
+    KeyLShift, KeyLAlt, KeyLSystem, KeyRControl,          #/< The right Control key
+    KeyRShift, KeyRAlt, KeyRSystem, KeyMenu,              #/< The Menu key
+    KeyLBracket, KeyRBracket, KeySemiColon, KeyComma,             #/< The , key
+    KeyPeriod, KeyQuote, KeySlash, KeyBackSlash,         #/< The \ key
+    KeyTilde, KeyEqual, KeyDash, KeySpace, KeyReturn,            #/< The Return key
+    KeyBack, KeyTab, KeyPageUp, KeyPageDown, KeyEnd,               #/< The End key
+    KeyHome, KeyInsert, KeyDelete, KeyAdd, KeySubtract,          #/< -
+    KeyMultiply, KeyDivide, KeyLeft, KeyRight, KeyUp,                #/< Up arrow
+    KeyDown, KeyNumpad0, KeyNumpad1, KeyNumpad2,           #/< The numpad 2 key
+    KeyNumpad3,           #/< The numpad 3 key
+    KeyNumpad4,           #/< The numpad 4 key
+    KeyNumpad5,           #/< The numpad 5 key
+    KeyNumpad6,           #/< The numpad 6 key
+    KeyNumpad7,           #/< The numpad 7 key
+    KeyNumpad8,           #/< The numpad 8 key
+    KeyNumpad9,           #/< The numpad 9 key
+    KeyF1,                #/< The F1 key
+    KeyF2,                #/< The F2 key
+    KeyF3,                #/< The F3 key
+    KeyF4,                #/< The F4 key
+    KeyF5,                #/< The F5 key
+    KeyF6,                #/< The F6 key
+    KeyF7,                #/< The F7 key
+    KeyF8,                #/< The F8 key
+    KeyF9,                #/< The F8 key
+    KeyF10,               #/< The F10 key
+    KeyF11,               #/< The F11 key
+    KeyF12,               #/< The F12 key
+    KeyF13,               #/< The F13 key
+    KeyF14,               #/< The F14 key
+    KeyF15,               #/< The F15 key
+    KeyPause,             #/< The Pause key
+    KeyCount              #/< Keep last -- the total number of keyboard keys
+
+type TWindowHandle* = clong
+
+#elif defined(mac):
+#  type TWindowHandle* = pointer ##typedef void* sfWindowHandle; <- whatever the hell that is
+#elif defined(windows):
+#  type TWindowHandle* = HWND__ ? windows is crazy. ##struct HWND__; typedef struct HWND__* sfWindowHandle;
+const
+  sfNone*         = 0
+  sfTitlebar*     = 1 shl 0
+  sfResize*       = 1 shl 1
+  sfClose*        = 1 shl 2
+  sfFullscreen*   = 1 shl 3
+  sfDefaultStyle* = sfTitlebar or sfResize or sfClose
+type
+  PRenderWindow* = ptr TRenderWindow
+  TRenderWindow* {.pf.} = object
+
+  PFont* = ptr TFont
+  TFont* {.pf.} = object
+  PImage* = ptr TImage
+  TImage* {.pf.} = object
+  PShader* = ptr TShader
+  TShader* {.pf.} = object
+  PSprite* = ptr TSprite
+  TSprite* {.pf.} = object
+  PText* = ptr TText
+  TText* {.pf.} = object
+  PTexture* = ptr TTexture
+  TTexture* {.pf.} = object
+  PVertexArray* = ptr TVertexArray
+  TVertexArray* {.pf.} = object
+  PView* = ptr TView
+  TView* {.pf.} = object
+  PRenderTexture* = ptr TRenderTexture
+  TRenderTexture* {.pf.} = object
+
+  PShape* = ptr TShape
+  TShape* {.pf.} = object
+  PCircleShape* = ptr TCircleShape
+  TCircleShape* {.pf.} = object
+  PRectangleShape* = ptr TRectangleShape
+  TRectangleShape* {.pf.} = object
+  PConvexShape* = ptr TConvexShape
+  TConvexShape* {.pf.} = object
+
+  TTextStyle*{.size: sizeof(cint).} = enum
+    TextRegular = 0, TextBold = 1 shl 0, TextItalic = 1 shl 1,
+    TextUnderlined = 1 shl 2
+
+  TBlendMode*{.size: sizeof(cint).} = enum
+      BlendAlpha, BlendAdd, BlendMultiply, BlendNone
+  PRenderStates* = ptr TRenderStates
+  TRenderStates* {.pf.} = object
+    blendMode*: TBlendMode
+    transform*: TTransform
+    texture*: PTexture
+    shader*: PShader
+
+  PTransform* = ptr TTransform
+  TTransform* {.pf.} = object
+    matrix*: array[0..8, cfloat]
+  TColor* {.pf.} = object
+    r*: uint8
+    g*: uint8
+    b*: uint8
+    a*: uint8
+  PFloatRect* = ptr TFloatRect
+  TFloatRect*{.pf.} = object
+    left*: cfloat
+    top*: cfloat
+    width*: cfloat
+    height*: cfloat
+  PIntRect* = ptr TIntRect
+  TIntRect*{.pf.} = object
+    left*: cint
+    top*: cint
+    width*: cint
+    height*: cint
+  TGlyph* {.pf.} = object
+    advance*: cint
+    bounds*: TIntRect
+    textureRect*: TIntRect
+  PVertex* = ptr TVertex
+  TVertex* {.pf.} = object
+    position*: TVector2f
+    color*: TColor
+    texCoords*: TVector2f
+  TPrimitiveType*{.size: sizeof(cint).} = enum
+    Points,               #/< List of individual points
+    Lines,                #/< List of individual lines
+    LinesStrip,           #/< List of connected lines, a point uses the previous point to form a line
+    Triangles,            #/< List of individual triangles
+    TrianglesStrip,       #/< List of connected triangles, a point uses the two previous points to form a triangle
+    TrianglesFan,         #/< List of connected triangles, a point uses the common center and the previous point to form a triangle
+    Quads
+
+
+proc newWindow*(mode: TVideoMode, title: cstring, style: uint32, settings: PContextSettings = nil): PWindow {.
+  cdecl, importc: "sfWindow_create", dynlib: LibW.}
+
+proc close*(window: PWindow) {.
+  cdecl, importc: "sfWindow_close", dynlib: LibW.}
+proc isOpen*(window: PWindow): bool {.cdecl, importc: "sfWindow_isOpen", dynlib: LibW.}
+
+proc pollEvent*(window: PWindow, event: PEvent): bool {.
+  cdecl, importc: "sfWindow_pollEvent", dynlib: LibW.}
+proc waitEvent*(window: PWindow, event: PEvent): bool {.
+  cdecl, importc: "sfWindow_waitEvent", dynlib: LibW.}
+
+proc getDesktopMode*(): TVideoMode {.
+  cdecl, importc: "sfVideoMode_getDesktopMode", dynlib: LibW.}
+proc isKeyPressed*(key: TKeyCode): bool {.
+  cdecl, importc: "sfKeyboard_isKeyPressed", dynlib: LibW.}
+
+proc mouseIsButtonPressed*(button: TMouseButton): bool {.
+  cdecl, importc: "sfMouse_isButtonPressed", dynlib: LibW.}
+proc mouseGetPosition*(relativeTo: PWindow): TVector2i {.
+  cdecl, importc: "sfMouse_getPosition", dynlib: LibW.}
+proc mouseSetPosition*(position: TVector2i, relativeTo: PWindow) {.
+  cdecl, importc: "sfMouse_setPosition", dynlib: LibW.}
+
+proc joystickIsConnected*(joystick: cint): bool {.
+  cdecl, importc: "sfJoystick_isConnected", dynlib: LibW.}
+proc joystickGetButtonCount*(joystick: cint): cint {.
+  cdecl, importc: "sfJoystick_getButtonCount", dynlib: LibW.}
+proc joystickHasAxis*(joystick: cint, axis: TJoystickAxis): bool {.
+  cdecl, importc: "sfJoystick_hasAxis", dynlib: LibW.}
+proc joystickIsButtonPressed*(joystick: cint, button: cint): bool {.
+  cdecl, importc: "sfJoystick_isButtonPressed", dynlib: LibW.}
+proc joystickGetAxisPosition*(joystick: cint, axis: TJoystickAxis): float {.
+  cdecl, importc: "sfJoystick_getAxisPosition", dynlib: LibW.}
+proc joystickUpdate*(): void {.
+  cdecl, importc: "sfJoystick_update", dynlib: LibW.}
+
+
+proc newRenderWindow*(handle: TWindowHandle, settings: PContextSettings = nil): PRenderWindow{.
+  cdecl, importc: "sfRenderWindow_createFromHandle", dynlib: LibG.}
+proc newRenderWindow*(mode: TVideoMode, title: cstring, style: int32, settings: PContextSettings = nil): PRenderWindow {.
+  cdecl, importc: "sfRenderWindow_create", dynlib: LibG.}
+
+proc destroy*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_destroy", dynlib: LibG.}
+proc close*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_close", dynlib: LibG.}
+proc isOpen*(window: PRenderWindow): bool {.
+  cdecl, importc: "sfRenderWindow_isOpen", dynlib: LibG.}
+
+#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfuint8* pixels);
+#proc setIcon*(window: PRenderWindow, width, height: cint, pixels: seq[uint8]) {.
+#  cdecl, importc: "sfRenderWindow_setIcon", dynlib: LibG.}
+
+proc getSettings*(window: PRenderWindow): TContextSettings {.
+  cdecl, importc: "sfRenderWindow_getSettings", dynlib: LibG.}
+
+proc pollEvent*(window: PRenderWindow, event: PEvent): bool {.
+  cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.}
+proc pollEvent*(window: PRenderWindow; event: var TEvent): bool {.
+  cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.}
+proc waitEvent*(window: PRenderWindow, event: PEvent): bool {.
+  cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.}
+proc waitEvent*(window: PRenderWindow, event: var TEvent): bool {.
+  cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.}
+proc getPosition*(window: PRenderWindow): TVector2i {.
+  cdecl, importc: "sfRenderWindow_getPosition", dynlib: LibG.}
+proc setPosition*(window: PRenderWindow, position: TVector2i) {.
+  cdecl, importc: "sfRenderWindow_setPosition", dynlib: LibG.}
+proc getSize*(window: PRenderWindow): TVector2i {.
+  cdecl, importc: "sfRenderWindow_getSize", dynlib: LibG.}
+proc setSize*(window: PRenderWindow, size: TVector2i): void {.
+  cdecl, importc: "sfRenderWindow_setSize", dynlib: LibG.}
+proc setTitle*(window: PRenderWindow, title: cstring): void {.
+  cdecl, importc: "sfRenderWindow_setTitle", dynlib: LibG.}
+
+proc setVisible*(window: PRenderWindow, visible: bool) {.
+  cdecl, importc: "sfRenderWindow_setVisible", dynlib: LibG.}
+proc setMouseCursorVisible*(window: PRenderWindow, show: bool) {.
+  cdecl, importc: "sfRenderWindow_setMouseCursorVisible", dynlib: LibG.}
+proc setVerticalSyncEnabled*(window: PRenderWindow, enabled: bool) {.
+  cdecl, importc: "sfRenderWindow_setVerticalSyncEnabled", dynlib: LibG.}
+proc setKeyRepeatEnabled*(window: PRenderWindow, enabled: bool) {.
+  cdecl, importc: "sfRenderWindow_setKeyRepeatEnabled", dynlib: LibG.}
+proc setActive*(window: PRenderWindow, active: bool): bool {.
+  cdecl, importc: "sfRenderWindow_setActive", dynlib: LibG.}
+proc display*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_display", dynlib: LibG.}
+proc setFramerateLimit*(window: PRenderWindow, limit: uint) {.
+  cdecl, importc: "sfRenderWindow_setFramerateLimit", dynlib: LibG.}
+proc setJoystickThreshold*(window: PRenderWindow, threshold: float) {.
+  cdecl, importc: "sfRenderWindow_setJoystickThreshold", dynlib: LibG.}
+proc getSystemHandle*(window: PRenderWindow): TWindowHandle {.
+  cdecl, importc: "sfRenderWindow_getSystemHandle", dynlib: LibG.}
+
+proc clear*(window: PRenderWindow, color: TColor) {.
+  cdecl, importc: "sfRenderWindow_clear", dynlib: LibG.}
+
+proc setView*(window: PRenderWindow, view: PView) {.
+  cdecl, importc: "sfRenderWindow_setView", dynlib: LibG.}
+proc getView*(window: PRenderWindow): PView {.
+  cdecl, importc: "sfRenderWindow_getView", dynlib: LibG.}
+proc getDefaultView*(window: PRenderWindow): PView {.
+  cdecl, importc: "sfRenderWindow_getDefaultView", dynlib: LibG.}
+proc getViewport*(window: PRenderWindow, view: PView): TIntRect {.
+  cdecl, importc: "sfRenderWindow_getViewport", dynlib: LibG.}
+
+proc convertCoords*(window: PRenderWindow, point: TVector2i, targetView: PView): TVector2f {.
+  cdecl, importc: "sfRenderWindow_convertCoords", dynlib: LibG.}
+
+proc draw*(window: PRenderWindow, sprite: PSprite, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawSprite", dynlib: LibG.}
+proc draw*(window: PRenderWindow, text: PText, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawText", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PCircleShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawCircleShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PRectangleShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawRectangleShape", dynlib: LibG.}
+
+proc draw*(window: PRenderWindow, shape: PConvexShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawConvexShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PVertexArray, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawVertexArray", dynlib: LibG.}
+proc draw*(window: PRenderWindow, vertices: PVertex, vertexCount: cint,
+           vertexType: TPrimitiveType, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawPrimitives", dynlib: LibG.}
+
+proc pushGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_pushGLStates", dynlib: LibG.}
+proc popGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_popGLStates", dynlib: LibG.}
+proc resetGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_resetGLStates", dynlib: LibG.}
+proc capture*(window: PRenderWindow): PImage {.
+  cdecl, importc: "sfRenderWindow_capture", dynlib: LibG.}
+
+#Construct a new render texture
+proc newRenderTexture*(width, height: cint; depthBuffer: bool): PRenderTexture {.
+  cdecl, importc: "sfRenderTexture_create", dynlib: LibG.}
+#Destroy an existing render texture
+proc destroy*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_destroy", dynlib: LibG.}
+#Get the size of the rendering region of a render texture
+proc getSize*(renderTexture: PRenderTexture): TVector2i {.
+  cdecl, importc: "sfRenderTexture_getSize", dynlib: LibG.}
+#Activate or deactivate a render texture as the current target for rendering
+proc setActive*(renderTexture: PRenderTexture; active: bool): bool{.
+  cdecl, importc: "sfRenderTexture_setActive", dynlib: LibG.}
+#Update the contents of the target texture
+proc display*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_display", dynlib: LibG.}
+#Clear the rendertexture with the given color
+proc clear*(renderTexture: PRenderTexture; color: TColor){.
+  cdecl, importc: "sfRenderTexture_clear", dynlib: LibG.}
+#Change the current active view of a render texture
+proc setView*(renderTexture: PRenderTexture; view: PView){.
+  cdecl, importc: "sfRenderTexture_setView", dynlib: LibG.}
+#Get the current active view of a render texture
+proc getView*(renderTexture: PRenderTexture): PView{.
+  cdecl, importc: "sfRenderTexture_getView", dynlib: LibG.}
+#Get the default view of a render texture
+proc getDefaultView*(renderTexture: PRenderTexture): PView{.
+  cdecl, importc: "sfRenderTexture_getDefaultView", dynlib: LibG.}
+#Get the viewport of a view applied to this target
+proc getViewport*(renderTexture: PRenderTexture; view: PView): TIntRect{.
+  cdecl, importc: "sfRenderTexture_getViewport", dynlib: LibG.}
+#Convert a point in texture coordinates into view coordinates
+proc convertCoords*(renderTexture: PRenderTexture; point: TVector2i; targetView: PView): TVector2f{.
+  cdecl, importc: "sfRenderTexture_convertCoords", dynlib: LibG.}
+#Draw a drawable object to the render-target
+proc draw*(renderTexture: PRenderTexture; sprite: PSprite; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawSprite", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; text: PText; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawText", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PShape; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PCircleShape;
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawCircleShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PConvexShape;
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawConvexShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PRectangleShape;
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawRectangleShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; va: PVertexArray;
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawVertexArray", dynlib: LibG.}
+#Draw primitives defined by an array of vertices to a render texture
+proc draw*(renderTexture: PRenderTexture; vertices: PVertex; vertexCount: cint;
+            primitiveType: TPrimitiveType; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawPrimitives", dynlib: LibG.}
+#Save the current OpenGL render states and matrices
+#/
+#/ This function can be used when you mix SFML drawing
+#/ and direct OpenGL rendering. Combined with popGLStates,
+#/ it ensures that:
+#/ * SFML's internal states are not messed up by your OpenGL code
+#/ * your OpenGL states are not modified by a call to a SFML function
+#/
+#/ Note that this function is quite expensive: it saves all the
+#/ possible OpenGL states and matrices, even the ones you
+#/ don't care about. Therefore it should be used wisely.
+#/ It is provided for convenience, but the best results will
+#/ be achieved if you handle OpenGL states yourself (because
+#/ you know which states have really changed, and need to be
+#/ saved and restored). Take a look at the resetGLStates
+#/ function if you do so.
+proc pushGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_pushGLStates", dynlib: LibG.}
+#Restore the previously saved OpenGL render states and matrices
+#/
+#/ See the description of pushGLStates to get a detailed
+#/ description of these functions.
+proc popGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_popGLStates", dynlib: LibG.}
+#Reset the internal OpenGL states so that the target is ready for drawing
+#/
+#/ This function can be used when you mix SFML drawing
+#/ and direct OpenGL rendering, if you choose not to use
+#/ pushGLStates/popGLStates. It makes sure that all OpenGL
+#/ states needed by SFML are set, so that subsequent sfRenderTexture_draw*()
+#/ calls will work as expected.
+proc resetGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_resetGLStates", dynlib: LibG.}
+#Get the target texture of a render texture
+proc getTexture*(renderTexture: PRenderTexture): PTexture{.
+  cdecl, importc: "sfRenderTexture_getTexture", dynlib: LibG.}
+#Enable or disable the smooth filter on a render texture
+proc setSmooth*(renderTexture: PRenderTexture; smooth: bool){.
+  cdecl, importc: "sfRenderTexture_setSmooth", dynlib: LibG.}
+#Tell whether the smooth filter is enabled or not for a render texture
+proc isSmooth*(renderTexture: PRenderTexture): bool {.
+  cdecl, importc: "sfRenderTexture_isSmooth", dynlib: LibG.}
+
+proc intRect*(left, top, width, height: cint): TIntRect =
+  result.left   = left
+  result.top    = top
+  result.width  = width
+  result.height = height
+proc floatRect*(left, top, width, height: cfloat): TFloatRect =
+  result.left   = left
+  result.top    = top
+  result.width  = width
+  result.height = height
+proc contains*(rect: PFloatRect, x, y: cfloat): bool {.
+  cdecl, importc: "sfFloatRect_contains", dynlib: LibG.}
+proc contains*(rect: PIntRect, x: cint, y: cint): bool{.cdecl,
+  importc: "sfIntRect_contains", dynlib: LibG.}
+proc intersects*(rect1, rect2, intersection: PFloatRect): bool {.
+  cdecl, importc: "sfFloatRect_intersects", dynlib: LibG.}
+proc intersects*(rect1, rect2, intersection: PIntRect): bool {.
+  cdecl, importc: "sfIntRect_intersects", dynlib: LibG.}
+
+proc newFont*(filename: cstring): PFont {.
+  cdecl, importc: "sfFont_createFromFile", dynlib: LibG.}
+proc newFont*(data: pointer, sizeInBytes: cint): PFont {.
+  cdecl, importc: "sfFont_createFromMemory", dynlib: LibG.}
+proc newFont*(stream: PInputStream): PFont {.
+  cdecl, importc: "sfFont_createFromStream", dynlib: LibG.}
+proc copy*(font: PFont): PFont {.
+  cdecl, importc: "sfFont_copy", dynlib: LibG.}
+proc destroy*(font: PFont) {.
+  cdecl, importc: "sfFont_destroy", dynlib: LibG.}
+proc getGlyph*(font: PFont, codePoint: uint32, characterSize: cint, bold: bool): TGlyph{.
+  cdecl, importc: "sfFont_getGlyph", dynlib: LibG.}
+proc getKerning*(font: PFont, first: uint32, second: uint32, characterSize: cint): cint {.
+  cdecl, importc: "sfFont_getKerning", dynlib: LibG.}
+proc getLineSpacing*(font: PFont, characterSize: cint): cint {.
+  cdecl, importc: "sfFont_getLineSpacing", dynlib: LibG.}
+proc getTexture*(font: PFont, characterSize: cint): PTexture {.
+  cdecl, importc: "sfFont_getTexture", dynlib: LibG.}
+#getDefaultFont() has been removed from CSFML
+proc getDefaultFont*(): PFont {.
+  error, cdecl, importc: "sfFont_getDefaultFont", dynlib: LibG.}
+
+proc newCircleShape*(): PCircleShape {.
+  cdecl, importc: "sfCircleShape_create", dynlib: LibG.}
+proc copy*(shape: PCircleShape): PCircleShape {.
+  cdecl, importc: "sfCircleShape_copy", dynlib: LibG.}
+proc destroy*(shape: PCircleShape) {.
+  cdecl, importc: "sfCircleShape_destroy", dynlib: LibG.}
+proc setPosition*(shape: PCircleShape, position: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setPosition", dynlib: LibG.}
+proc setRotation*(shape: PCircleShape, angle: cfloat) {.
+  cdecl, importc: "sfCircleShape_setRotation", dynlib: LibG.}
+proc setScale*(shape: PCircleShape, scale: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setScale", dynlib: LibG.}
+proc setOrigin*(shape: PCircleShape, origin: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setOrigin", dynlib: LibG.}
+proc getPosition*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getPosition", dynlib: LibG.}
+proc getRotation*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getRotation", dynlib: LibG.}
+proc getScale*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getScale", dynlib: LibG.}
+proc getOrigin*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getOrigin", dynlib: LibG.}
+proc move*(shape: PCircleShape, offset: TVector2f) {.
+  cdecl, importc: "sfCircleShape_move", dynlib: LibG.}
+proc rotate*(shape: PCircleShape, angle: cfloat){.
+  cdecl, importc: "sfCircleShape_rotate", dynlib: LibG.}
+proc scale*(shape: PCircleShape, factors: TVector2f) {.
+  cdecl, importc: "sfCircleShape_scale", dynlib: LibG.}
+proc getTransform*(shape: PCircleShape): TTransform {.
+  cdecl, importc: "sfCircleShape_getTransform", dynlib: LibG.}
+proc getInverseTransform*(shape: PCircleShape): TTransform {.
+  cdecl, importc: "sfCircleShape_getInverseTransform", dynlib: LibG.}
+proc setTexture*(shape: PCircleShape, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfCircleShape_setTexture", dynlib: LibG.}
+proc setTextureRect*(shape: PCircleShape, rect: TIntRect) {.
+  cdecl, importc: "sfCircleShape_setTextureRect", dynlib: LibG.}
+proc setFillColor*(shape: PCircleShape, color: TColor) {.
+  cdecl, importc: "sfCircleShape_setFillColor", dynlib: LibG.}
+proc setOutlineColor*(shape: PCircleShape, color: TColor) {.
+  cdecl, importc: "sfCircleShape_setOutlineColor", dynlib: LibG.}
+proc setOutlineThickness*(shape: PCircleShape, thickness: cfloat) {.
+  cdecl, importc: "sfCircleShape_setOutlineThickness", dynlib: LibG.}
+proc getTexture*(shape: PCircleShape): PTexture {.
+  cdecl, importc: "sfCircleShape_getTexture", dynlib: LibG.}
+proc getTextureRect*(shape: PCircleShape): TIntRect {.
+  cdecl, importc: "sfCircleShape_getTextureRect", dynlib: LibG.}
+proc getFillColor*(shape: PCircleShape): TColor {.
+  cdecl, importc: "sfCircleShape_getFillColor", dynlib: LibG.}
+proc getOutlineColor*(shape: PCircleShape): TColor {.
+  cdecl, importc: "sfCircleShape_getOutlineColor", dynlib: LibG.}
+proc getOutlineThickness*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getOutlineThickness", dynlib: LibG.}
+proc getPointCount*(shape: PCircleShape): cint {.
+  cdecl, importc: "sfCircleShape_getPointCount", dynlib: LibG.}
+proc getPoint*(shape: PCircleShape, index: cint): TVector2f {.
+  cdecl, importc: "sfCircleShape_getPoint", dynlib: LibG.}
+proc setRadius*(shape: PCircleShape, radius: cfloat) {.
+  cdecl, importc: "sfCircleShape_setRadius", dynlib: LibG.}
+proc getRadius*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getRadius", dynlib: LibG.}
+proc setPointCount*(shape: PCircleShape, count: cint) {.
+  cdecl, importc: "sfCircleShape_setPointCount", dynlib: LibG.}
+proc getLocalBounds*(shape: PCircleShape): TFloatRect {.
+  cdecl, importc: "sfCircleShape_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(shape: PCircleShape): TFloatRect {.
+  cdecl, importc: "sfCircleShape_getGlobalBounds", dynlib: LibG.}
+
+proc newRectangleShape*(): PRectangleShape {.
+  cdecl, importc: "sfRectangleShape_create", dynlib: LibG.}
+proc copy*(shape: PRectangleShape): PRectangleShape {.
+  cdecl, importc: "sfRectangleShape_copy", dynlib: LibG.}
+proc destroy*(shape: PRectangleShape){.
+  cdecl, importc: "sfRectangleShape_destroy", dynlib: LibG.}
+proc setPosition*(shape: PRectangleShape, position: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setPosition", dynlib: LibG.}
+proc setRotation*(shape: PRectangleShape, angle: cfloat) {.
+  cdecl, importc: "sfRectangleShape_setRotation", dynlib: LibG.}
+proc setScale*(shape: PRectangleShape, scale: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setScale", dynlib: LibG.}
+proc setOrigin*(shape: PRectangleShape, origin: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setOrigin", dynlib: LibG.}
+proc getPosition*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getPosition", dynlib: LibG.}
+proc getRotation*(shape: PRectangleShape): cfloat {.
+  cdecl, importc: "sfRectangleShape_getRotation", dynlib: LibG.}
+proc getScale*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getScale", dynlib: LibG.}
+proc getOrigin*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getOrigin", dynlib: LibG.}
+proc move*(shape: PRectangleShape, offset: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_move", dynlib: LibG.}
+proc rotate*(shape: PRectangleShape, angle: cfloat) {.
+  cdecl, importc: "sfRectangleShape_rotate", dynlib: LibG.}
+proc scale*(shape: PRectangleShape, factors: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_scale", dynlib: LibG.}
+proc getTransform*(shape: PRectangleShape): TTransform {.
+  cdecl, importc: "sfRectangleShape_getTransform", dynlib: LibG.}
+proc getInverseTransform*(shape: PRectangleShape): TTransform {.
+  cdecl, importc: "sfRectangleShape_getInverseTransform", dynlib: LibG.}
+proc setTexture*(shape: PRectangleShape, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfRectangleShape_setTexture", dynlib: LibG.}
+proc setTextureRect*(shape: PRectangleShape, rect: TIntRect) {.
+  cdecl, importc: "sfRectangleShape_setTextureRect", dynlib: LibG.}
+proc setFillColor*(shape: PRectangleShape, color: TColor) {.
+  cdecl, importc: "sfRectangleShape_setFillColor", dynlib: LibG.}
+proc setOutlineColor*(shape: PRectangleShape, color: TColor) {.
+  cdecl, importc: "sfRectangleShape_setOutlineColor", dynlib: LibG.}
+proc setOutlineThickness*(shape: PRectangleShape, thickness: cfloat) {.
+  cdecl, importc: "sfRectangleShape_setOutlineThickness", dynlib: LibG.}
+proc getTexture*(shape: PRectangleShape): PTexture {.
+  cdecl, importc: "sfRectangleShape_getTexture", dynlib: LibG.}
+proc getTextureRect*(shape: PRectangleShape): TIntRect {.
+  cdecl, importc: "sfRectangleShape_getTextureRect", dynlib: LibG.}
+proc getFillColor*(shape: PRectangleShape): TColor {.
+  cdecl, importc: "sfRectangleShape_getFillColor", dynlib: LibG.}
+proc getOutlineColor*(shape: PRectangleShape): TColor {.
+  cdecl, importc: "sfRectangleShape_getOutlineColor", dynlib: LibG.}
+proc getOutlineThickness*(shape: PRectangleShape): cfloat {.
+  cdecl, importc: "sfRectangleShape_getOutlineThickness", dynlib: LibG.}
+proc getPointCount*(shape: PRectangleShape): cint {.
+  cdecl, importc: "sfRectangleShape_getPointCount", dynlib: LibG.}
+proc getPoint*(shape: PRectangleShape, index: cint): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getPoint", dynlib: LibG.}
+proc setSize*(shape: PRectangleShape, size: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setSize", dynlib: LibG.}
+proc getSize*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getSize", dynlib: LibG.}
+proc getLocalBounds*(shape: PRectangleShape): TFloatRect {.
+  cdecl, importc: "sfRectangleShape_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(shape: PRectangleShape): TFloatRect {.
+  cdecl, importc: "sfRectangleShape_getGlobalBounds", dynlib: LibG.}
+
+
+proc newView*(): PView {.
+  cdecl, importc: "sfView_create", dynlib: LibG.}
+proc viewFromRect*(rectangle: TFloatRect): PView{.
+  cdecl, importc: "sfView_createFromRect", dynlib: LibG.}
+proc copy*(view: PView): PView {.
+  cdecl, importc: "sfView_copy", dynlib: LibG.}
+proc destroy*(view: PView) {.
+  cdecl, importc: "sfView_destroy", dynlib: LibG.}
+proc setCenter*(view: PView, center: TVector2f) {.
+  cdecl, importc: "sfView_setCenter", dynlib: LibG.}
+proc setSize*(view: PView, size: TVector2f) {.
+  cdecl, importc: "sfView_setSize", dynlib: LibG.}
+proc setRotation*(view: PView, angle: cfloat) {.
+  cdecl, importc: "sfView_setRotation", dynlib: LibG.}
+proc setViewport*(view: PView, viewport: TFloatRect) {.
+  cdecl, importc: "sfView_setViewport", dynlib: LibG.}
+proc reset*(view: PView, rectangle: TFloatRect) {.
+  cdecl, importc: "sfView_reset", dynlib: LibG.}
+proc getCenter*(view: PView): TVector2f {.
+  cdecl, importc: "sfView_getCenter", dynlib: LibG.}
+proc getSize*(view: PView): TVector2f {.
+  cdecl, importc: "sfView_getSize", dynlib: LibG.}
+proc getRotation*(view: PView): cfloat {.
+  cdecl, importc: "sfView_getRotation", dynlib: LibG.}
+proc getViewport*(view: PView): TFloatRect {.
+  cdecl, importc: "sfView_getViewport", dynlib: LibG.}
+proc move*(view: PView, offset: TVector2f) {.
+  cdecl, importc: "sfView_move", dynlib: LibG.}
+proc rotate*(view: PView, angle: cfloat) {.
+  cdecl, importc: "sfView_rotate", dynlib: LibG.}
+proc zoom*(view: PView, factor: cfloat) {.
+  cdecl, importc: "sfView_zoom", dynlib: LibG.}
+
+proc newImage*(width, height: cint): PImage {.
+  cdecl, importc: "sfImage_create", dynlib: LibG.}
+proc newImage*(width, height: cint, color: TColor): PImage {.
+  cdecl, importc: "sfImage_createFromColor", dynlib: LibG.}
+proc newImage*(width, height: cint, pixels: pointer): PImage {. ##same deal as setIcon()
+  cdecl, importc: "sfImage_createFromPixels", dynlib: LibG.}
+proc newImage*(filename: cstring): PImage {.
+  cdecl, importc: "sfImage_createFromFile", dynlib: LibG.}
+proc newImage*(data: pointer, size: cint): PImage {.
+  cdecl, importc: "sfImage_createFromMemory", dynlib: LibG.}
+proc newImage*(stream: PInputStream): PImage {.
+  cdecl, importc: "sfImage_createFromStream", dynlib: LibG.}
+proc copy*(image: PImage): PImage {.
+  cdecl, importc: "sfImage_copy", dynlib: LibG.}
+proc destroy*(image: PImage) {.
+  cdecl, importc: "sfImage_destroy", dynlib: LibG.}
+proc save*(image: PImage, filename: cstring): bool {.
+  cdecl, importc: "sfImage_saveToFile", dynlib: LibG.}
+proc getSize*(image: PImage): TVector2i {.
+  cdecl, importc: "sfImage_getSize", dynlib: LibG.}
+proc createMask*(image: PImage, color: TColor, alpha: cchar) {.
+  cdecl, importc: "sfImage_createMaskFromColor", dynlib: LibG.}
+proc copy*(destination, source: PImage, destX, destY: cint;
+            sourceRect: TIntRect, applyAlpha: bool) {.
+  cdecl, importc: "sfImage_copyImage", dynlib: LibG.}
+proc setPixel*(image: PImage, x, y: cint, color: TColor) {.
+  cdecl, importc: "sfImage_setPixel", dynlib: LibG.}
+proc getPixel*(image: PImage, x, y: cint): TColor {.
+  cdecl, importc: "sfImage_getPixel", dynlib: LibG.}
+proc getPixels*(image: PImage): pointer {.
+  cdecl, importc: "sfImage_getPixelsPtr", dynlib: LibG.}
+proc flipHorizontally*(image: PImage) {.
+  cdecl, importc: "sfImage_flipHorizontally", dynlib: LibG.}
+proc flipVertically*(image: PImage) {.
+  cdecl, importc: "sfImage_flipVertically", dynlib: LibG.}
+
+proc newSprite*(): PSprite {.
+  cdecl, importc: "sfSprite_create", dynlib: LibG.}
+proc copy*(sprite: PSprite): PSprite {.
+  cdecl, importc: "sfSprite_copy", dynlib: LibG.}
+proc destroy*(sprite: PSprite) {.
+  cdecl, importc: "sfSprite_destroy", dynlib: LibG.}
+proc setPosition*(sprite: PSprite, position: TVector2f) {.
+  cdecl, importc: "sfSprite_setPosition", dynlib: LibG.}
+proc setRotation*(sprite: PSprite, angle: cfloat) {.
+  cdecl, importc: "sfSprite_setRotation", dynlib: LibG.}
+proc setScale*(sprite: PSprite, scale: TVector2f) {.
+  cdecl, importc: "sfSprite_setScale", dynlib: LibG.}
+proc setOrigin*(sprite: PSprite, origin: TVector2f) {.
+  cdecl, importc: "sfSprite_setOrigin", dynlib: LibG.}
+proc getPosition*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getPosition", dynlib: LibG.}
+proc getRotation*(sprite: PSprite): cfloat {.
+  cdecl, importc: "sfSprite_getRotation", dynlib: LibG.}
+proc getScale*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getScale", dynlib: LibG.}
+proc getOrigin*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getOrigin", dynlib: LibG.}
+proc move*(sprite: PSprite, offset: TVector2f) {.
+  cdecl, importc: "sfSprite_move", dynlib: LibG.}
+proc rotate*(sprite: PSprite, angle: cfloat) {.
+  cdecl, importc: "sfSprite_rotate", dynlib: LibG.}
+proc scale*(sprite: PSprite, factor: TVector2f) {.
+  cdecl, importc: "sfSprite_scale", dynlib: LibG.}
+proc getTransform*(sprite: PSprite): TTransform {.
+  cdecl, importc: "sfSprite_getTransform", dynlib: LibG.}
+proc getInverseTransform*(sprite: PSprite): TTransform {.
+  cdecl, importc: "sfSprite_getInverseTransform", dynlib: LibG.}
+proc setTexture*(sprite: PSprite, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfSprite_setTexture", dynlib: LibG.}
+proc setTextureRect*(sprite: PSprite, rectangle: TIntRect) {.
+  cdecl, importc: "sfSprite_setTextureRect", dynlib: LibG.}
+proc setColor*(sprite: PSprite, color: TColor) {.
+  cdecl, importc: "sfSprite_setColor", dynlib: LibG.}
+proc getTexture*(sprite: PSprite): TTexture {.
+  cdecl, importc: "sfSprite_getTexture", dynlib: LibG.}
+proc getTextureRect*(sprite: PSprite): TIntRect {.
+  cdecl, importc: "sfSprite_getTextureRect", dynlib: LibG.}
+proc getColor*(sprite: PSprite): TColor {.
+  cdecl, importc: "sfSprite_getColor", dynlib: LibG.}
+proc getLocalBounds*(sprite: PSprite): TFloatRect {.
+  cdecl, importc: "sfSprite_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(sprite: PSprite): TFloatRect {.
+  cdecl, importc: "sfSprite_getGlobalBounds", dynlib: LibG.}
+
+proc newTexture*(width, height: cint): PTexture {.
+  cdecl, importc: "sfTexture_create", dynlib: LibG.}
+proc newTexture*(filename: cstring): PTexture {.
+  cdecl, importc: "sfTexture_createFromFile", dynlib: LibG.}
+proc newTexture*(data: pointer, size: cint, area: PIntRect): PTexture {.
+  cdecl, importc: "sfTexture_createFromMemory", dynlib: LibG.}
+proc newTexture*(stream: PInputStream, area: PIntRect): PTexture {.
+  cdecl, importc: "sfTexture_createFromStream", dynlib: LibG.}
+proc newTexture*(image: PImage, area: PIntRect = nil): PTexture {.
+  cdecl, importc: "sfTexture_createFromImage", dynlib: LibG.}
+proc copy*(texture: PTexture): PTexture {.
+  cdecl, importc: "sfTexture_copy", dynlib: LibG.}
+proc destroy*(texture: PTexture) {.
+  cdecl, importc: "sfTexture_destroy", dynlib: LibG.}
+proc getSize*(texture: PTexture): TVector2i {.
+  cdecl, importc: "sfTexture_getSize", dynlib: LibG.}
+proc copyToImage*(texture: PTexture): PImage {.
+  cdecl, importc: "sfTexture_copyToImage", dynlib: LibG.}
+proc updateFromPixels*(texture: PTexture, pixels: pointer, width, height, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromPixels", dynlib: LibG.}
+proc updateFromImage*(texture: PTexture, image: PImage, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromImage", dynlib: LibG.}
+proc updateFromWindow*(texture: PTexture, window: PWindow, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromWindow", dynlib: LibG.}
+proc updateFromWindow*(texture: PTexture, window: PRenderWindow, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromRenderWindow", dynlib: LibG.}
+proc bindGL*(texture: PTexture) {.
+  cdecl, importc: "sfTexture_bind", dynlib: LibG.}
+proc setSmooth*(texture: PTexture, smooth: bool) {.
+  cdecl, importc: "sfTexture_setSmooth", dynlib: LibG.}
+proc isSmooth*(texture: PTexture): bool {.
+  cdecl, importc: "sfTexture_isSmooth", dynlib: LibG.}
+proc setRepeated*(texture: PTexture, repeated: bool) {.
+  cdecl, importc: "sfTexture_setRepeated", dynlib: LibG.}
+proc isRepeated*(texture: PTexture): bool {.
+  cdecl, importc: "sfTexture_isRepeated", dynlib: LibG.}
+proc textureMaxSize*(): cint {.
+  cdecl, importc: "sfTexture_getMaximumSize", dynlib: LibG.}
+
+proc newVertexArray*(): PVertexArray {.
+  cdecl, importc: "sfVertexArray_create", dynlib: LibG.}
+proc copy*(vertexArray: PVertexArray): PVertexArray {.
+  cdecl, importc: "sfVertexArray_copy", dynlib: LibG.}
+proc destroy*(va: PVertexArray) {.
+  cdecl, importc: "sfVertexArray_destroy", dynlib: LibG.}
+proc getVertexCount*(va: PVertexArray): cint {.
+  cdecl, importc: "sfVertexArray_getVertexCount", dynlib: LibG.}
+proc getVertex*(va: PVertexArray, index: cint): PVertex {.
+  cdecl, importc: "sfVertexArray_getVertex", dynlib: LibG.}
+proc clear*(va: PVertexArray) {.
+  cdecl, importc: "sfVertexArray_clear", dynlib: LibG.}
+proc resize*(va: PVertexArray, size: cint) {.
+  cdecl, importc: "sfVertexArray_resize", dynlib: LibG.}
+proc append*(va: PVertexArray, vertex: TVertex) {.
+  cdecl, importc: "sfVertexArray_append", dynlib: LibG.}
+proc setPrimitiveType*(va: PVertexArray, primitiveType: TPrimitiveType) {.
+  cdecl, importc: "sfVertexArray_setPrimitiveType", dynlib: LibG.}
+proc getPrimitiveType*(va: PVertexArray): TPrimitiveType {.
+  cdecl, importc: "sfVertexArray_getPrimitiveType", dynlib: LibG.}
+proc getBounds*(va: PVertexArray): TFloatRect {.
+  cdecl, importc: "sfVertexArray_getBounds", dynlib: LibG.}
+
+
+proc newText*(): PText {.
+  cdecl, importc: "sfText_create", dynlib: LibG.}
+proc copy*(text: PText): PText {.
+  cdecl, importc: "sfText_copy", dynlib: LibG.}
+proc destroy*(text: PText) {.
+  cdecl, importc: "sfText_destroy", dynlib: LibG.}
+proc setPosition*(text: PText, position: TVector2f) {.
+  cdecl, importc: "sfText_setPosition", dynlib: LibG.}
+proc setRotation*(text: PText, angle: cfloat) {.
+  cdecl, importc: "sfText_setRotation", dynlib: LibG.}
+proc setScale*(text: PText, scale: TVector2f) {.
+  cdecl, importc: "sfText_setScale", dynlib: LibG.}
+proc setOrigin*(text: PText, origin: TVector2f) {.
+  cdecl, importc: "sfText_setOrigin", dynlib: LibG.}
+proc getPosition*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getPosition", dynlib: LibG.}
+proc getRotation*(text: PText): cfloat {.
+  cdecl, importc: "sfText_getRotation", dynlib: LibG.}
+proc getScale*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getScale", dynlib: LibG.}
+proc getOrigin*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getOrigin", dynlib: LibG.}
+proc move*(text: PText, offset: TVector2f) {.
+  cdecl, importc: "sfText_move", dynlib: LibG.}
+proc rotate*(text: PText, angle: cfloat) {.
+  cdecl, importc: "sfText_rotate", dynlib: LibG.}
+proc scale*(text: PText, factors: TVector2f) {.
+  cdecl, importc: "sfText_scale", dynlib: LibG.}
+proc getTransform*(text: PText): TTransform {.
+  cdecl, importc: "sfText_getTransform", dynlib: LibG.}
+proc getInverseTransform*(text: PText): TTransform {.
+  cdecl, importc: "sfText_getInverseTransform", dynlib: LibG.}
+proc setString*(text: PText, string: cstring) {.
+  cdecl, importc: "sfText_setString", dynlib: LibG.}
+proc setUnicodeString*(text: PText, string: ptr uint32) {.
+  cdecl, importc: "sfText_setUnicodeString", dynlib: LibG.}
+proc setFont*(text: PText, font: PFont) {.
+  cdecl, importc: "sfText_setFont", dynlib: LibG.}
+proc setCharacterSize*(text: PText, size: cint) {.
+  cdecl, importc: "sfText_setCharacterSize", dynlib: LibG.}
+proc setStyle*(text: PText, style: TTextStyle) {.
+  cdecl, importc: "sfText_setStyle", dynlib: LibG.}
+proc setColor*(text: PText, color: TColor) {.
+  cdecl, importc: "sfText_setColor", dynlib: LibG.}
+proc getString*(text: PText): cstring {.
+  cdecl, importc: "sfText_getString", dynlib: LibG.}
+proc getUnicodeString*(text: PText): ptr uint32 {.cdecl,
+  importc: "sfText_getUnicodeString", dynlib: LibG.}
+proc getFont*(text: PText): PFont {.
+  cdecl, importc: "sfText_getFont", dynlib: LibG.}
+proc getCharacterSize*(text: PText): cint {.
+  cdecl, importc: "sfText_getCharacterSize", dynlib: LibG.}
+proc getStyle*(text: PText): uint32 {.
+  cdecl, importc: "sfText_getStyle", dynlib: LibG.}
+proc getColor*(text: PText): TColor {.
+  cdecl, importc: "sfText_getColor", dynlib: LibG.}
+proc findCharacterPos*(text: PText, index: cint): TVector2f {.
+  cdecl, importc: "sfText_findCharacterPos", dynlib: LibG.}
+proc getLocalBounds*(text: PText): TFloatRect {.
+  cdecl, importc: "sfText_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(text: PText): TFloatRect {.
+  cdecl, importc: "sfText_getGlobalBounds", dynlib: LibG.}
+
+proc transformFromMatrix*(a00, a01, a02, a10, a11, a12, a20, a21, a22: cfloat): TTransform {.
+  cdecl, importc: "sfTransform_fromMatrix", dynlib: LibG.}
+proc getMatrix*(transform: PTransform, matrix: ptr cfloat) {.
+  cdecl, importc: "sfTransform_getMatrix", dynlib: LibG.}
+proc getInverse*(transform: PTransform): TTransform {.
+  cdecl, importc: "sfTransform_getInverse", dynlib: LibG.}
+proc transformPoint*(transform: PTransform, point: TVector2f): TVector2f {.
+  cdecl, importc: "sfTransform_transformPoint", dynlib: LibG.}
+proc transformRect*(transform: PTransform, rectangle: TFloatRect): TFloatRect {.
+  cdecl, importc: "sfTransform_transformRect", dynlib: LibG.}
+proc combine*(transform: PTransform, other: PTransform) {.
+  cdecl, importc: "sfTransform_combine", dynlib: LibG.}
+proc translate*(transform: PTransform, x, y: cfloat) {.
+  cdecl, importc: "sfTransform_translate", dynlib: LibG.}
+proc rotate*(transform: PTransform, angle: cfloat) {.
+  cdecl, importc: "sfTransform_rotate", dynlib: LibG.}
+proc rotateWithCenter*(transform: PTransform, angle, centerX, centerY: cfloat){.
+  cdecl, importc: "sfTransform_rotateWithCenter", dynlib: LibG.}
+proc scale*(transform: PTransform, scaleX, scaleY: cfloat) {.
+  cdecl, importc: "sfTransform_scale", dynlib: LibG.}
+proc scaleWithCenter*(transform: PTransform, scaleX, scaleY, centerX, centerY: cfloat) {.
+  cdecl, importc: "sfTransform_scaleWithCenter", dynlib: LibG.}
+let IdentityMatrix*: TTransform = transformFromMatrix(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
+
+
+proc newShader*(VSfilename: cstring, fragmentShaderFilename: cstring): PShader {.
+  cdecl, importc: "sfShader_createFromFile", dynlib: LibG.}
+proc newShaderFromStr*(vertexShader: cstring, fragmentShader: cstring): PShader {.
+  cdecl, importc: "sfShader_createFromMemory", dynlib: LibG.}
+proc newShader*(vertexShaderStream: PInputStream, fragmentShaderStream: PInputStream): PShader {.
+  cdecl, importc: "sfShader_createFromStream", dynlib: LibG.}
+proc destroy*(shader: PShader) {.
+  cdecl, importc: "sfShader_destroy", dynlib: LibG.}
+proc setFloatParameter*(shader: PShader, name: cstring, x: cfloat) {.
+  cdecl, importc: "sfShader_setFloatParameter", dynlib: LibG.}
+proc setFloat2Parameter*(shader: PShader, name: cstring, x, y: cfloat) {.
+  cdecl, importc: "sfShader_setFloat2Parameter", dynlib: LibG.}
+proc setFloat3Parameter*(shader: PShader, name: cstring, x, y, z: cfloat) {.
+  cdecl, importc: "sfShader_setFloat3Parameter", dynlib: LibG.}
+proc setFloat4Parameter*(shader: PShader, name: cstring, x, y, z, w: cfloat) {.
+  cdecl, importc: "sfShader_setFloat4Parameter", dynlib: LibG.}
+proc setVector2Parameter*(shader: PShader, name: cstring, vector: TVector2f) {.
+  cdecl, importc: "sfShader_setVector2Parameter", dynlib: LibG.}
+proc setVector3Parameter*(shader: PShader, name: cstring, vector: TVector3f) {.
+  cdecl, importc: "sfShader_setVector3Parameter", dynlib: LibG.}
+proc setColorParameter*(shader: PShader, name: cstring, color: TColor) {.
+  cdecl, importc: "sfShader_setColorParameter", dynlib: LibG.}
+proc setTransformParameter*(shader: PShader, name: cstring, transform: TTransform) {.
+  cdecl, importc: "sfShader_setTransformParameter", dynlib: LibG.}
+proc setTextureParameter*(shader: PShader, name: cstring, texture: PTexture) {.
+  cdecl, importc: "sfShader_setTextureParameter", dynlib: LibG.}
+proc setCurrentTextureParameter*(shader: PShader, name: cstring) {.
+  cdecl, importc: "sfShader_setCurrentTextureParameter", dynlib: LibG.}
+proc bindGL*(shader: PShader) {.
+  cdecl, importc: "sfShader_bind", dynlib: LibG.}
+proc unbindGL*(shader: PShader) {.
+  cdecl, importc: "sfShader_unbind", dynlib: LibG.}
+proc shaderIsAvailable*(): bool {.
+  cdecl, importc: "sfShader_isAvailable", dynlib: LibG.}
+
+proc color*(red, green, blue: cchar): TColor {.
+  cdecl, importc: "sfColor_fromRGB", dynlib: LibG.}
+proc color*(red, green, blue: int): TColor {.inline.} =
+  return color(red.cchar, green.cchar, blue.cchar)
+proc color*(red, green, blue, alpha: cchar): TColor {.
+  cdecl, importc: "sfColor_fromRGBA", dynlib: LibG.}
+proc color*(red, green, blue, alpha: int): TColor {.inline.} =
+  return color(red.cchar, green.cchar, blue.cchar, alpha.cchar)
+proc `+`*(color1, color2: TColor): TColor {.
+  cdecl, importc: "sfColor_add", dynlib: LibG.}
+proc `*`*(color1, color2: TColor): TColor {.
+  cdecl, importc: "sfColor_modulate", dynlib: LibG.}
+proc newColor*(r,g,b: int): TColor {.inline.} =
+  return color(r,g,b)
+proc newColor*(r,g,b,a: int): TColor {.inline.} =
+  return color(r,g,b,a)
+
+proc newClock*(): PClock {.
+  cdecl, importc: "sfClock_create", dynlib: LibS.}
+proc copy*(clocK: PClock): PClock {.
+  cdecl, importc: "sfClock_copy", dynlib: LibS.}
+proc destroy*(clock: PClock): PClock {.
+  cdecl, importc: "sfClock_destroy", dynlib: LibS.}
+proc getElapsedTime*(clock: PClock): TTime {.
+  cdecl, importc: "sfClock_getElapsedTime", dynlib: LibS.}
+proc restart*(clock: PClock): TTime {.
+  cdecl, importc: "sfClock_restart", dynlib: LibS, discardable.}
+proc asSeconds*(time: TTime): cfloat {.
+  cdecl, importc: "sfTime_asSeconds", dynlib: LibS.}
+proc asMilliseconds*(time: TTime): int32 {.
+  cdecl, importc: "sfTime_asMilliseconds", dynlib: LibS.}
+proc asMicroseconds*(time: TTime): int64 {.
+  cdecl, importc: "sfTime_asMicroseconds", dynlib: LibS.}
+proc seconds*(seconds: cfloat): TTime {.
+  cdecl, importc: "sfSeconds", dynlib: LibS.}
+proc milliseconds*(ms: int32): TTime {.
+  cdecl, importc: "sfMilliseconds", dynlib: LibS.}
+proc microseconds*(us: int64): TTime {.
+  cdecl, importc: "sfMicroseconds", dynlib: LibS.}
+
+proc newContextSettings*(depthBits: cint = 0,
+                         stencilBits: cint = 0,
+                         antialiasingLevel: cint = 0,
+                         majorVersion: cint = 0,
+                         minorVersion: cint = 0): TContextSettings =
+  result.depthBits = depthBits
+  result.stencilBits = stencilBits
+  result.antialiasingLevel = antialiasingLevel
+  result.majorVersion = majorVersion
+  result.minorVersion = minorVersion
+
+proc newCircleShape*(radius: cfloat; pointCount: cint = 30): PCircleShape =
+  result = newCircleShape()
+  result.setRadius radius
+  result.setPointCount pointCount
+proc newText*(str: string, font: PFont, size: int): PText =
+  result = newText()
+  result.setString(str)
+  result.setFont(font)
+  result.setCharacterSize(size.cint)
+proc newVertexArray*(primitiveType: TPrimitiveType, vertexCount: cint = 0): PVertexArray =
+  result = newVertexArray()
+  result.setPrimitiveType(primitiveType)
+  if vertexCount != 0:
+    result.resize(vertexCount)
+proc videoMode*(width, height, bpp: cint): TVideoMode =
+  result.width = width
+  result.height = height
+  result.bitsPerPixel = bpp
+
+proc `[]`*(a: PVertexArray, index: int): PVertex =
+  return getVertex(a, index.cint)
+
+proc `$` *(a: TContextSettings): string =
+  return "<TContextSettings stencil=$1 aa=$2 major=$3 minor=$4 depth=$5>" % [
+    $a.stencilBits, $a.antialiasingLevel, $a.majorVersion, $a.minorVersion, $a.depthBits]
+proc `$` *(a: TVideoMode): string =
+  return "<TVideoMode $1x$2 $3bpp>" % [$a.width, $a.height, $a.bitsPerPixel]
+proc `$` *(a: TFloatRect): string =
+  return "<TFloatRect $1,$2 $3x$4>" % [$a.left, $a.top, $a.width, $a.height]
+proc `$` *(a: PView): string =
+  return $a.getViewport()
+proc `$` *(a: TVector2f): string =
+  return "<TVector2f $1,$2>" % [$a.x, $a.y]
+
+proc vec2i*(x, y: int): TVector2i =
+  result.x = x.cint
+  result.y = y.cint
+proc vec2f*(x, y: float): TVector2f =
+  result.x = x.cfloat
+  result.y = y.cfloat
+
+proc `+`*(a, b: TVector2f): TVector2f {.inline.} =
+  result.x = a.x + b.x
+  result.y = a.y + b.y
+proc `-`*(a: TVector2f): TVector2f {.inline.} =
+  result.x = -a.x
+  result.y = -a.y
+proc `-`*(a, b: TVector2f): TVector2f {.inline.}=
+  result.x = a.x - b.x
+  result.y = a.y - b.y
+proc `*`*(a: TVector2f, b: cfloat): TVector2f {.inline.} =
+  result.x = a.x * b
+  result.y = a.y * b
+proc `*`*(a, b: TVector2f): TVector2f {.inline.} =
+  result.x = a.x * b.x
+  result.y = a.y * b.y
+proc `/`*(a: TVector2f, b: cfloat): TVector2f {.inline.} =
+  result.x = a.x / b
+  result.y = a.y / b
+proc `+=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a + b
+proc `-=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a - b
+proc `*=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} =
+  a = a * b
+proc `*=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a * b
+proc `/=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} =
+  a = a / b
+proc `<` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x < b.x or (a.x == b.x and a.y < b.y)
+proc `<=` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x <= b.x and a.y <= b.y
+proc `==` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x == b.x and a.y == b.y
+proc length*(a: TVector2f): float {.inline.} =
+  return sqrt(pow(a.x, 2.0) + pow(a.y, 2.0))
+proc lengthSq*(a: TVector2f): float {.inline.} =
+  return pow(a.x, 2.0) + pow(a.y, 2.0)
+proc distanceSq*(a, b: TVector2f): float {.inline.} =
+  return pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0)
+proc distance*(a, b: TVector2f): float {.inline.} =
+  return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0))
+proc permul*(a, b: TVector2f): TVector2f =
+  result.x = a.x * b.x
+  result.y = a.y * b.y
+proc rotate*(a: TVector2f, phi: float): TVector2f =
+  var c = cos(phi)
+  var s = sin(phi)
+  result.x = a.x * c - a.y * s
+  result.y = a.x * s + a.y * c
+proc perpendicular(a: TVector2f): TVector2f =
+  result.x = -a.x
+  result.y =  a.y
+proc cross(a, b: TVector2f): float =
+  return a.x * b.y - a.y * b.x
+
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
new file mode 100644
index 000000000..6f81e50a3
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
@@ -0,0 +1,899 @@
+import
+  sfml
+const
+  Lib = "libcsfml-audio.so.2.0"
+type
+  PMusic* = ptr TMusic
+  TMusic* {.pure, final.} = object
+  PSound* = ptr TSound
+  TSound* {.pure, final.} = object
+  PSoundBuffer* = ptr TSoundBuffer
+  TSoundBuffer* {.pure, final.} = object
+  PSoundBufferRecorder* = ptr TSoundBufferRecorder
+  TSoundBufferRecorder* {.pure, final.} = object
+  PSoundRecorder* = ptr TSoundRecorder
+  TSoundRecorder* {.pure, final.} = object
+  PSoundStream* = ptr TSoundStream
+  TSoundStream* {.pure, final.} = object
+  TSoundStatus* {.size: sizeof(cint).} = enum
+    Stopped, Paused, Playing
+
+proc newMusic*(filename: cstring): PMusic {.
+  cdecl, importc: "sfMusic_createFromFile", dynlib: Lib.}
+proc newMusic*(data: pointer, size: cint): PMusic {.
+  cdecl, importc: "sfMusic_createFromMemory", dynlib: Lib.}
+proc newMusic*(stream: PInputStream): PMusic {.
+  cdecl, importc: "sfMusic_createFromStream", dynlib: Lib.}
+proc destroy*(music: PMusic) {.
+  cdecl, importc: "sfMusic_destroy", dynlib: Lib.}
+proc setLoop*(music: PMusic, loop: bool) {.
+  cdecl, importc: "sfMusic_setLoop", dynlib: Lib.}
+proc getLoop*(music: PMusic): bool {.
+  cdecl, importc: "sfMusic_getLoop", dynlib: Lib.}
+proc getDuration*(music: PMusic): TTime {.
+  cdecl, importc: "sfMusic_getDuration", dynlib: Lib.}
+proc play*(music: PMusic) {.
+  cdecl, importc: "sfMusic_play", dynlib: Lib.}
+proc pause*(music: PMusic) {.
+  cdecl, importc: "sfMusic_pause", dynlib: Lib.}
+proc stop*(music: PMusic) {.
+  cdecl, importc: "sfMusic_stop", dynlib: Lib.}
+proc getChannelCount*(music: PMusic): cint {.
+  cdecl, importc: "sfMusic_getChannelCount", dynlib: Lib.}
+proc getSampleRate*(music: PMusic): cint {.
+  cdecl, importc: "sfMusic_getSampleRate", dynlib: Lib.}
+proc getStatus*(music: PMusic): TSoundStatus {.
+  cdecl, importc: "sfMusic_getStatus", dynlib: Lib.}
+proc getPlayingOffset*(music: PMusic): TTime {.
+  cdecl, importc: "sfMusic_getPlayingOffset", dynlib: Lib.}
+proc setPitch*(music: PMusic, pitch: cfloat) {.
+  cdecl, importc: "sfMusic_setPitch", dynlib: Lib.}
+proc setVolume*(music: PMusic, volume: float) {.
+  cdecl, importc: "sfMusic_setVolume", dynlib: Lib.}
+proc setPosition*(music: PMusic, position: TVector3f) {.
+  cdecl, importc: "sfMusic_setPosition", dynlib: Lib.}
+proc setRelativeToListener*(music: PMusic, relative: bool) {.
+  cdecl, importc: "sfMusic_setRelativeToListener", dynlib: Lib.}
+proc setMinDistance*(music: PMusic, distance: cfloat) {.
+  cdecl, importc: "sfMusic_setMinDistance", dynlib: Lib.}
+proc setAttenuation*(music: PMusic, attenuation: cfloat) {.
+  cdecl, importc: "sfMusic_setAttenuation", dynlib: Lib.}
+proc setPlayingOffset*(music: PMusic, time: TTime) {.
+  cdecl, importc: "sfMusic_setPlayingOffset", dynlib: Lib.}
+proc getPitch*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_getPitch", dynlib: Lib.}
+proc getVolume*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_getVolume", dynlib: Lib.}
+proc getPosition*(music: PMusic): TVector3f {.
+  cdecl, importc: "sfMusic_getPosition", dynlib: Lib.}
+proc isRelativeToListener*(music: PMusic): bool {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+proc getMinDistance*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+proc getAttenuation*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+
+#/ \brief Create a new sound
+proc newSound*(): PSound{.
+  cdecl, importc: "sfSound_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound by copying an existing one
+#/
+#/ \param sound Sound to copy
+#/
+#/ \return A new sfSound object which is a copy of \a sound
+#/
+#//////////////////////////////////////////////////////////
+proc copy*(sound: PSound): PSound{.
+  cdecl, importc: "sfSound_copy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound
+proc destroy*(sound: PSound){.
+  cdecl, importc: "sfSound_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start or resume playing a sound
+#/
+#/ This function starts the sound if it was stopped, resumes
+#/ it if it was paused, and restarts it from beginning if it
+#/ was it already playing.
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the sound is played.
+proc play*(sound: PSound){.
+  cdecl, importc: "sfSound_play", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ This function pauses the sound if it was playing,
+#/ otherwise (sound already paused or stopped) it has no effect.
+proc pause*(sound: PSound){.
+  cdecl, importc: "sfSound_pause", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ This function stops the sound if it was playing or paused,
+#/ and does nothing if it was already stopped.
+#/ It also resets the playing position (unlike sfSound_pause).
+proc stop*(sound: PSound){.
+  cdecl, importc: "sfSound_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ It is important to note that the sound buffer is not copied,
+#/ thus the sfSoundBuffer object must remain alive as long
+#/ as it is attached to the sound.
+proc setBuffer*(sound: PSound; buffer: PSoundBuffer){.
+  cdecl, importc: "sfSound_setBuffer", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the audio buffer attached to a sound
+proc getBuffer*(sound: PSound): PSoundBuffer{.
+  cdecl, importc: "sfSound_getBuffer", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set whether or not a sound should loop after reaching the end
+#/
+#/ If set, the sound will restart from beginning after
+#/ reaching the end and so on, until it is stopped or
+#/ sfSound_setLoop(sound, sfFalse) is called.
+#/ The default looping state for sounds is false.
+proc setLoop*(sound: PSound; loop: bool){.
+  cdecl, importc: "sfSound_setLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether or not a soud is in loop mode
+proc getLoop*(sound: PSound): bool {.
+  cdecl, importc: "sfSound_getLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current status of a sound (stopped, paused, playing)
+proc getStatus*(sound: PSound): TSoundStatus{.
+  cdecl, importc: "sfSound_getStatus", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the pitch of a sound
+#/
+#/ The pitch represents the perceived fundamental frequency
+#/ of a sound; thus you can make a sound more acute or grave
+#/ by changing its pitch. A side effect of changing the pitch
+#/ is to modify the playing speed of the sound as well.
+#/ The default value for the pitch is 1.
+proc setPitch*(sound: PSound; pitch: cfloat){.
+  cdecl, importc: "sfSound_setPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the volume of a sound
+#/
+#/ The volume is a value between 0 (mute) and 100 (full volume).
+#/ The default value for the volume is 100.
+proc setVolume*(sound: PSound; volume: cfloat){.
+  cdecl, importc: "sfSound_setVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the 3D position of a sound in the audio scene
+#/
+#/ Only sounds with one channel (mono sounds) can be
+#/ spatialized.
+#/ The default position of a sound is (0, 0, 0).
+proc setPosition*(sound: PSound; position: TVector3f){.
+  cdecl, importc: "sfSound_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Make the sound's position relative to the listener or absolute
+#/
+#/ Making a sound relative to the listener will ensure that it will always
+#/ be played the same way regardless the position of the listener.
+#/ This can be useful for non-spatialized sounds, sounds that are
+#/ produced by the listener, or sounds attached to it.
+#/ The default value is false (position is absolute).
+proc setRelativeToListener*(sound: PSound; relative: bool){.
+  cdecl, importc: "sfSound_setRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the minimum distance of a sound
+#/
+#/ The "minimum distance" of a sound is the maximum
+#/ distance at which it is heard at its maximum volume. Further
+#/ than the minimum distance, it will start to fade out according
+#/ to its attenuation factor. A value of 0 ("inside the head
+#/ of the listener") is an invalid value and is forbidden.
+#/ The default value of the minimum distance is 1.
+proc setMinDistance*(sound: PSound; distance: cfloat){.
+  cdecl, importc: "sfSound_setMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the attenuation factor of a sound
+#/
+#/ The attenuation is a multiplicative factor which makes
+#/ the sound more or less loud according to its distance
+#/ from the listener. An attenuation of 0 will produce a
+#/ non-attenuated sound, i.e. its volume will always be the same
+#/ whether it is heard from near or from far. On the other hand,
+#/ an attenuation value such as 100 will make the sound fade out
+#/ very quickly as it gets further from the listener.
+#/ The default value of the attenuation is 1.
+proc setAttenuation*(sound: PSound; attenuation: cfloat){.
+  cdecl, importc: "sfSound_setAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Change the current playing position of a sound
+#/
+#/ The playing position can be changed when the sound is
+#/ either paused or playing.
+proc setPlayingOffset*(sound: PSound; timeOffset: sfml.TTime){.
+  cdecl, importc: "sfSound_setPlayingOffset", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the pitch of a sound
+proc getPitch*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the volume of a sound
+proc getVolume*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the 3D position of a sound in the audio scene
+proc getPosition*(sound: PSound): TVector3f{.
+  cdecl, importc: "sfSound_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether a sound's position is relative to the
+#/        listener or is absolute
+proc isRelativeToListener*(sound: PSound): bool{.
+  cdecl, importc: "sfSound_isRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the minimum distance of a sound
+proc getMinDistance*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the attenuation factor of a sound
+proc getAttenuation*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current playing position of a sound
+proc getPlayingOffset*(sound: PSound): TTime{.
+  cdecl, importc: "sfSound_getPlayingOffset", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+# Headers
+#//////////////////////////////////////////////////////////
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a file
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param filename Path of the sound file to load
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(filename: cstring): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromFile", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a file in memory
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param data        Pointer to the file data in memory
+#/ \param sizeInBytes Size of the data to load, in bytes
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(data: pointer; sizeInBytes: cint): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromMemory", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a custom stream
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param stream Source stream to read from
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(stream: PInputStream): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromStream", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from an array of samples in memory
+#/
+#/ The assumed format of the audio samples is 16 bits signed integer
+#/ (sfint16).
+#/
+#/ \param samples      Pointer to the array of samples in memory
+#/ \param sampleCount  Number of samples in the array
+#/ \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
+#/ \param sampleRate   Sample rate (number of samples to play per second)
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc createFromSamples*(samples: ptr int16; sampleCount: cuint;
+                         channelCount: cuint; sampleRate: cuint): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromSamples", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer by copying an existing one
+#/
+#/ \param soundBuffer Sound buffer to copy
+#/
+#/ \return A new sfSoundBuffer object which is a copy of \a soundBuffer
+#/
+#//////////////////////////////////////////////////////////
+proc copy*(soundBuffer: PSoundBuffer): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_copy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound buffer
+#/
+#/ \param soundBuffer Sound buffer to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundBuffer: PSoundBuffer){.
+  cdecl, importc: "sfSoundBuffer_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Save a sound buffer to an audio file
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param soundBuffer Sound buffer object
+#/ \param filename    Path of the sound file to write
+#/
+#/ \return sfTrue if saving succeeded, sfFalse if it failed
+#/
+#//////////////////////////////////////////////////////////
+proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {.
+  cdecl, importc: "sfSoundBuffer_saveToFile", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the array of audio samples stored in a sound buffer
+#/
+#/ The format of the returned samples is 16 bits signed integer
+#/ (sfint16). The total number of samples in this array
+#/ is given by the sfSoundBuffer_getSampleCount function.
+#/
+#/ \param soundBuffer Sound buffer object
+#/
+#/ \return Read-only pointer to the array of sound samples
+#/
+#//////////////////////////////////////////////////////////
+proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr int16{.
+  cdecl, importc: "sfSoundBuffer_getSamples", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the number of samples stored in a sound buffer
+#/
+#/ The array of samples can be accessed with the
+#/ sfSoundBuffer_getSamples function.
+proc getSampleCount*(soundBuffer: PSoundBuffer): cint{.
+  cdecl, importc: "sfSoundBuffer_getSampleCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound buffer
+#/
+#/ The sample rate is the number of samples played per second.
+#/ The higher, the better the quality (for example, 44100
+#/ samples/s is CD quality).
+proc getSampleRate*(soundBuffer: PSoundBuffer): cuint{.
+  cdecl, importc: "sfSoundBuffer_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the number of channels used by a sound buffer
+#/
+#/ If the sound is mono then the number of channels will
+#/ be 1, 2 for stereo, etc.
+proc getChannelCount*(soundBuffer: PSoundBuffer): cuint{.
+  cdecl, importc: "sfSoundBuffer_getChannelCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the total duration of a sound buffer
+#/
+#/ \param soundBuffer Sound buffer object
+#/
+#/ \return Sound duration
+#/
+#//////////////////////////////////////////////////////////
+proc getDuration*(soundBuffer: PSoundBuffer): TTime{.
+  cdecl, importc: "sfSoundBuffer_getDuration", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+#/ \brief Change the global volume of all the sounds and musics
+#/
+#/ The volume is a number between 0 and 100; it is combined with
+#/ the individual volume of each sound / music.
+#/ The default value for the volume is 100 (maximum).
+#/
+#/ \param volume New global volume, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetGlobalVolume*(volume: cfloat){.
+  cdecl, importc: "sfListener_setGlobalVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current value of the global volume
+#/
+#/ \return Current global volume, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetGlobalVolume*(): cfloat{.
+  cdecl, importc: "sfListener_getGlobalVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the position of the listener in the scene
+#/
+#/ The default listener's position is (0, 0, 0).
+#/
+#/ \param position New position of the listener
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetPosition*(position: TVector3f){.
+  cdecl, importc: "sfListener_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current position of the listener in the scene
+#/
+#/ \return The listener's position
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetPosition*(): TVector3f{.
+  cdecl, importc: "sfListener_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the orientation of the listener in the scene
+#/
+#/ The orientation defines the 3D axes of the listener
+#/ (left, up, front) in the scene. The orientation vector
+#/ doesn't have to be normalized.
+#/ The default listener's orientation is (0, 0, -1).
+#/
+#/ \param position New direction of the listener
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetDirection*(orientation: TVector3f){.
+  cdecl, importc: "sfListener_setDirection", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current orientation of the listener in the scene
+#/
+#/ \return The listener's direction
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetDirection*(): TVector3f{.
+  cdecl, importc: "sfListener_getDirection", dynlib: Lib.}
+
+type
+  TSoundRecorderStartCallback* = proc (a2: pointer): bool {.cdecl.}
+  #/< Type of the callback used when starting a capture
+  TSoundRecorderProcessCallback* = proc(a2: ptr int16; a3: cuint;
+    a4: pointer): bool {.cdecl.}
+  #/< Type of the callback used to process audio data
+  TSoundRecorderStopCallback* = proc (a2: pointer){.cdecl.}
+  #/< Type of the callback used when stopping a capture
+#//////////////////////////////////////////////////////////
+#/ \brief Construct a new sound recorder from callback functions
+#/
+#/ \param onStart   Callback function which will be called when a new capture starts (can be NULL)
+#/ \param onProcess Callback function which will be called each time there's audio data to process
+#/ \param onStop    Callback function which will be called when the current capture stops (can be NULL)
+#/ \param userData  Data to pass to the callback function (can be NULL)
+#/
+#/ \return A new sfSoundRecorder object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundRecorder*(onStart: TSoundRecorderStartCallback;
+                        onProcess: TSoundRecorderProcessCallback;
+                        onStop: TSoundRecorderStopCallback;
+                        userData: pointer = nil): PSoundRecorder{.
+  cdecl, importc: "sfSoundRecorder_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound recorder
+#/
+#/ \param soundRecorder Sound recorder to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundRecorder: PSoundRecorder){.
+  cdecl, importc: "sfSoundRecorder_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start the capture of a sound recorder
+#/
+#/ The \a sampleRate parameter defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the capture runs.
+#/ Please note that only one capture can happen at the same time.
+#/
+#/ \param soundRecorder Sound recorder object
+#/ \param sampleRate    Desired capture rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc start*(soundRecorder: PSoundRecorder; sampleRate: cuint){.
+  cdecl, importc: "sfSoundRecorder_start", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop the capture of a sound recorder
+#/
+#/ \param soundRecorder Sound recorder object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundRecorder: PSoundRecorder){.
+  cdecl, importc: "sfSoundRecorder_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound recorder
+#/
+#/ The sample rate defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/
+#/ \param soundRecorder Sound recorder object
+#/
+#/ \return Sample rate, in samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundRecorder: PSoundRecorder): cuint{.
+  cdecl, importc: "sfSoundRecorder_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Check if the system supports audio capture
+#/
+#/ This function should always be called before using
+#/ the audio capture features. If it returns false, then
+#/ any attempt to use sfSoundRecorder will fail.
+#/
+#/ \return sfTrue if audio capture is supported, sfFalse otherwise
+#/
+#//////////////////////////////////////////////////////////
+proc soundRecorderIsAvailable*(): bool {.
+  cdecl, importc: "sfSoundRecorder_isAvailable", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer recorder
+#/
+#/ \return A new sfSoundBufferRecorder object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBufferRecorder*(): PSoundBufferRecorder{.
+  cdecl, importc: "sfSoundBufferRecorder_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound buffer recorder
+#/
+#/ \param soundBufferRecorder Sound buffer recorder to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundBufferRecorder: PSoundBufferRecorder){.
+  cdecl, importc: "sfSoundBufferRecorder_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start the capture of a sound recorder recorder
+#/
+#/ The \a sampleRate parameter defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the capture runs.
+#/ Please note that only one capture can happen at the same time.
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/ \param sampleRate          Desired capture rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc start*(soundBufferRecorder: PSoundBufferRecorder; sampleRate: cuint){.
+  cdecl, importc: "sfSoundBufferRecorder_start", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop the capture of a sound recorder
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundBufferRecorder: PSoundBufferRecorder){.
+  cdecl, importc: "sfSoundBufferRecorder_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound buffer recorder
+#/
+#/ The sample rate defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#/ \return Sample rate, in samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundBufferRecorder: PSoundBufferRecorder): cuint{.
+  cdecl, importc: "sfSoundBufferRecorder_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sound buffer containing the captured audio data
+#/
+#/ The sound buffer is valid only after the capture has ended.
+#/ This function provides a read-only access to the internal
+#/ sound buffer, but it can be copied if you need to
+#/ make any modification to it.
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#/ \return Read-only access to the sound buffer
+#/
+#//////////////////////////////////////////////////////////
+proc getBuffer*(soundBufferRecorder: PSoundBufferRecorder): PSoundBuffer{.
+  cdecl, importc: "sfSoundBufferRecorder_getBuffer", dynlib: Lib.}
+
+
+#//////////////////////////////////////////////////////////
+#/ \brief defines the data to fill by the OnGetData callback
+#/
+#//////////////////////////////////////////////////////////
+type
+  PSoundStreamChunk* = ptr TSoundStreamChunk
+  TSoundStreamChunk*{.pure, final.} = object
+    samples*: ptr int16   #/< Pointer to the audio samples
+    sampleCount*: cuint     #/< Number of samples pointed by Samples
+
+  TSoundStreamGetDataCallback* = proc (a2: PSoundStreamChunk;
+      a3: pointer): bool{.cdecl.}
+  #/< Type of the callback used to get a sound stream data
+  TSoundStreamSeekCallback* = proc (a2: TTime; a3: pointer){.cdecl.}
+  #/< Type of the callback used to seek in a sound stream
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound stream
+#/
+#/ \param onGetData    Function called when the stream needs more data (can't be NULL)
+#/ \param onSeek       Function called when the stream seeks (can't be NULL)
+#/ \param channelCount Number of channels to use (1 = mono, 2 = stereo)
+#/ \param sampleRate   Sample rate of the sound (44100 = CD quality)
+#/ \param userData     Data to pass to the callback functions
+#/
+#/ \return A new sfSoundStream object
+#/
+#//////////////////////////////////////////////////////////
+proc create*(onGetData: TSoundStreamGetDataCallback; onSeek: TSoundStreamSeekCallback;
+              channelCount: cuint; sampleRate: cuint; userData: pointer): PSoundStream{.
+  cdecl, importc: "sfSoundStream_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound stream
+#/
+#/ \param soundStream Sound stream to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start or resume playing a sound stream
+#/
+#/ This function starts the stream if it was stopped, resumes
+#/ it if it was paused, and restarts it from beginning if it
+#/ was it already playing.
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the music is played.
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc play*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_play", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Pause a sound stream
+#/
+#/ This function pauses the stream if it was playing,
+#/ otherwise (stream already paused or stopped) it has no effect.
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc pause*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_pause", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop playing a sound stream
+#/
+#/ This function stops the stream if it was playing or paused,
+#/ and does nothing if it was already stopped.
+#/ It also resets the playing position (unlike sfSoundStream_pause).
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current status of a sound stream (stopped, paused, playing)
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Current status
+#/
+#//////////////////////////////////////////////////////////
+proc getStatus*(soundStream: PSoundStream): TSoundStatus{.
+  cdecl, importc: "sfSoundStream_getStatus", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Return the number of channels of a sound stream
+#/
+#/ 1 channel means a mono sound, 2 means stereo, etc.
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Number of channels
+#/
+#//////////////////////////////////////////////////////////
+proc getChannelCount*(soundStream: PSoundStream): cuint{.
+  cdecl, importc: "sfSoundStream_getChannelCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound stream
+#/
+#/ The sample rate is the number of audio samples played per
+#/ second. The higher, the better the quality.
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Sample rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundStream: PSoundStream): cuint{.
+  cdecl, importc: "sfSoundStream_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the pitch of a sound stream
+#/
+#/ The pitch represents the perceived fundamental frequency
+#/ of a sound; thus you can make a stream more acute or grave
+#/ by changing its pitch. A side effect of changing the pitch
+#/ is to modify the playing speed of the stream as well.
+#/ The default value for the pitch is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param pitch       New pitch to apply to the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setPitch*(soundStream: PSoundStream; pitch: cfloat){.
+  cdecl, importc: "sfSoundStream_setPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the volume of a sound stream
+#/
+#/ The volume is a value between 0 (mute) and 100 (full volume).
+#/ The default value for the volume is 100.
+#/
+#/ \param soundStream Sound stream object
+#/ \param volume      Volume of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setVolume*(soundStream: PSoundStream; volume: cfloat){.
+  cdecl, importc: "sfSoundStream_setVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the 3D position of a sound stream in the audio scene
+#/
+#/ Only streams with one channel (mono streams) can be
+#/ spatialized.
+#/ The default position of a stream is (0, 0, 0).
+#/
+#/ \param soundStream Sound stream object
+#/ \param position    Position of the stream in the scene
+#/
+#//////////////////////////////////////////////////////////
+proc setPosition*(soundStream: PSoundStream; position: TVector3f){.
+  cdecl, importc: "sfSoundStream_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Make a sound stream's position relative to the listener or absolute
+#/
+#/ Making a stream relative to the listener will ensure that it will always
+#/ be played the same way regardless the position of the listener.
+#/ This can be useful for non-spatialized streams, streams that are
+#/ produced by the listener, or streams attached to it.
+#/ The default value is false (position is absolute).
+#/
+#/ \param soundStream Sound stream object
+#/ \param relative    sfTrue to set the position relative, sfFalse to set it absolute
+#/
+#//////////////////////////////////////////////////////////
+proc setRelativeToListener*(soundStream: PSoundStream; relative: bool){.
+  cdecl, importc: "sfSoundStream_setRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the minimum distance of a sound stream
+#/
+#/ The "minimum distance" of a stream is the maximum
+#/ distance at which it is heard at its maximum volume. Further
+#/ than the minimum distance, it will start to fade out according
+#/ to its attenuation factor. A value of 0 ("inside the head
+#/ of the listener") is an invalid value and is forbidden.
+#/ The default value of the minimum distance is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param distance    New minimum distance of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setMinDistance*(soundStream: PSoundStream; distance: cfloat){.
+  cdecl, importc: "sfSoundStream_setMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the attenuation factor of a sound stream
+#/
+#/ The attenuation is a multiplicative factor which makes
+#/ the stream more or less loud according to its distance
+#/ from the listener. An attenuation of 0 will produce a
+#/ non-attenuated stream, i.e. its volume will always be the same
+#/ whether it is heard from near or from far. On the other hand,
+#/ an attenuation value such as 100 will make the stream fade out
+#/ very quickly as it gets further from the listener.
+#/ The default value of the attenuation is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param attenuation New attenuation factor of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setAttenuation*(soundStream: PSoundStream; attenuation: cfloat){.
+  cdecl, importc: "sfSoundStream_setAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Change the current playing position of a sound stream
+#/
+#/ The playing position can be changed when the stream is
+#/ either paused or playing.
+#/
+#/ \param soundStream Sound stream object
+#/ \param timeOffset  New playing position
+#/
+#//////////////////////////////////////////////////////////
+proc setPlayingOffset*(soundStream: PSoundStream; timeOffset: TTime){.
+  cdecl, importc: "sfSoundStream_setPlayingOffset", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set whether or not a sound stream should loop after reaching the end
+#/
+#/ If set, the stream will restart from beginning after
+#/ reaching the end and so on, until it is stopped or
+#/ sfSoundStream_setLoop(stream, sfFalse) is called.
+#/ The default looping state for sound streams is false.
+#/
+#/ \param soundStream Sound stream object
+#/ \param loop        sfTrue to play in loop, sfFalse to play once
+#/
+#//////////////////////////////////////////////////////////
+proc setLoop*(soundStream: PSoundStream; loop: bool){.
+  cdecl, importc: "sfSoundStream_setLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the pitch of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Pitch of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getPitch*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the volume of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Volume of the stream, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc getVolume*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the 3D position of a sound stream in the audio scene
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Position of the stream in the world
+#/
+#//////////////////////////////////////////////////////////
+proc getPosition*(soundStream: PSoundStream): TVector3f{.
+  cdecl, importc: "sfSoundStream_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether a sound stream's position is relative to the
+#/        listener or is absolute
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return sfTrue if the position is relative, sfFalse if it's absolute
+#/
+#//////////////////////////////////////////////////////////
+proc isRelativeToListener*(soundStream: PSoundStream): bool{.
+  cdecl, importc: "sfSoundStream_isRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the minimum distance of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Minimum distance of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getMinDistance*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the attenuation factor of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Attenuation factor of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getAttenuation*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether or not a sound stream is in loop mode
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return sfTrue if the music is looping, sfFalse otherwise
+#/
+#//////////////////////////////////////////////////////////
+proc getLoop*(soundStream: PSoundStream): bool{.
+  cdecl, importc: "sfSoundStream_getLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current playing position of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Current playing position
+#/
+#//////////////////////////////////////////////////////////
+proc getPlayingOffset*(soundStream: PSoundStream): TTime{.
+  cdecl, importc: "sfSoundStream_getPlayingOffset", dynlib: Lib.}
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim
new file mode 100644
index 000000000..b4eb1b8f0
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim
@@ -0,0 +1,15 @@
+import sfml
+
+let
+  Black*: TColor = color(0, 0, 0)
+  White*: TColor = color(255, 255, 255)
+  Red*: TColor = color(255, 0, 0)
+  Green*: TColor = color(0, 255, 0)
+  Blue*: TColor = color(0, 0, 255)
+  Yellow*: TColor = color(255, 255, 0)
+  Magenta*: TColor = color(255, 0, 255)
+  Cyan*: TColor = color(0, 255, 255)
+  Transparent*: TColor = color(0, 0, 0, 0)
+  Gray* = color(84, 84, 84)
+  RoyalBlue* = color(65, 105, 225)
+##todo: define more colors lul
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim
new file mode 100644
index 000000000..94c5308a9
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim
@@ -0,0 +1 @@
+import sfml, math, strutils
diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim
new file mode 100644
index 000000000..7aa7b9c2f
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim
@@ -0,0 +1,229 @@
+import enet, strutils,
+  sfml, sfml_colors, sg_gui, input_helpers,
+  math_helpers, sg_packets, estreams, tables,
+  json, sg_assets, client_helpers
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+type
+  TClientSettings = object
+    resolution*: TVideoMode
+    offlineFile: string
+    dirserver: tuple[host: string, port: int16]
+    website*: string
+var
+  clientSettings: TClientSettings
+  event: enet.TEvent
+  bConnected = false
+  runServer = true
+  gui = newGuiContainer()
+  zonelist = newGuiContainer()
+  kc = newKeyClient(setActive = true)
+  clock = newClock()
+  chatBox: PMessageArea
+  chatInput: PTextEntry
+  loginBtn, playBtn: PButton
+  fpsText = newText("", guiFont, 18)
+  connectionButtons: seq[PButton]
+  connectButton: PButton
+  u_alias, u_passwd: PTextEntry
+  dirServer: PServer
+  zone: PServer
+  showZoneList = false
+  myCreds = newScLogin(0, "", "") ##my session token
+
+proc handleChat(server: PServer; buf: PBuffer) =
+  let msg = readScChat(buf)
+  chatBox.add msg
+proc handlePlayerLogin(server: PServer; buf: PBuffer) =
+  let login = readScLogin(buf)
+  myCreds = login
+  echo("I am ", $myCreds)
+
+
+kc.registerHandler MouseLeft, down, proc() =
+  gui.click(input_helpers.getMousePos())
+
+block:
+  var pos = vec2f(15, 550)
+  chatBox = gui.newMessageArea(pos)
+  pos.y += 20
+  chatInput = gui.newTextEntry("...", pos, proc() =
+    sendPubChat dirServer, chatInput.getText()
+    chatInput.clearText())
+
+gui.setActive(chatInput)
+
+proc dispMessage(args: varargs[string, `$`]) =
+  var s = ""
+  for it in items(args):
+    s.add it
+  chatbox.add(s)
+proc dispMessage(text: string) {.inline.} =
+  chatbox.add(text)
+proc dispError(text: string) {.inline.} =
+  chatBox.add(newScChat(kind = CError, text = text))
+
+proc updateButtons() =
+  let conn = dirServer.connected
+  for b in connectionButtons: setEnabled(b, conn)
+  if conn:
+    connectButton.setString "Disconnect"
+  else:
+    connectButton.setString "Connect"
+
+proc poll(serv: PServer; timeout: cuint = 30) =
+  if serv.isNil or serv.host.isNil: return
+  if serv.connected:
+    while serv.host.hostService(event, timeout) > 0:
+      case event.kind
+      of EvtReceive:
+        var buf = newBuffer(event.packet)
+
+        serv.handlePackets(buf)
+
+        event.packet.destroy()
+      of EvtDisconnect:
+        dispMessage "Disconnected"
+        serv.connected = false
+        event.peer.data = nil
+        updateButtons()
+      of EvtNone: discard
+      else:
+        echo repr(event)
+  else:
+    if serv.host.hostService(event, timeout) > 0 and event.kind == EvtConnect:
+      dispMessage "Connected"
+      serv.connected = true
+      if serv.peer != event.peer:
+        serv.peer = event.peer
+      event.peer.data = serv
+      updateButtons()
+
+proc tryLogin*(b: PButton) =
+  var login = newCsLogin(
+    alias = u_alias.getText(),
+    passwd = u_passwd.getText())
+  dirServer.send HLogin, login
+proc tryTransition*(b: PButton) =
+  discard
+  #zone.writePkt HZoneJoinReq, myCreds
+proc tryConnect*(b: PButton) =
+  if not dirServer.connected:
+    var error: string
+    if not dirServer.connect(
+            clientSettings.dirServer.host,
+            clientSettings.dirServer.port,
+            error):
+      dispError(error)
+  else:
+    dirServer.peer.disconnect(1)
+
+proc playOffline*(b: PButton) =
+  var errors: seq[string] = @[]
+  if loadSettingsFromFile(clientSettings.offlineFile, errors):
+    transition()
+  else:
+    dispMessage "Errors reading the file (", clientSettings.offlineFile, "):"
+    for e in errors: dispError(e)
+
+proc getClientSettings*(): TClientSettings =
+  result = clientSettings
+
+
+proc lobbyInit*() =
+  var s = json.parseFile("./client_settings.json")
+  clientSettings.offlineFile = "data/"
+  clientSettings.offlineFile.add s["default-file"].str
+  let dirserv = s["directory-server"]
+  clientSettings.dirserver.host = dirserv["host"].str
+  clientSettings.dirserver.port = dirserv["port"].num.int16
+  clientSettings.resolution.width = s["resolution"][0].num.cint
+  clientSettings.resolution.height= s["resolution"][1].num.cint
+  clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint
+  clientSettings.website = s["website"].str
+  zonelist.setPosition(vec2f(200.0, 100.0))
+  connectionButtons = @[]
+
+  var pos = vec2f(10, 10)
+  u_alias = gui.newTextEntry(
+    if s.hasKey("alias"): s["alias"].str else: "alias",
+    pos)
+  pos.y += 20
+  u_passwd = gui.newTextEntry("buzz", pos)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Login",
+    position = pos,
+    onClick = tryLogin,
+    startEnabled = false))
+  pos.y += 20
+  fpsText.setPosition pos
+  pos.y += 20
+  connectButton = gui.newButton(
+    text = "Connect",
+    position = pos,
+    onClick = tryConnect)
+  pos.y += 20
+  gui.newButton("Test Files", position = pos, onClick = proc(b: PButton) =
+    var req = newCsZoneJoinReq(myCreds)
+    dirServer.send HZoneJoinReq, req)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Test Chat",
+    position = pos,
+    onClick = (proc(b: PButton) =
+      var pkt = newCsChat(text = "ohai")
+      dirServer.send HChat, pkt),
+    startEnabled = false))
+  pos.y += 20
+  downloadProgress.setPosition(pos)
+  downloadProgress.bg.setFillColor(color(34, 139, 34))
+  downloadProgress.bg.setSize(vec2f(0, 0))
+  gui.add(downloadProgress)
+
+  playBtn = gui.newButton(
+    text = "Play",
+    position = vec2f(680.0, 8.0),
+    onClick = tryTransition,
+    startEnabled = false)
+  gui.newButton(
+    text = "Play Offline",
+    position = vec2f(680.0, 28.0),
+    onClick = playOffline)
+  discard """gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack += 1
+    update(messageArea))
+  gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack -= 1
+    update(messageArea))
+  gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) =
+    for i in 0..< 30:
+      dispMessage($i))"""
+  dirServer = newServer()
+  dirServer.addHandler HChat, handleChat
+  dirServer.addHandler HLogin, handlePlayerLogin
+  dirServer.addHandler HFileTransfer, client_helpers.handleFilePartRecv
+  dirServer.addHandler HChallengeResult, client_helpers.handleFileChallengeResult
+  dirServer.addHandler HFileChallenge, client_helpers.handleFileChallenge
+
+proc lobbyReady*() =
+  kc.setActive()
+  gui.setActive(u_alias)
+
+var i = 0
+proc lobbyUpdate*(dt: float) =
+  dirServer.poll()
+  #let res = disp.poll()
+  gui.update(dt)
+  i = (i + 1) mod 60
+  if i == 0:
+    fpsText.setString("FPS: " & ff(1.0/dt))
+
+proc lobbyDraw*(window: PRenderWindow) =
+  window.clear(Black)
+  window.draw chatBox
+  window.draw gui
+  window.draw fpsText
+  if showZonelist: window.draw zonelist
+  window.display()
+
diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim
new file mode 100644
index 000000000..86d0ab360
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim
@@ -0,0 +1,294 @@
+import enet, strutils, idgen, tables, math_helpers,
+  estreams, sg_packets, server_utils, sg_assets, client_helpers
+when appType == "gui":
+  import sfml, sfml_colors, sg_gui,
+    input_helpers, sfml_stuff
+else:
+  import times
+type
+  TCallback = proc(client: PClient; buffer: PBuffer)
+var
+  server: PHost
+  dirServer: PServer
+  standAloneMode = true
+  event: enet.TEvent
+  clientID = newIDGen[int32]()
+  clients = initTable[int32, PClient](64)
+  handlers = initTable[char, TCallback](32)
+
+when appType == "gui":
+  var
+    gui = newGuiContainer()
+    chatBox = gui.newMessageArea(vec2f(15, 550))
+    window = newRenderWindow(videoMode(800, 600, 32), "Sup yo", sfDefaultSTyle)
+    mousepos = newText("", guiFont, 16)
+    fpsText = mousePos.copy()
+    inputClient = newKeyClient(setActive = true)
+  chatBox.sizeVisible = 30
+  mousePos.setColor(Green)
+  fpsText.setposition(vec2f(0, 20))
+  inputClient.registerHandler MouseLeft, down, proc() =
+    gui.click(input_helpers.getMousePos())
+  inputClient.registerHandler MouseMiddle, down, proc() =
+    let pos = input_helpers.getMousePos()
+    mousePos.setString("($1,$2)".format(ff(pos.x), ff(pos.y)))
+    mousePos.setPosition(pos)
+  proc dispMessage(args: varargs[string, `$`]) =
+    var s = ""
+    for it in items(args):
+      s.add it
+    chatbox.add(s)
+  proc dispError(args: varargs[string, `$`]) =
+    var s = ""
+    for it in items(args): s.add(it)
+    chatBox.add(newScChat(kind = CError, text = s))
+else:
+  proc dispMessage(args: varargs[string, `$`]) =
+    var m = ""
+    for it in items(args): m.add(it)
+    echo "<msg> ", m
+  proc dispError(args: varargs[string, `$`]) =
+    var m = ""
+    for it in items(args): m.add(it)
+    echo "**", m
+
+
+var pubChatQueue = newBuffer(1024)
+proc queuePub(sender: PClient, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender.alias, text = msg.text)
+  pubChatQueue.write(HChat)
+  pubChatQueue.pack(chat)
+proc flushPubChat() =
+  if pubChatQueue.isDirty:
+    let packet = pubChatQueue.toPacket(FlagReliable)
+    for id, client in pairs(clients):
+      discard client.peer.send(0.cuchar, packet)
+    pubChatQueue.flush()
+
+handlers[HChat] = proc(client: PClient; buffer: PBuffer) =
+  var chat = readCsChat(buffer)
+
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  #if chat.target != "": ##private
+  #  if alias2client.hasKey(chat.target):
+  #    alias2client[chat.target].forwardPrivate(client, chat.text)
+  #else:
+
+  dispmessage("<", client.alias, "> ", chat.text)
+  queuePub(client, chat)
+
+handlers[HLogin] = proc(client: PClient; buffer: PBuffer) =
+  var info = readCsLogin(buffer)
+  if client.auth:
+    client.sendError "You are already logged in."
+    return
+  client.alias = info.alias
+  client.auth = true
+  var resp = newScLogin(client.id, client.alias, "sessionkeylulz")
+  client.send HLogin, resp
+  client.sendMessage "welcome"
+  dispMessage("Client logged in: ", client)
+
+
+handlers[HFileTransfer] = server_utils.handleFilePartAck
+handlers[HFileChallenge] = server_utils.handleFileChallengeResp
+
+handlers[HZoneJoinReq] = proc(client: PClient; buffer: PBuffer) =
+  var info = readCsZoneJoinReq(buffer)
+  dispmessage "Got zone join request"
+  client.startVerifyingFiles()
+
+
+
+when true:
+  import parseopt, os, json
+
+
+  if enetInit() != 0:
+    quit "Could not initialize ENet"
+
+  var address: enet.TAddress
+
+  block:
+    var zoneCfgFile = "./server_settings.json"
+    for kind, key, val in getopt():
+      case kind
+      of cmdShortOption, cmdLongOption:
+        case key
+        of "f", "file":
+          if fileExists(val):
+            zoneCfgFile = val
+          else:
+            echo("File does not exist: ", val)
+        else:
+          echo("Unknown option: ", key," ", val)
+      else:
+        echo("Unknown option: ", key, " ", val)
+    var jsonSettings = parseFile(zoneCfgFile)
+    let
+      port = uint16(jsonSettings["port"].num)
+      zoneFile = jsonSettings["settings"].str
+      dirServerInfo = jsonSettings["dirserver"]
+
+    address.host = EnetHostAny
+    address.port = port
+
+    var path = getAppDir()/../"data"/zoneFile
+    if not fileExists(path):
+      echo("Zone settings file does not exist: ../data/", zoneFile)
+      echo(path)
+      quit(1)
+
+    discard """block:
+      var
+        TestFile: FileChallengePair
+        contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
+      testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
+      testFile.file = checksumStr(contents)
+      myAssets.add testFile"""
+
+    setCurrentDir getAppDir().parentDir()
+    let zonesettings = readFile(path)
+    var
+      errors: seq[string] = @[]
+    if not loadSettings(zoneSettings, errors):
+      echo("You have errors in your zone settings:")
+      for e in errors: echo("**", e)
+      quit(1)
+    errors.setLen 0
+
+    var pair: FileChallengePair
+    pair.challenge.file = zoneFile
+    pair.challenge.assetType = FZoneCfg
+    pair.challenge.fullLen = zoneSettings.len.int32
+    pair.file = checksumStr(zoneSettings)
+    myAssets.add pair
+
+    allAssets:
+      if not load(asset):
+        echo "Invalid or missing file ", file
+      else:
+        var pair: FileChallengePair
+        pair.challenge.file = file
+        pair.challenge.assetType = assetType
+        pair.challenge.fullLen = getFileSize(
+          expandPath(assetType, file)).int32
+        pair.file = asset.contents
+        myAssets.add pair
+
+    echo "Zone has ", myAssets.len, " associated assets"
+
+    dirServer = newServer()
+
+    dirServer.addHandler HDsMsg, proc(serv: PServer; buffer: PBuffer) =
+      var m = readDsMsg(buffer)
+      dispMessage("<DirServer> ", m.msg)
+    dirServer.addHandler HZoneLogin, proc(serv: PServer; buffer: PBuffer) =
+      let loggedIn = readDsZoneLogin(buffer).status
+      if loggedIn:
+        #dirServerConnected = true
+
+    if dirServerInfo.kind == JArray:
+      var error: string
+      if not dirServer.connect(dirServerInfo[0].str, dirServerInfo[1].num.int16, error):
+        dispError("<DirServer> "&error)
+
+
+  server = enet.createHost(address, 32, 2,  0,  0)
+  if server == nil:
+    quit "Could not create the server!"
+
+  dispMessage("Listening on port ", address.port)
+
+  var
+    serverRunning = true
+  when appType == "gui":
+    var frameRate = newClock()
+    var pubChatDelay = newClock()
+  else:
+    var frameRate = epochTime()
+    var pubChatDelay = frameRate
+
+  while serverRunning:
+    when appType == "gui":
+      let dt = frameRate.restart.asMilliseconds().float / 1000.0
+
+      for event in window.filterEvents():
+        case event.kind
+        of sfml.EvtClosed:
+          window.close()
+          serverRunning = false
+        else:
+          discard
+    else:
+      let dt = epochTime() - frameRate ##is this right? probably not
+      frameRate = epochTime()
+
+    while server.hostService(event, 10) > 0:
+      case event.kind
+      of EvtConnect:
+        var client = newClient()
+        clients[client.id] = client
+
+        event.peer.data = addr client.id
+        client.peer = event.peer
+
+        dispMessage("New client connected ", client)
+
+        var
+          msg = "hello"
+          resp = createPacket(cstring(msg), msg.len + 1, FlagReliable)
+
+        if event.peer.send(0.cuchar, resp) < 0:
+          echo "FAILED"
+        else:
+          echo "Replied"
+      of EvtReceive:
+        let client = clients[cast[ptr int32](event.peer.data)[]]
+
+        var buf = newBuffer(event.packet)
+        let k = buf.readChar()
+        if handlers.hasKey(k):
+          handlers[k](client, buf)
+        else:
+          dispError("Unknown packet from ", client)
+
+        destroy(event.packet)
+      of EvtDisconnect:
+        var
+          id = cast[ptr int32](event.peer.data)[]
+          client = clients[id]
+        if client.isNil:
+          disperror("CLIENT IS NIL!")
+          dispmessage(event.peer.data.isNil)
+        else:
+          dispMessage(clients[id], " disconnected")
+          GCUnref(clients[id])
+          clients.del id
+
+        event.peer.data = nil
+      else:
+        discard
+
+    when appType == "gui":
+      fpsText.setString(ff(1.0/dt))
+      if pubChatDelay.getElapsedTime.asSeconds > 0.25:
+        pubChatDelay.restart()
+        flushPubChat()
+    else:
+      pubChatDelay -= dt
+      if frameRate - pubChatDelay > 0.25:
+        flushPubChat()
+
+    when appType == "gui":
+      window.clear(Black)
+      window.draw(GUI)
+      window.draw chatbox
+      window.draw mousePos
+      window.draw fpstext
+      window.display()
+
+  server.destroy()
+  enetDeinit()
diff --git a/tests/manyloc/keineschweine/enet_server/nakefile.nim b/tests/manyloc/keineschweine/enet_server/nakefile.nim
new file mode 100644
index 000000000..3764c6271
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/nakefile.nim
@@ -0,0 +1,13 @@
+import nake
+nakeimports
+
+const
+  ServerDefines = "-d:NoSFML --forceBuild"
+
+task "server", "build the server":
+  if shell("nim", ServerDefines, "-r", "compile", "enet_server") != 0:
+    quit "Failed to build"
+task "gui", "build the server GUI mode":
+  if shell("nim", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0:
+    quit "Failed to build"
+
diff --git a/tests/manyloc/keineschweine/enet_server/nim.cfg b/tests/manyloc/keineschweine/enet_server/nim.cfg
new file mode 100644
index 000000000..72ef47ee0
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/nim.cfg
@@ -0,0 +1,9 @@
+path = ".."
+path = "../dependencies/sfml"
+path = "../dependencies/enet"
+path = "../dependencies/nake"
+path = "../dependencies/genpacket"
+path = "../lib"
+define = "noChipmunk"
+define = "noSFML"
+
diff --git a/tests/manyloc/keineschweine/enet_server/server_settings.json b/tests/manyloc/keineschweine/enet_server/server_settings.json
new file mode 100644
index 000000000..7d2f1d822
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/server_settings.json
@@ -0,0 +1,8 @@
+{
+ "name": "Alpha Zone",
+ "desc": "Beta Testing",
+ "host": "localhost",
+ "port": 8024,
+ "settings": "alphazone.json",
+ "dirserver":["localhost",2049,"alphazone","skittles"]
+}
diff --git a/tests/manyloc/keineschweine/enet_server/server_utils.nim b/tests/manyloc/keineschweine/enet_server/server_utils.nim
new file mode 100644
index 000000000..3940dcf01
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/server_utils.nim
@@ -0,0 +1,122 @@
+import ../../../../dist/checksums/src/checksums/md5
+
+import enet, sg_packets, estreams, zlib_helpers, client_helpers, strutils,
+  idgen, sg_assets, tables, os
+type
+  PClient* = ref object
+    id*: int32
+    auth*: bool
+    alias*: string
+    peer*: PPeer
+
+  FileChallengePair* = tuple[challenge: ScFileChallenge; file: TChecksumFile]
+  PFileChallengeSequence* = ref TFileChallengeSequence
+  TFileChallengeSequence = object
+    index: int  #which file is active
+    transfer: ScFileTransfer
+    file: ptr FileChallengePair
+var
+  clientID = newIdGen[int32]()
+  myAssets*: seq[FileChallengePair] = @[]
+  fileChallenges = initTable[int32, PFileChallengeSequence](32)
+const FileChunkSize = 256
+
+proc free(client: PClient) =
+  if client.id != 0:
+    fileChallenges.del client.id
+    clientID.del client.id
+proc newClient*(): PClient =
+  new(result, free)
+  result.id = clientID.next()
+  result.alias = "billy"
+
+proc `$`*(client: PClient): string =
+  result = "$1:$2".format(client.id, client.alias)
+
+proc send*[T](client: PClient; pktType: char; pkt: var T) =
+  var buf = newBuffer(128)
+  buf.write pktType
+  buf.pack pkt
+  discard client.peer.send(0.cuchar, buf, flagReliable)
+
+proc sendMessage*(client: PClient; txt: string) =
+  var m = newScChat(CSystem, text = txt)
+  client.send HChat, m
+proc sendError*(client: PClient; error: string) =
+  var m = newScChat(CError, text = error)
+  client.send HChat, m
+
+
+
+
+proc next*(challenge: PFileChallengeSequence, client: PClient)
+proc sendChunk*(challenge: PFileChallengeSequence, client: PClient)
+
+proc startVerifyingFiles*(client: PClient) =
+  var fcs: PFileChallengeSequence
+  new(fcs)
+  fcs.index = -1
+  fileChallenges[client.id] = fcs
+  next(fcs, client)
+
+proc next*(challenge: PFileChallengeSequence, client: PClient) =
+  inc(challenge.index)
+  if challenge.index >= myAssets.len:
+    client.sendMessage "You are cleared to enter"
+    fileChallenges.del client.id
+    return
+  else:
+    echo myAssets.len, "assets"
+  challenge.file = addr myAssets[challenge.index]
+  client.send HFileChallenge, challenge.file.challenge # :rolleyes:
+  echo "sent challenge"
+
+proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) =
+  let size = min(FileChunkSize, challenge.transfer.fileSize - challenge.transfer.pos)
+  challenge.transfer.data.setLen size
+  copyMem(
+    addr challenge.transfer.data[0],
+    addr challenge.file.file.compressed[challenge.transfer.pos],
+    size)
+  client.send HFileTransfer, challenge.transfer
+  echo "chunk sent"
+
+proc startSend*(challenge: PFileChallengeSequence, client: PClient) =
+  challenge.transfer.fileSize = challenge.file.file.compressed.len().int32
+  challenge.transfer.pos = 0
+  challenge.transfer.data = ""
+  challenge.transfer.data.setLen FileChunkSize
+  challenge.sendChunk(client)
+  echo "starting xfer"
+
+## HFileTransfer
+proc handleFilePartAck*(client: PClient; buffer: PBuffer) =
+  echo "got filepartack"
+  var
+    ftrans = readCsFilepartAck(buffer)
+    fcSeq = fileChallenges[client.id]
+  fcSeq.transfer.pos = ftrans.lastPos
+  fcSeq.sendChunk client
+
+## HFileCHallenge
+proc handleFileChallengeResp*(client: PClient; buffer: PBuffer) =
+  echo "got file challenge resp"
+  var
+    fcResp = readCsFileChallenge(buffer)
+    fcSeq = fileChallenges[client.id]
+  let index = $(fcSeq.index + 1) / $(myAssets.len)
+  if fcResp.needFile:
+    client.sendMessage "Sending file... "&index
+    fcSeq.startSend(client)
+  else:
+    var resp = newScChallengeResult(false)
+    if fcResp.checksum == fcSeq.file.file.sum: ##client is good
+      client.sendMessage "Checksum is good. "&index
+      resp.status = true
+      client.send HChallengeResult, resp
+      fcSeq.next(client)
+    else:
+      client.sendMessage "Checksum is bad, sending file... "&index
+      client.send HChallengeResult, resp
+      fcSeq.startSend(client)
+
diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
new file mode 100644
index 000000000..123a4aebb
--- /dev/null
+++ b/tests/manyloc/keineschweine/keineschweine.nim
@@ -0,0 +1,726 @@
+import
+  os, math, strutils, gl, tables,
+  sfml, sfml_audio, sfml_colors, chipmunk, math_helpers,
+  input_helpers, animations, game_objects, sfml_stuff, map_filter,
+  sg_gui, sg_assets, sound_buffer, enet_client
+when defined(profiler):
+  import nimprof
+
+type
+  PPlayer* = ref TPlayer
+  TPlayer* = object
+    id: uint16
+    vehicle: PVehicle
+    spectator: bool
+    alias: string
+    nameTag: PText
+    items: seq[PItem]
+  PVehicle* = ref TVehicle
+  TVehicle* = object
+    body*:      chipmunk.PBody
+    shape*:     chipmunk.PShape
+    record*:   PVehicleRecord
+    sprite*:   PSprite
+    spriteRect*: TIntRect
+    occupant: PPlayer
+    when false:
+      position*: TVector2f
+      velocity*: TVector2f
+      angle*:    float
+  PItem* = ref object
+    record: PItemRecord
+    cooldown: float
+  PLiveBullet* = ref TLiveBullet ##represents a live bullet in the arena
+  TLiveBullet* = object
+    lifetime*: float
+    dead: bool
+    anim*: PAnimation
+    record*: PBulletRecord
+    fromPlayer*: PPlayer
+    trailDelay*: float
+    body: chipmunk.PBody
+    shape: chipmunk.PShape
+include vehicles
+const
+  LGrabbable*  = (1 shl 0).TLayers
+  LBorders*    = (1 shl 1).TLayers
+  LPlayer*     = ((1 shl 2) and LBorders.int).TLayers
+  LEnemy*      = ((1 shl 4) and LBorders.int).TLayers
+  LEnemyFire*  = (LPlayer).TLayers
+  LPlayerFire* = (LEnemy).TLayers
+  CTBullet = 1.TCollisionType
+  CTVehicle= 2.TCollisionType
+  ##temporary constants
+  W_LIMIT = 2.3
+  V_LIMIT = 35
+  MaxLocalBots = 3
+var
+  localPlayer: PPlayer
+  localBots: seq[PPlayer] = @[]
+  activeVehicle: PVehicle
+  myVehicles: seq[PVehicle] = @[]
+  objects: seq[PGameObject] = @[]
+  liveBullets: seq[PLiveBullet] = @[]
+  explosions: seq[PAnimation] = @[]
+  gameRunning = true
+  frameRate = newClock()
+  showStars = off
+  levelArea: TIntRect
+  videoMode: TVideoMode
+  window: PRenderWindow
+  worldView: PView
+  guiView: PView
+  space = newSpace()
+  ingameClient = newKeyClient("ingame")
+  specInputClient = newKeyClient("spec")
+  specGui = newGuiContainer()
+  stars: seq[PSpriteSheet] = @[]
+  playBtn: PButton
+  shipSelect = newGuiContainer()
+  delObjects: seq[int] = @[]
+  showShipSelect = false
+  myPosition: array[0..1, TVector3f] ##for audio positioning
+let
+  nameTagOffset = vec2f(0.0, 1.0)
+when defined(escapeMenuTest):
+  import browsers
+  var
+    escMenu = newGuiContainer(vec2f(100, 100))
+    escMenuOpen = false
+    pos = vec2f(0, 0)
+  escMenu.newButton("Some Website", pos, proc(b: PButton) =
+    openDefaultBrowser(getClientSettings().website))
+  pos.y += 20.0
+  escMenu.newButton("Back to Lobby", pos, proc(b: PButton) =
+    echo "herro")
+  proc toggleEscape() =
+    escMenuOpen = not escMenuOpen
+  ingameClient.registerHandler(KeyEscape, down, toggleEscape)
+  specInputClient.registerHandler(KeyEscape, down, toggleEscape)
+when defined(foo):
+  var mouseSprite: sfml.PCircleShape
+when defined(recordMode):
+  var
+    snapshots: seq[PImage] = @[]
+    isRecording = false
+  proc startRecording() =
+    if snapshots.len > 100: return
+    echo "Started recording"
+    isRecording = true
+  proc stopRecording() =
+    if isRecording:
+      echo "Stopped recording. ", snapshots.len, " images."
+    isRecording = false
+  proc zeroPad*(s: string; minLen: int): string =
+    if s.len < minLen:
+      result = repeat(0, minLen - s.len)
+      result.add s
+    else:
+      result = s
+  var
+    recordButton = newButton(
+      nil, text = "Record", position = vec2f(680, 50),
+      onClick = proc(b: PButton) = startRecording())
+
+proc newNameTag*(text: string): PText =
+  result = newText()
+  result.setFont(guiFont)
+  result.setCharacterSize(14)
+  result.setColor(Red)
+  result.setString(text)
+
+var debugText = newNameTag("Loading...")
+debugText.setPosition(vec2f(0.0, 600.0 - 50.0))
+
+when defined(showFPS):
+  var fpsText = newNameTag("0")
+  #fpsText.setCharacterSize(16)
+  fpsText.setPosition(vec2f(300.0, (800 - 50).float))
+
+proc mouseToSpace*(): TVector =
+  result = window.convertCoords(vec2i(getMousePos()), worldView).sfml2cp()
+
+proc explode*(b: PLiveBullet)
+## TCollisionBeginFunc
+proc collisionBulletPlayer(arb: PArbiter; space: PSpace;
+                            data: pointer): bool{.cdecl.} =
+  var
+    bullet = cast[PLiveBullet](arb.a.data)
+    target = cast[PVehicle](arb.b.data)
+  if target.occupant.isNil or target.occupant == bullet.fromPlayer: return
+  bullet.explode()
+
+proc angularDampingSim(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
+  body.w -= (body.w * 0.98 * dt)
+  body.UpdateVelocity(gravity, damping, dt)
+
+proc initLevel() =
+  loadAllAssets()
+
+  if not space.isNil: space.destroy()
+  space = newSpace()
+  space.addCollisionHandler CTBullet, CTVehicle, collisionBulletPlayer,
+    nil, nil, nil, nil
+
+  let levelSettings = getLevelSettings()
+  levelArea.width = levelSettings.size.x
+  levelArea.height= levelSettings.size.y
+  let borderSeq = @[
+    vector(0, 0), vector(levelArea.width.float, 0.0),
+    vector(levelArea.width.float, levelArea.height.float), vector(0.0, levelArea.height.float)]
+  for i in 0..3:
+    var seg = space.addShape(
+      newSegmentShape(
+        space.staticBody,
+        borderSeq[i],
+        borderSeq[(i + 1) mod 4],
+        8.0))
+    seg.setElasticity 0.96
+    seg.setLayers(LBorders)
+  if levelSettings.starfield.len > 0:
+    showStars = true
+    for sprite in levelSettings.starfield:
+      sprite.tex.setRepeated(true)
+      sprite.sprite.setTextureRect(levelArea)
+      sprite.sprite.setOrigin(vec2f(0, 0))
+      stars.add(sprite)
+  var pos = vec2f(0.0, 0.0)
+  for veh in playableVehicles():
+    shipSelect.newButton(
+      veh.name,
+      position = pos,
+      onClick = proc(b: PButton) =
+        echo "-__-")
+    pos.y += 18.0
+
+
+proc newItem*(record: PItemRecord): PItem =
+  new(result)
+  result.record = record
+proc newItem*(name: string): PItem {.inline.} =
+  return newItem(fetchItm(name))
+proc canUse*(itm: PItem): bool =
+  if itm.cooldown > 0.0: return
+  return true
+proc update*(itm: PItem; dt: float) =
+  if itm.cooldown > 0:
+    itm.cooldown -= dt
+
+proc free(obj: PLiveBullet) =
+  obj.shape.free
+  obj.body.free
+  obj.record = nil
+
+
+template newExplosion(obj, animation) =
+  explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, obj.body.getAngle))
+
+template newExplosion(obj, animation, angle) =
+  explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, angle))
+
+proc explode*(b: PLiveBullet) =
+  if b.dead: return
+  b.dead = true
+  space.removeShape b.shape
+  space.removeBody b.body
+  if not b.record.explosion.anim.isNil:
+    newExplosion(b, b.record.explosion.anim)
+  playSound(b.record.explosion.sound, b.body.getPos())
+
+proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
+  body.UpdateVelocity(gravity, damping, dt)
+
+template getPhysical() {.dirty.} =
+  result.body = space.addBody(newBody(
+    record.physics.mass,
+    record.physics.moment))
+  result.shape = space.addShape(
+    chipmunk.newCircleShape(
+      result.body,
+      record.physics.radius,
+      VectorZero))
+
+proc newBullet*(record: PBulletRecord; fromPlayer: PPlayer): PLiveBullet =
+  new(result, free)
+  result.anim = newAnimation(record.anim, AnimLoop)
+  result.fromPlayer = fromPlayer
+  result.lifetime = record.lifetime
+  result.record = record
+  getPhysical()
+  if fromPlayer == localPlayer:
+    result.shape.setLayers(LPlayerFire)
+  else:
+    result.shape.setLayers(LEnemyFire)
+  result.shape.setCollisionType CTBullet
+  result.shape.setUserData(cast[ptr TLiveBullet](result))
+  let
+    fireAngle = fromPlayer.vehicle.body.getAngle()
+    fireAngleV = vectorForAngle(fireAngle)
+  result.body.setAngle fireAngle
+  result.body.setPos(fromPlayer.vehicle.body.getPos() + (fireAngleV * fromPlayer.vehicle.shape.getCircleRadius()))
+  #result.body.velocityFunc = bulletUpdate
+  result.body.setVel((fromPlayer.vehicle.body.getVel() * record.inheritVelocity) + (fireAngleV * record.baseVelocity))
+
+proc update*(b: PLiveBullet; dt: float): bool =
+  if b.dead: return true
+  b.lifetime -= dt
+  b.anim.next(dt)
+  #b.anim.sprite.setPosition(b.body.getPos.floor())
+  b.anim.setPos(b.body.getPos)
+  b.anim.setAngle(b.body.getAngle())
+  if b.lifetime <= 0.0:
+    b.explode()
+    return true
+  b.trailDelay -= dt
+  if b.trailDelay <= 0.0:
+    b.trailDelay += b.record.trail.timer
+    if b.record.trail.anim.isNil: return
+    newExplosion(b, b.record.trail.anim)
+proc draw*(window: PRenderWindow; b: PLiveBullet) {.inline.} =
+  draw(window, b.anim.sprite)
+
+
+proc free*(veh: PVehicle) =
+  ("Destroying vehicle " & veh.record.name).echo
+  destroy(veh.sprite)
+  if veh.shape.isNil: "Free'd vehicle's shape was NIL!".echo
+  else: space.removeShape(veh.shape)
+  if veh.body.isNil: "Free'd vehicle's BODY was NIL!".echo
+  else: space.removeBody(veh.body)
+  veh.body.free()
+  veh.shape.free()
+  veh.sprite = nil
+  veh.body = nil
+  veh.shape  = nil
+
+
+proc newVehicle*(record: PVehicleRecord): PVehicle =
+  echo("Creating " & record.name)
+  new(result, free)
+  result.record = record
+  result.sprite = result.record.anim.spriteSheet.sprite.copy()
+  result.spriteRect = result.sprite.getTextureRect()
+  getPhysical()
+  result.body.setAngVelLimit W_LIMIT
+  result.body.setVelLimit result.record.handling.topSpeed
+  result.body.velocityFunc = angularDampingSim
+  result.shape.setCollisionType CTVehicle
+  result.shape.setUserData(cast[ptr TVehicle](result))
+proc newVehicle*(name: string): PVehicle =
+  result = newVehicle(fetchVeh(name))
+
+proc update*(obj: PVehicle) =
+  obj.sprite.setPosition(obj.body.getPos.floor)
+  obj.spriteRect.left = (((-obj.body.getAngVel + W_LIMIT) / (W_LIMIT*2.0) * (obj.record.anim.spriteSheet.cols - 1).float).floor.int * obj.record.anim.spriteSheet.framew).cint
+  obj.spriteRect.top = ((obj.offsetAngle.wmod(TAU) / TAU) * obj.record.anim.spriteSheet.rows.float).floor.cint * obj.record.anim.spriteSheet.frameh.cint
+  obj.sprite.setTextureRect(obj.spriteRect)
+
+
+proc newPlayer*(alias: string = "poo"): PPlayer =
+  new(result)
+  result.spectator = true
+  result.alias     = alias
+  result.nameTag   = newNameTag(result.alias)
+  result.items     = @[]
+proc updateItems*(player: PPlayer, dt: float) =
+  for i in items(player.items):
+    update(i, dt)
+proc addItem*(player: PPlayer; name: string) =
+  player.items.add newItem(name)
+proc useItem*(player: PPlayer; slot: int) =
+  if slot > player.items.len - 1: return
+  let item = player.items[slot]
+  if item.canUse:
+    item.cooldown += item.record.cooldown
+    let b = newBullet(item.record.bullet, player)
+    liveBullets.add(b)
+    sound_buffer.playSound(item.record.useSound, b.body.getPos)
+
+proc update*(obj: PPlayer) =
+  if not obj.spectator:
+    obj.vehicle.update()
+    obj.nameTag.setPosition(obj.vehicle.body.getPos.floor + (nameTagOffset * (obj.vehicle.record.physics.radius + 5).cfloat))
+
+proc draw(window: PRenderWindow, player: PPlayer) {.inline.} =
+  if not player.spectator:
+    if player.vehicle != nil:
+      window.draw(player.vehicle.sprite)
+    window.draw(player.nameTag)
+
+proc setVehicle(p: PPlayer; v: PVehicle) =
+  p.vehicle = v  #sorry mom, this is just how things worked out ;(
+  if not v.isNil:
+    v.occupant = p
+
+proc createBot() =
+  if localBots.len < MaxLocalBots:
+    var bot = newPlayer("Dodo Brown")
+    bot.setVehicle(newVehicle("Turret0"))
+    if bot.isNil:
+      echo "BOT IS NIL"
+      return
+    elif bot.vehicle.isNil:
+      echo "BOT VEH IS NIL"
+      return
+    localBots.add(bot)
+    bot.vehicle.body.setPos(vector(100, 100))
+    echo "new bot at ", $bot.vehicle.body.getPos()
+
+var inputCursor = newVertexArray(sfml.Lines, 2)
+inputCursor[0].position = vec2f(10.0, 10.0)
+inputCursor[1].position = vec2f(50.0, 90.0)
+
+proc hasVehicle(p: PPlayer): bool {.inline.} =
+  result = not p.spectator and not p.vehicle.isNil
+
+proc setMyVehicle(v: PVehicle) {.inline.} =
+  activeVehicle = v
+  localPlayer.setVehicle v
+
+proc unspec() =
+  var veh = newVehicle("Turret0")
+  if not veh.isNil:
+    setMyVehicle veh
+    localPlayer.spectator = false
+    ingameClient.setActive
+    veh.body.setPos vector(100, 100)
+    veh.shape.setLayers(LPlayer)
+    when defined(debugWeps):
+      localPlayer.addItem("Mass Driver")
+      localPlayer.addItem("Neutron Bomb")
+      localPlayer.additem("Dem Lasers")
+      localPlayer.addItem("Mold Spore Beam")
+      localPlayer.addItem("Genericorp Mine")
+      localPlayer.addItem("Gravitic Bomb")
+proc spec() =
+  setMyVehicle nil
+  localPlayer.spectator = true
+  specInputClient.setActive
+
+var
+  specLimiter = newClock()
+  timeBetweenSpeccing = 1.0 #seconds
+proc toggleSpec() {.inline.} =
+  if specLimiter.getElapsedTime.asSeconds < timeBetweenSpeccing:
+    return
+  specLimiter.restart()
+  if localPlayer.isNil:
+    echo("OMG WTF PLAYER IS NILL!!")
+  elif localPlayer.spectator: unspec()
+  else: spec()
+
+proc addObject*(name: string) =
+  var o = newObject(name)
+  if not o.isNil:
+    echo "Adding object ", o
+    discard space.addBody(o.body)
+    discard space.addShape(o.shape)
+    o.shape.setLayers(LGrabbable)
+    objects.add(o)
+proc explode(obj: PGameObject) =
+  echo obj, " exploded"
+  let ind = objects.find(obj)
+  if ind != -1:
+    delObjects.add ind
+proc update(obj: PGameObject; dt: float) =
+  if not(obj.anim.next(dt)):
+    obj.explode()
+  else:
+    obj.anim.setPos(obj.body.getPos)
+    obj.anim.setAngle(obj.body.getAngle)
+
+proc toggleShipSelect() =
+  showShipSelect = not showShipSelect
+proc handleLClick() =
+  let pos = input_helpers.getMousePos()
+  when defined(escapeMenuTest):
+    if escMenuOpen:
+      escMenu.click(pos)
+      return
+  if showShipSelect:
+    shipSelect.click(pos)
+  if localPlayer.spectator:
+    specGui.click(pos)
+
+ingameClient.registerHandler(KeyF12, down, proc() = toggleSpec())
+ingameClient.registerHandler(KeyF11, down, toggleShipSelect)
+ingameClient.registerHandler(MouseLeft, down, handleLClick)
+when defined(recordMode):
+  if not dirExists("data/snapshots"):
+    createDir("data/snapshots")
+  ingameClient.registerHandler(keynum9, down, proc() =
+    if not isRecording: startRecording()
+    else: stopRecording())
+  ingameClient.registerHandler(keynum0, down, proc() =
+    if snapshots.len > 0 and not isRecording:
+      echo "Saving images (LOL)"
+      for i in 0..high(snapshots):
+        if not(snapshots[i].save("data/snapshots/image"&(zeroPad($i, 3))&".jpg")):
+          echo "Could not save"
+        snapshots[i].destroy()
+      snapshots.setLen 0)
+when defined(DebugKeys):
+  ingameClient.registerHandler MouseRight, down, proc() =
+    echo($activevehicle.body.getAngle.vectorForAngle())
+  ingameClient.registerHandler KeyBackslash, down, proc() =
+    createBot()
+  ingameClient.registerHandler(KeyNum1, down, proc() =
+    if localPlayer.items.len == 0:
+      localPlayer.addItem("Mass Driver")
+      echo "Gave you a mass driverz")
+  ingameClient.registerHandler(KeyL, down, proc() =
+    echo("len(livebullets) = ", len(livebullets)))
+  ingameClient.registerHandler(KeyRShift, down, proc() =
+    if keyPressed(KeyR):
+      echo("Friction: ", ff(activeVehicle.shape.getFriction()))
+      echo("Damping: ", ff(space.getDamping()))
+    elif keypressed(KeyM):
+      echo("Mass: ", activeVehicle.body.getMass.ff())
+      echo("Moment: ", activeVehicle.body.getMoment.ff())
+    elif keypressed(KeyI):
+      echo(repr(activeVehicle.record))
+    elif keyPressed(KeyH):
+      activeVehicle.body.setPos(vector(100.0, 100.0))
+      activeVehicle.body.setVel(VectorZero)
+    elif keyPressed(KeyComma):
+      activeVehicle.body.setPos mouseToSpace())
+  ingameClient.registerHandler(KeyY, down, proc() =
+    const looloo = ["Asteroid1", "Asteroid2"]
+    addObject(looloo[rand(looloo.len)]))
+  ingameClient.registerHandler(KeyO, down, proc() =
+    if objects.len == 0:
+      echo "Objects is empty"
+      return
+    for i, o in pairs(objects):
+      echo i, " ", o)
+  ingameClient.registerHandler(KeyLBracket, down, sound_buffer.report)
+  var
+    mouseJoint: PConstraint
+    mouseBody = space.addBody(newBody(CpInfinity, CpInfinity))
+  ingameClient.registerHandler(MouseMiddle, down, proc() =
+    var point = mouseToSpace()
+    var shape = space.pointQueryFirst(point, LGrabbable, 0)
+    if not mouseJoint.isNil:
+      space.removeConstraint mouseJoint
+      mouseJoint.destroy()
+      mouseJoint = nil
+    if shape.isNil:
+      return
+    let body = shape.getBody()
+    mouseJoint = space.addConstraint(
+      newPivotJoint(mouseBody, body, VectorZero, body.world2local(point)))
+    mouseJoint.maxForce = 50000.0
+    mouseJoint.errorBias = pow(1.0 - 0.15, 60))
+
+var specCameraSpeed = 5.0
+specInputClient.registerHandler(MouseLeft, down, handleLClick)
+specInputClient.registerHandler(KeyF11, down, toggleShipSelect)
+specInputClient.registerHandler(KeyF12, down, proc() = toggleSpec())
+specInputClient.registerHandler(KeyLShift, down, proc() = specCameraSpeed *= 2)
+specInputClient.registerHandler(KeyLShift, up, proc() = specCameraSpeed /= 2)
+
+specInputClient.registerHandler(KeyP, down, proc() =
+  echo("addObject(solar mold)")
+  addObject("Solar Mold"))
+
+proc resetForcesCB(body: PBody; data: pointer) {.cdecl.} =
+  body.resetForces()
+
+var frameCount= 0
+proc mainUpdate(dt: float) =
+  if localPlayer.spectator:
+    if keyPressed(KeyLeft):
+      worldView.move(vec2f(-1.0, 0.0) * specCameraSpeed)
+    elif keyPressed(KeyRight):
+      worldView.move(vec2f( 1.0, 0.0) * specCameraSpeed)
+    if keyPressed(KeyUp):
+      worldView.move(vec2f(0.0, -1.0) * specCameraSpeed)
+    elif keyPressed(KeyDown):
+      worldView.move(vec2f(0.0,  1.0) * specCameraSpeed)
+  elif not activeVehicle.isNil:
+    if keyPressed(KeyUp):
+      activeVehicle.accel(dt)
+    elif keyPressed(KeyDown):
+      activeVehicle.reverse(dt)
+    if keyPressed(KeyRight):
+      activeVehicle.turn_right(dt)
+    elif keyPressed(KeyLeft):
+      activeVehicle.turn_left(dt)
+    if keyPressed(Keyz):
+      activeVehicle.strafe_left(dt)
+    elif keyPressed(Keyx):
+      activeVehicle.strafe_right(dt)
+    if keyPressed(KeyLControl):
+      localPlayer.useItem 0
+    if keyPressed(KeyTab):
+      localPlayer.useItem 1
+    if keyPressed(KeyQ):
+      localPlayer.useItem 2
+    if keyPressed(KeyW):
+      localPlayer.useItem 3
+    if keyPressed(KeyA):
+      localPlayer.useItem 4
+    if keyPressed(sfml.KeyS):
+      localPlayer.useItem 5
+    if keyPressed(KeyD):
+      localPlayer.useItem 6
+    worldView.setCenter(activeVehicle.body.getPos.floor)#cp2sfml)
+
+  if localPlayer != nil:
+    localPlayer.update()
+    localPlayer.updateItems(dt)
+  for b in localBots:
+    b.update()
+
+  for o in items(objects):
+    o.update(dt)
+  for i in countdown(high(delObjects), 0):
+    objects.del i
+  delObjects.setLen 0
+
+  var i = 0
+  while i < len(liveBullets):
+    if liveBullets[i].update(dt):
+      liveBullets.del i
+    else:
+      inc i
+  i = 0
+  while i < len(explosions):
+    if explosions[i].next(dt): inc i
+    else: explosions.del i
+
+  when defined(DebugKeys):
+    mouseBody.setPos(mouseToSpace())
+
+  space.step(dt)
+  space.eachBody(resetForcesCB, nil)
+
+  when defined(foo):
+    var coords = window.convertCoords(vec2i(getMousePos()), worldView)
+    mouseSprite.setPosition(coords)
+
+  if localPlayer != nil and localPlayer.vehicle != nil:
+    let
+      pos = localPlayer.vehicle.body.getPos()
+      ang = localPlayer.vehicle.body.getAngle.vectorForAngle()
+    myPosition[0].x = pos.x
+    myPosition[0].z = pos.y
+    myPosition[1].x = ang.x
+    myPosition[1].z = ang.y
+    listenerSetPosition(myPosition[0])
+    listenerSetDirection(myPosition[1])
+
+  inc frameCount
+  when defined(showFPS):
+    if frameCount mod 60 == 0:
+      fpsText.setString($(1.0/dt).round)
+  if frameCount mod 250 == 0:
+    updateSoundBuffer()
+    frameCount = 0
+
+proc mainRender() =
+  window.clear(Black)
+  window.setView(worldView)
+
+  if showStars:
+    for star in stars:
+      window.draw(star.sprite)
+  window.draw(localPlayer)
+
+  for b in localBots:
+    window.draw(b)
+  for o in objects:
+    window.draw(o)
+
+  for b in explosions: window.draw(b)
+  for b in liveBullets: window.draw(b)
+
+  when defined(Foo):
+    window.draw(mouseSprite)
+
+  window.setView(guiView)
+
+  when defined(EscapeMenuTest):
+    if escMenuOpen:
+      window.draw escMenu
+  when defined(showFPS):
+    window.draw(fpsText)
+  when defined(recordMode):
+    window.draw(recordButton)
+
+  if localPlayer.spectator:
+    window.draw(specGui)
+  if showShipSelect: window.draw shipSelect
+  window.display()
+
+  when defined(recordMode):
+    if isRecording:
+      if snapshots.len < 100:
+        if frameCount mod 5 == 0:
+          snapshots.add(window.capture())
+      else: stopRecording()
+
+proc readyMainState() =
+  specInputClient.setActive()
+
+when true:
+  import parseopt
+
+  localPlayer = newPlayer()
+  lobbyInit()
+
+  videoMode = getClientSettings().resolution
+  window = newRenderWindow(videoMode, "sup", sfDefaultStyle)
+  window.setFrameRateLimit 60
+
+  worldView = window.getView.copy()
+  guiView = worldView.copy()
+  shipSelect.setPosition vec2f(665.0, 50.0)
+
+  when defined(foo):
+    mouseSprite = sfml.newCircleShape(14)
+    mouseSprite.setFillColor Transparent
+    mouseSprite.setOutlineColor RoyalBlue
+    mouseSprite.setOutlineThickness 1.4
+    mouseSprite.setOrigin vec2f(14, 14)
+
+  lobbyReady()
+  playBtn = specGui.newButton(
+    "Unspec - F12", position = vec2f(680.0, 8.0), onClick = proc(b: PButton) =
+      toggleSpec())
+
+  block:
+    var bPlayOffline = false
+    for kind, key, val in getopt():
+      case kind
+      of cmdArgument:
+        if key == "offline": bPlayOffline = true
+      else:
+        echo "Invalid argument ", key, " ", val
+    if bPlayOffline:
+      playoffline(nil)
+
+  gameRunning = true
+  while gameRunning:
+    for event in window.filterEvents:
+      if event.kind == EvtClosed:
+        gameRunning = false
+        break
+      elif event.kind == EvtMouseWheelMoved and getActiveState() == Field:
+        if event.mouseWheel.delta == 1:
+          worldView.zoom(0.9)
+        else:
+          worldView.zoom(1.1)
+    let dt = frameRate.restart.asMilliSeconds().float / 1000.0
+    case getActiveState()
+    of Field:
+      mainUpdate(dt)
+      mainRender()
+    of Lobby:
+      lobbyUpdate(dt)
+      lobbyDraw(window)
+    else:
+      initLevel()
+      echo("Done? lol")
+      doneWithSaidTransition()
+      readyMainState()
diff --git a/tests/manyloc/keineschweine/keineschweine.nim.cfg b/tests/manyloc/keineschweine/keineschweine.nim.cfg
new file mode 100644
index 000000000..a670e2b77
--- /dev/null
+++ b/tests/manyloc/keineschweine/keineschweine.nim.cfg
@@ -0,0 +1,10 @@
+path = "lib"
+path = "dependencies/sfml"
+path = "dependencies/chipmunk"
+path = "dependencies/nake"
+path = "dependencies/enet"
+path = "dependencies/genpacket"
+path = "enet_server"
+debugger = off
+warning[SmallLshouldNotBeUsed] = off
+mm = refc
diff --git a/tests/manyloc/keineschweine/lib/animations.nim b/tests/manyloc/keineschweine/lib/animations.nim
new file mode 100644
index 000000000..a021005f0
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/animations.nim
@@ -0,0 +1,75 @@
+import
+  math,
+  sfml, chipmunk,
+  sg_assets, sfml_stuff, math_helpers
+type
+  PAnimation* = ref TAnimation
+  TAnimation* = object
+    sprite*: PSprite
+    record*: PAnimationRecord
+    delay*: float
+    index*: int
+    direction*: int
+    spriteRect*: TIntRect
+    style*: TAnimationStyle
+  TAnimationStyle* = enum
+    AnimLoop = 0'i8, AnimBounce, AnimOnce
+
+proc setPos*(obj: PAnimation; pos: TVector) {.inline.}
+proc setPos*(obj: PAnimation; pos: TVector2f) {.inline.}
+proc setAngle*(obj: PAnimation; radians: float) {.inline.}
+
+proc free*(obj: PAnimation) =
+  obj.sprite.destroy()
+  obj.record = nil
+
+proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle): PAnimation =
+  new(result, free)
+  result.sprite = src.spriteSheet.sprite.copy()
+  result.record = src
+  result.delay = src.delay
+  result.index = 0
+  result.direction = 1
+  result.spriteRect = result.sprite.getTextureRect()
+  result.style = style
+proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle;
+                    pos: TVector2f; angle: float): PAnimation =
+  result = newAnimation(src, style)
+  result.setPos pos
+  setAngle(result, angle)
+
+proc next*(obj: PAnimation; dt: float): bool {.discardable.} =
+  ## step the animation. Returns false if the object is out of frames
+  result = true
+  obj.delay -= dt
+  if obj.delay <= 0.0:
+    obj.delay += obj.record.delay
+    obj.index += obj.direction
+    #if obj.index > (obj.record.spriteSheet.cols - 1) or obj.index < 0:
+    if not(obj.index in 0..(obj.record.spriteSheet.cols - 1)):
+      case obj.style
+      of AnimOnce:
+        return false
+      of AnimBounce:
+        obj.direction *= -1
+        obj.index += obj.direction * 2
+      of AnimLoop:
+        obj.index = 0
+    obj.spriteRect.left = obj.index.cint * obj.record.spriteSheet.frameW.cint
+    obj.sprite.setTextureRect obj.spriteRect
+
+proc setPos*(obj: PAnimation; pos: TVector) =
+  setPosition(obj.sprite, pos.floor())
+proc setPos*(obj: PAnimation; pos: TVector2f) =
+  setPosition(obj.sprite, pos)
+proc setAngle*(obj: PAnimation; radians: float)  =
+  let rads = (radians + obj.record.angle).wmod(TAU)
+  if obj.record.spriteSheet.rows > 1:
+    ## (rotation percent * rows).floor * frameheight
+    obj.spriteRect.top = (rads / TAU * obj.record.spriteSheet.rows.float).floor.cint * obj.record.spriteSheet.frameh.cint
+    obj.sprite.setTextureRect obj.spriteRect
+  else:
+    setRotation(obj.sprite, degrees(rads)) #stupid sfml, who uses degrees these days? -__-
+
+proc draw*(window: PRenderWindow; obj: PAnimation) {.inline.} =
+  window.draw(obj.sprite)
diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim
new file mode 100644
index 000000000..b21e67cf7
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/client_helpers.nim
@@ -0,0 +1,144 @@
+import ../../../../dist/checksums/src/checksums/md5
+
+import
+  tables, sg_packets, enet, estreams, sg_gui, sfml,
+  zlib_helpers, sg_assets, os
+type
+  PServer* = ptr TServer
+  TServer* = object
+    connected*: bool
+    addy: enet.TAddress
+    host*: PHost
+    peer*: PPeer
+    handlers*: Table[char, TScPktHandler]
+  TScPktHandler* = proc(serv: PServer; buffer: PBuffer)
+  TFileTransfer = object
+    fileName: string
+    assetType: TAssetType
+    fullLen: int
+    pos: int32
+    data: string
+    readyToSave: bool
+var
+  currentFileTransfer: TFileTransfer
+  downloadProgress* = newButton(nil, "", vec2f(0,0), nil)
+currentFileTransfer.data = ""
+
+proc addHandler*(serv: PServer; packetType: char; handler: TScPktHandler) =
+  serv.handlers[packetType] = handler
+
+proc newServer*(): PServer =
+  result = cast[PServer](alloc0(sizeof(TServer)))
+  result.connected = false
+  result.host = createHost(nil, 1, 2, 0, 0)
+  result.handlers = initTable[char, TScPktHandler](32)
+
+proc connect*(serv: PServer; host: string; port: int16; error: var string): bool =
+  if setHost(serv.addy, host) != 0:
+    error = "Could not resolve host "
+    error.add host
+    return false
+  serv.addy.port = port.cushort
+  serv.peer = serv.host.connect(serv.addy, 2, 0)
+  if serv.peer.isNil:
+    error = "Could not connect to host "
+    error.add host
+    return false
+  return true
+
+proc send*[T](serv: PServer; packetType: char; pkt: var T) =
+  if serv.connected:
+    var b = newBuffer(100)
+    b.write packetType
+    b.pack pkt
+    serv.peer.send(0.cuchar, b, FlagUnsequenced)
+
+proc sendPubChat*(server: PServer; msg: string) =
+  var chat = newCsChat("", msg)
+  server.send HChat, chat
+
+proc handlePackets*(server: PServer; buf: PBuffer) =
+  while not buf.atEnd():
+    let typ = readChar(buf)
+    if server.handlers.hasKey(typ):
+      server.handlers[typ](server, buf)
+    else:
+      break
+
+proc updateFileProgress*() =
+  let progress = currentFileTransfer.pos / currentFileTransfer.fullLen
+  downloadProgress.bg.setSize(vec2f(progress * 100, 20))
+  downloadProgress.setString($currentFileTransfer.pos & '/' & $currentFileTransfer.fullLen)
+
+## HFileTransfer
+proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) =
+  var
+    f = readScFileTransfer(buffer)
+  updateFileProgress()
+  if not(f.pos == currentFileTransfer.pos):
+    echo "returning early from filepartrecv"
+    return ##issues, probably
+  if currentFileTransfer.data.len == 0:
+    echo "setting current file size"
+    currentFileTransfer.data.setLen f.fileSize
+  let len = f.data.len
+  copymem(
+    addr currentFileTransfer.data[f.pos],
+    addr f.data[0],
+    len)
+  currentFileTransfer.pos = f.pos + len.int32
+  if currentFileTransfer.pos == f.fileSize: #file should be done, rizzight
+    currentFileTransfer.data = uncompress(
+      currentFileTransfer.data, currentFileTransfer.fullLen)
+    currentFileTransfer.readyToSave = true
+    var resp: CsFileChallenge
+    resp.checksum = toMD5(currentFileTransfer.data)
+    serv.send HFileChallenge, resp
+    echo "responded with challenge (ready to save)"
+  else:
+    var resp = newCsFilepartAck(currentFileTransfer.pos)
+    serv.send HFileTransfer, resp
+    echo "responded for next part"
+
+proc saveCurrentFile() =
+  if not currentFileTransfer.readyToSave: return
+  let
+    path = expandPath(currentFileTransfer.assetType, currentFileTransfer.fileName)
+    parent = parentDir(path)
+  if not dirExists(parent):
+    createDir(parent)
+    echo("Created dir")
+  writeFile path, currentFIleTransfer.data
+  echo "Write file"
+
+## HChallengeResult
+proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) =
+  var res = readScChallengeResult(buffer).status
+  echo "got challnege result: ", res
+  if res and currentFileTransfer.readyToSave:
+    echo "saving"
+    saveCurrentFile()
+  else:
+    currentFileTransfer.readyToSave = false
+    currentFileTransfer.pos = 0
+    echo "REsetting current file"
+
+## HFileCHallenge
+proc handleFileChallenge*(serv: PServer; buffer: PBuffer) =
+  var
+    challenge = readScFileChallenge(buffer)
+    path = expandPath(challenge)
+    resp: CsFileChallenge
+  if not fileExists(path):
+    resp.needFile = true
+    echo "Got file challenge, need file."
+  else:
+    resp.checksum = toMD5(readFile(path))
+    echo "got file challenge, sending sum"
+  currentFileTransfer.fileName = challenge.file
+  currentFileTransfer.assetType = challenge.assetType
+  currentFileTransfer.fullLen = challenge.fullLen.int
+  currentFileTransfer.pos = 0
+  currentFileTransfer.data.setLen 0
+  currentFileTransfer.readyToSave = false
+  serv.send HFileChallenge, resp
diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim
new file mode 100644
index 000000000..c5e45e0e7
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/estreams.nim
@@ -0,0 +1,120 @@
+import endians
+
+proc swapEndian16*(outp, inp: pointer) =
+  ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
+  ## contain at least 2 bytes.
+  var i = cast[cstring](inp)
+  var o = cast[cstring](outp)
+  o[0] = i[1]
+  o[1] = i[0]
+
+import enet
+
+type
+  PBuffer* = ref object
+    data*: string
+    pos: int
+
+proc free(b: PBuffer) =
+  GCunref b.data
+proc newBuffer*(len: int): PBuffer =
+  new result, free
+  result.data = newString(len)
+proc newBuffer*(pkt: PPacket): PBuffer =
+  new result, free
+  result.data = newString(pkt.dataLength)
+  copyMem(addr result.data[0], pkt.data, pkt.dataLength)
+proc toPacket*(buffer: PBuffer; flags: TPacketFlag): PPacket =
+  buffer.data.setLen buffer.pos
+  result = createPacket(cstring(buffer.data), cast[csize_t](buffer.pos), flags)
+
+proc isDirty*(buffer: PBuffer): bool {.inline.} =
+  result = (buffer.pos != 0)
+proc atEnd*(buffer: PBuffer): bool {.inline.} =
+  result = (buffer.pos == buffer.data.len)
+proc reset*(buffer: PBuffer) {.inline.} =
+  buffer.pos = 0
+
+proc flush*(buf: PBuffer) =
+  buf.pos = 0
+  buf.data.setLen(0)
+proc send*(peer: PPeer; channel: cuchar; buf: PBuffer; flags: TPacketFlag): cint {.discardable.} =
+  result = send(peer, channel, buf.toPacket(flags))
+
+proc read*[T: int16|uint16](buffer: PBuffer; outp: var T) =
+  bigEndian16(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 2
+proc read*[T: float32|int32|uint32](buffer: PBuffer; outp: var T) =
+  bigEndian32(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 4
+proc read*[T: float64|int64|uint64](buffer: PBuffer; outp: var T) =
+  bigEndian64(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 8
+proc read*[T: int8|uint8|byte|bool|char](buffer: PBuffer; outp: var T) =
+  copyMem(addr outp, addr buffer.data[buffer.pos], 1)
+  inc buffer.pos, 1
+
+proc writeBE*[T: int16|uint16](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 2
+  bigEndian16(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 2
+proc writeBE*[T: int32|uint32|float32](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 4
+  bigEndian32(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 4
+proc writeBE*[T: int64|uint64|float64](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 8
+  bigEndian64(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 8
+proc writeBE*[T: char|int8|uint8|byte|bool](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 1
+  copyMem(addr buffer.data[buffer.pos], addr val, 1)
+  inc buffer.pos, 1
+
+
+proc write*(buffer: PBuffer; val: var string) =
+  var length = len(val).uint16
+  writeBE buffer, length
+  setLen buffer.data, buffer.pos + length.int
+  copyMem(addr buffer.data[buffer.pos], addr val[0], length.int)
+  inc buffer.pos, length.int
+proc write*[T: SomeNumber|bool|char|byte](buffer: PBuffer; val: sink T) =
+  var v: T
+  v = val
+  writeBE buffer, v
+
+proc readInt8*(buffer: PBuffer): int8 =
+  read buffer, result
+proc readInt16*(buffer: PBuffer): int16 =
+  read buffer, result
+proc readInt32*(buffer: PBuffer): int32 =
+  read buffer, result
+proc readInt64*(buffer: PBuffer): int64 =
+  read buffer, result
+proc readFloat32*(buffer: PBuffer): float32 =
+  read buffer, result
+proc readFloat64*(buffer: PBuffer): float64 =
+  read buffer, result
+proc readStr*(buffer: PBuffer): string =
+  let len = readInt16(buffer).int
+  result = ""
+  if len > 0:
+    result.setLen len
+    copyMem(addr result[0], addr buffer.data[buffer.pos], len)
+    inc buffer.pos, len
+proc readChar*(buffer: PBuffer): char {.inline.} = return readInt8(buffer).char
+proc readBool*(buffer: PBuffer): bool {.inline.} = return readInt8(buffer).bool
+
+
+when false:
+  var b = newBuffer(100)
+  var str = "hello there"
+  b.write str
+  echo(repr(b))
+  b.pos = 0
+  echo(repr(b.readStr()))
+
+  b.flush()
+  echo "flushed"
+  b.writeC([1,2,3])
+  echo(repr(b))
diff --git a/tests/manyloc/keineschweine/lib/game_objects.nim b/tests/manyloc/keineschweine/lib/game_objects.nim
new file mode 100644
index 000000000..277ffb6cb
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/game_objects.nim
@@ -0,0 +1,34 @@
+import chipmunk, sfml, animations, sg_assets
+type
+  PGameObject* = ref TGameObject
+  TGameObject = object
+    body*: chipmunk.PBody
+    shape*: chipmunk.PShape
+    record*: PObjectRecord
+    anim*: PAnimation
+
+
+proc `$`*(obj: PGameObject): string =
+  result = "<Object "
+  result.add obj.record.name
+  result.add ' '
+  result.add($obj.body.getpos())
+  result.add '>'
+proc free(obj: PGameObject) =
+  obj.record = nil
+  free(obj.anim)
+  obj.anim = nil
+proc newObject*(record: PObjectRecord): PGameObject =
+  if record.isNil: return nil
+  new(result, free)
+  result.record = record
+  result.anim = newAnimation(record.anim, AnimLoop)
+  when false:
+    result.sprite = record.anim.spriteSheet.sprite.copy()
+  result.body = newBody(result.record.physics.mass, 10.0)
+  result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, VectorZero)
+  result.body.setPos(vector(100, 100))
+proc newObject*(name: string): PGameObject =
+  result = newObject(fetchObj(name))
+proc draw*(window: PRenderWindow, obj: PGameObject) {.inline.} =
+  window.draw(obj.anim.sprite)
diff --git a/tests/manyloc/keineschweine/lib/gl.nim b/tests/manyloc/keineschweine/lib/gl.nim
new file mode 100644
index 000000000..b634a96cf
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/gl.nim
@@ -0,0 +1,1536 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#
+#******************************************************************************
+# Converted to Delphi by Tom Nuydens (tom@delphi3d.net)
+# For the latest updates, visit Delphi3D: http://www.delphi3d.net
+#******************************************************************************
+
+when defined(windows):
+  {.push, callconv: stdcall.}
+else:
+  {.push, callconv: cdecl.}
+when defined(windows):
+  const
+    dllname* = "opengl32.dll"
+elif defined(macosx):
+  const
+    dllname* = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
+else:
+  const
+    dllname* = "libGL.so.1"
+type
+  PGLenum* = ptr TGLenum
+  PGLboolean* = ptr TGLboolean
+  PGLbitfield* = ptr TGLbitfield
+  TGLbyte* = int8
+  PGLbyte* = ptr TGlbyte
+  PGLshort* = ptr TGLshort
+  PGLint* = ptr TGLint
+  PGLsizei* = ptr TGLsizei
+  PGLubyte* = ptr TGLubyte
+  PGLushort* = ptr TGLushort
+  PGLuint* = ptr TGLuint
+  PGLfloat* = ptr TGLfloat
+  PGLclampf* = ptr TGLclampf
+  PGLdouble* = ptr TGLdouble
+  PGLclampd* = ptr TGLclampd
+  PGLvoid* = pointer
+  PPGLvoid* = ptr PGLvoid
+  TGLenum* = cint
+  TGLboolean* = bool
+  TGLbitfield* = cint
+  TGLshort* = int16
+  TGLint* = cint
+  TGLsizei* = int
+  TGLubyte* = int8
+  TGLushort* = int16
+  TGLuint* = cint
+  TGLfloat* = float32
+  TGLclampf* = float32
+  TGLdouble* = float
+  TGLclampd* = float
+
+const                         # Version
+  GL_VERSION_1_1* = 1         # AccumOp
+  constGL_ACCUM* = 0x00000100
+  GL_LOAD* = 0x00000101
+  GL_RETURN* = 0x00000102
+  GL_MULT* = 0x00000103
+  GL_ADD* = 0x00000104        # AlphaFunction
+  GL_NEVER* = 0x00000200
+  GL_LESS* = 0x00000201
+  GL_EQUAL* = 0x00000202
+  GL_LEQUAL* = 0x00000203
+  GL_GREATER* = 0x00000204
+  GL_NOTEQUAL* = 0x00000205
+  GL_GEQUAL* = 0x00000206
+  GL_ALWAYS* = 0x00000207     # AttribMask
+  GL_CURRENT_BIT* = 0x00000001
+  GL_POINT_BIT* = 0x00000002
+  GL_LINE_BIT* = 0x00000004
+  GL_POLYGON_BIT* = 0x00000008
+  GL_POLYGON_STIPPLE_BIT* = 0x00000010
+  GL_PIXEL_MODE_BIT* = 0x00000020
+  GL_LIGHTING_BIT* = 0x00000040
+  GL_FOG_BIT* = 0x00000080
+  GL_DEPTH_BUFFER_BIT* = 0x00000100
+  GL_ACCUM_BUFFER_BIT* = 0x00000200
+  GL_STENCIL_BUFFER_BIT* = 0x00000400
+  GL_VIEWPORT_BIT* = 0x00000800
+  GL_TRANSFORM_BIT* = 0x00001000
+  GL_ENABLE_BIT* = 0x00002000
+  GL_COLOR_BUFFER_BIT* = 0x00004000
+  GL_HINT_BIT* = 0x00008000
+  GL_EVAL_BIT* = 0x00010000
+  GL_LIST_BIT* = 0x00020000
+  GL_TEXTURE_BIT* = 0x00040000
+  GL_SCISSOR_BIT* = 0x00080000
+  GL_ALL_ATTRIB_BITS* = 0x000FFFFF # BeginMode
+  GL_POINTS* = 0x00000000
+  GL_LINES* = 0x00000001
+  GL_LINE_LOOP* = 0x00000002
+  GL_LINE_STRIP* = 0x00000003
+  GL_TRIANGLES* = 0x00000004
+  GL_TRIANGLE_STRIP* = 0x00000005
+  GL_TRIANGLE_FAN* = 0x00000006
+  GL_QUADS* = 0x00000007
+  GL_QUAD_STRIP* = 0x00000008
+  GL_POLYGON* = 0x00000009    # BlendingFactorDest
+  GL_ZERO* = 0
+  GL_ONE* = 1
+  GL_SRC_COLOR* = 0x00000300
+  GL_ONE_MINUS_SRC_COLOR* = 0x00000301
+  GL_SRC_ALPHA* = 0x00000302
+  GL_ONE_MINUS_SRC_ALPHA* = 0x00000303
+  GL_DST_ALPHA* = 0x00000304
+  GL_ONE_MINUS_DST_ALPHA* = 0x00000305 # BlendingFactorSrc
+                                       #      GL_ZERO
+                                       #      GL_ONE
+  GL_DST_COLOR* = 0x00000306
+  GL_ONE_MINUS_DST_COLOR* = 0x00000307
+  GL_SRC_ALPHA_SATURATE* = 0x00000308 #      GL_SRC_ALPHA
+                                      #      GL_ONE_MINUS_SRC_ALPHA
+                                      #      GL_DST_ALPHA
+                                      #      GL_ONE_MINUS_DST_ALPHA
+                                      # Boolean
+  GL_TRUE* = 1
+  GL_FALSE* = 0               # ClearBufferMask
+                              #      GL_COLOR_BUFFER_BIT
+                              #      GL_ACCUM_BUFFER_BIT
+                              #      GL_STENCIL_BUFFER_BIT
+                              #      GL_DEPTH_BUFFER_BIT
+                              # ClientArrayType
+                              #      GL_VERTEX_ARRAY
+                              #      GL_NORMAL_ARRAY
+                              #      GL_COLOR_ARRAY
+                              #      GL_INDEX_ARRAY
+                              #      GL_TEXTURE_COORD_ARRAY
+                              #      GL_EDGE_FLAG_ARRAY
+                              # ClipPlaneName
+  GL_CLIP_PLANE0* = 0x00003000
+  GL_CLIP_PLANE1* = 0x00003001
+  GL_CLIP_PLANE2* = 0x00003002
+  GL_CLIP_PLANE3* = 0x00003003
+  GL_CLIP_PLANE4* = 0x00003004
+  GL_CLIP_PLANE5* = 0x00003005 # ColorMaterialFace
+                               #      GL_FRONT
+                               #      GL_BACK
+                               #      GL_FRONT_AND_BACK
+                               # ColorMaterialParameter
+                               #      GL_AMBIENT
+                               #      GL_DIFFUSE
+                               #      GL_SPECULAR
+                               #      GL_EMISSION
+                               #      GL_AMBIENT_AND_DIFFUSE
+                               # ColorPointerType
+                               #      GL_BYTE
+                               #      GL_UNSIGNED_BYTE
+                               #      GL_SHORT
+                               #      GL_UNSIGNED_SHORT
+                               #      GL_INT
+                               #      GL_UNSIGNED_INT
+                               #      GL_FLOAT
+                               #      GL_DOUBLE
+                               # CullFaceMode
+                               #      GL_FRONT
+                               #      GL_BACK
+                               #      GL_FRONT_AND_BACK
+                               # DataType
+  GL_BYTE* = 0x00001400
+  GL_UNSIGNED_BYTE* = 0x00001401
+  GL_SHORT* = 0x00001402
+  GL_UNSIGNED_SHORT* = 0x00001403
+  GL_INT* = 0x00001404
+  GL_UNSIGNED_INT* = 0x00001405
+  GL_FLOAT* = 0x00001406
+  GL_2_BYTES* = 0x00001407
+  GL_3_BYTES* = 0x00001408
+  GL_4_BYTES* = 0x00001409
+  GL_DOUBLE* = 0x0000140A     # DepthFunction
+                              #      GL_NEVER
+                              #      GL_LESS
+                              #      GL_EQUAL
+                              #      GL_LEQUAL
+                              #      GL_GREATER
+                              #      GL_NOTEQUAL
+                              #      GL_GEQUAL
+                              #      GL_ALWAYS
+                              # DrawBufferMode
+  GL_NONE* = 0
+  GL_FRONT_LEFT* = 0x00000400
+  GL_FRONT_RIGHT* = 0x00000401
+  GL_BACK_LEFT* = 0x00000402
+  GL_BACK_RIGHT* = 0x00000403
+  GL_FRONT* = 0x00000404
+  GL_BACK* = 0x00000405
+  GL_LEFT* = 0x00000406
+  GL_RIGHT* = 0x00000407
+  GL_FRONT_AND_BACK* = 0x00000408
+  GL_AUX0* = 0x00000409
+  GL_AUX1* = 0x0000040A
+  GL_AUX2* = 0x0000040B
+  GL_AUX3* = 0x0000040C       # Enable
+                              #      GL_FOG
+                              #      GL_LIGHTING
+                              #      GL_TEXTURE_1D
+                              #      GL_TEXTURE_2D
+                              #      GL_LINE_STIPPLE
+                              #      GL_POLYGON_STIPPLE
+                              #      GL_CULL_FACE
+                              #      GL_ALPHA_TEST
+                              #      GL_BLEND
+                              #      GL_INDEX_LOGIC_OP
+                              #      GL_COLOR_LOGIC_OP
+                              #      GL_DITHER
+                              #      GL_STENCIL_TEST
+                              #      GL_DEPTH_TEST
+                              #      GL_CLIP_PLANE0
+                              #      GL_CLIP_PLANE1
+                              #      GL_CLIP_PLANE2
+                              #      GL_CLIP_PLANE3
+                              #      GL_CLIP_PLANE4
+                              #      GL_CLIP_PLANE5
+                              #      GL_LIGHT0
+                              #      GL_LIGHT1
+                              #      GL_LIGHT2
+                              #      GL_LIGHT3
+                              #      GL_LIGHT4
+                              #      GL_LIGHT5
+                              #      GL_LIGHT6
+                              #      GL_LIGHT7
+                              #      GL_TEXTURE_GEN_S
+                              #      GL_TEXTURE_GEN_T
+                              #      GL_TEXTURE_GEN_R
+                              #      GL_TEXTURE_GEN_Q
+                              #      GL_MAP1_VERTEX_3
+                              #      GL_MAP1_VERTEX_4
+                              #      GL_MAP1_COLOR_4
+                              #      GL_MAP1_INDEX
+                              #      GL_MAP1_NORMAL
+                              #      GL_MAP1_TEXTURE_COORD_1
+                              #      GL_MAP1_TEXTURE_COORD_2
+                              #      GL_MAP1_TEXTURE_COORD_3
+                              #      GL_MAP1_TEXTURE_COORD_4
+                              #      GL_MAP2_VERTEX_3
+                              #      GL_MAP2_VERTEX_4
+                              #      GL_MAP2_COLOR_4
+                              #      GL_MAP2_INDEX
+                              #      GL_MAP2_NORMAL
+                              #      GL_MAP2_TEXTURE_COORD_1
+                              #      GL_MAP2_TEXTURE_COORD_2
+                              #      GL_MAP2_TEXTURE_COORD_3
+                              #      GL_MAP2_TEXTURE_COORD_4
+                              #      GL_POINT_SMOOTH
+                              #      GL_LINE_SMOOTH
+                              #      GL_POLYGON_SMOOTH
+                              #      GL_SCISSOR_TEST
+                              #      GL_COLOR_MATERIAL
+                              #      GL_NORMALIZE
+                              #      GL_AUTO_NORMAL
+                              #      GL_VERTEX_ARRAY
+                              #      GL_NORMAL_ARRAY
+                              #      GL_COLOR_ARRAY
+                              #      GL_INDEX_ARRAY
+                              #      GL_TEXTURE_COORD_ARRAY
+                              #      GL_EDGE_FLAG_ARRAY
+                              #      GL_POLYGON_OFFSET_POINT
+                              #      GL_POLYGON_OFFSET_LINE
+                              #      GL_POLYGON_OFFSET_FILL
+                              # ErrorCode
+  GL_NO_ERROR* = 0
+  GL_INVALID_ENUM* = 0x00000500
+  GL_INVALID_VALUE* = 0x00000501
+  GL_INVALID_OPERATION* = 0x00000502
+  GL_STACK_OVERFLOW* = 0x00000503
+  GL_STACK_UNDERFLOW* = 0x00000504
+  GL_OUT_OF_MEMORY* = 0x00000505 # FeedBackMode
+  GL_2D* = 0x00000600
+  GL_3D* = 0x00000601
+  GL_3D_COLOR* = 0x00000602
+  GL_3D_COLOR_TEXTURE* = 0x00000603
+  GL_4D_COLOR_TEXTURE* = 0x00000604 # FeedBackToken
+  GL_PASS_THROUGH_TOKEN* = 0x00000700
+  GL_POINT_TOKEN* = 0x00000701
+  GL_LINE_TOKEN* = 0x00000702
+  GL_POLYGON_TOKEN* = 0x00000703
+  GL_BITMAP_TOKEN* = 0x00000704
+  GL_DRAW_PIXEL_TOKEN* = 0x00000705
+  GL_COPY_PIXEL_TOKEN* = 0x00000706
+  GL_LINE_RESET_TOKEN* = 0x00000707 # FogMode
+                                    #      GL_LINEAR
+  GL_EXP* = 0x00000800
+  GL_EXP2* = 0x00000801       # FogParameter
+                              #      GL_FOG_COLOR
+                              #      GL_FOG_DENSITY
+                              #      GL_FOG_END
+                              #      GL_FOG_INDEX
+                              #      GL_FOG_MODE
+                              #      GL_FOG_START
+                              # FrontFaceDirection
+  GL_CW* = 0x00000900
+  GL_CCW* = 0x00000901        # GetMapTarget
+  GL_COEFF* = 0x00000A00
+  GL_ORDER* = 0x00000A01
+  GL_DOMAIN* = 0x00000A02     # GetPixelMap
+                              #      GL_PIXEL_MAP_I_TO_I
+                              #      GL_PIXEL_MAP_S_TO_S
+                              #      GL_PIXEL_MAP_I_TO_R
+                              #      GL_PIXEL_MAP_I_TO_G
+                              #      GL_PIXEL_MAP_I_TO_B
+                              #      GL_PIXEL_MAP_I_TO_A
+                              #      GL_PIXEL_MAP_R_TO_R
+                              #      GL_PIXEL_MAP_G_TO_G
+                              #      GL_PIXEL_MAP_B_TO_B
+                              #      GL_PIXEL_MAP_A_TO_A
+                              # GetPointerTarget
+                              #      GL_VERTEX_ARRAY_POINTER
+                              #      GL_NORMAL_ARRAY_POINTER
+                              #      GL_COLOR_ARRAY_POINTER
+                              #      GL_INDEX_ARRAY_POINTER
+                              #      GL_TEXTURE_COORD_ARRAY_POINTER
+                              #      GL_EDGE_FLAG_ARRAY_POINTER
+                              # GetTarget
+  GL_CURRENT_COLOR* = 0x00000B00
+  GL_CURRENT_INDEX* = 0x00000B01
+  GL_CURRENT_NORMAL* = 0x00000B02
+  GL_CURRENT_TEXTURE_COORDS* = 0x00000B03
+  GL_CURRENT_RASTER_COLOR* = 0x00000B04
+  GL_CURRENT_RASTER_INDEX* = 0x00000B05
+  GL_CURRENT_RASTER_TEXTURE_COORDS* = 0x00000B06
+  GL_CURRENT_RASTER_POSITION* = 0x00000B07
+  GL_CURRENT_RASTER_POSITION_VALID* = 0x00000B08
+  GL_CURRENT_RASTER_DISTANCE* = 0x00000B09
+  GL_POINT_SMOOTH* = 0x00000B10
+  constGL_POINT_SIZE* = 0x00000B11
+  GL_POINT_SIZE_RANGE* = 0x00000B12
+  GL_POINT_SIZE_GRANULARITY* = 0x00000B13
+  GL_LINE_SMOOTH* = 0x00000B20
+  constGL_LINE_WIDTH* = 0x00000B21
+  GL_LINE_WIDTH_RANGE* = 0x00000B22
+  GL_LINE_WIDTH_GRANULARITY* = 0x00000B23
+  constGL_LINE_STIPPLE* = 0x00000B24
+  GL_LINE_STIPPLE_PATTERN* = 0x00000B25
+  GL_LINE_STIPPLE_REPEAT* = 0x00000B26
+  GL_LIST_MODE* = 0x00000B30
+  GL_MAX_LIST_NESTING* = 0x00000B31
+  constGL_LIST_BASE* = 0x00000B32
+  GL_LIST_INDEX* = 0x00000B33
+  constGL_POLYGON_MODE* = 0x00000B40
+  GL_POLYGON_SMOOTH* = 0x00000B41
+  constGL_POLYGON_STIPPLE* = 0x00000B42
+  constGL_EDGE_FLAG* = 0x00000B43
+  constGL_CULL_FACE* = 0x00000B44
+  GL_CULL_FACE_MODE* = 0x00000B45
+  constGL_FRONT_FACE* = 0x00000B46
+  GL_LIGHTING* = 0x00000B50
+  GL_LIGHT_MODEL_LOCAL_VIEWER* = 0x00000B51
+  GL_LIGHT_MODEL_TWO_SIDE* = 0x00000B52
+  GL_LIGHT_MODEL_AMBIENT* = 0x00000B53
+  constGL_SHADE_MODEL* = 0x00000B54
+  GL_COLOR_MATERIAL_FACE* = 0x00000B55
+  GL_COLOR_MATERIAL_PARAMETER* = 0x00000B56
+  constGL_COLOR_MATERIAL* = 0x00000B57
+  GL_FOG* = 0x00000B60
+  GL_FOG_INDEX* = 0x00000B61
+  GL_FOG_DENSITY* = 0x00000B62
+  GL_FOG_START* = 0x00000B63
+  GL_FOG_END* = 0x00000B64
+  GL_FOG_MODE* = 0x00000B65
+  GL_FOG_COLOR* = 0x00000B66
+  constGL_DEPTH_RANGE* = 0x00000B70
+  GL_DEPTH_TEST* = 0x00000B71
+  GL_DEPTH_WRITEMASK* = 0x00000B72
+  GL_DEPTH_CLEAR_VALUE* = 0x00000B73
+  constGL_DEPTH_FUNC* = 0x00000B74
+  GL_ACCUM_CLEAR_VALUE* = 0x00000B80
+  GL_STENCIL_TEST* = 0x00000B90
+  GL_STENCIL_CLEAR_VALUE* = 0x00000B91
+  constGL_STENCIL_FUNC* = 0x00000B92
+  GL_STENCIL_VALUE_MASK* = 0x00000B93
+  GL_STENCIL_FAIL* = 0x00000B94
+  GL_STENCIL_PASS_DEPTH_FAIL* = 0x00000B95
+  GL_STENCIL_PASS_DEPTH_PASS* = 0x00000B96
+  GL_STENCIL_REF* = 0x00000B97
+  GL_STENCIL_WRITEMASK* = 0x00000B98
+  constGL_MATRIX_MODE* = 0x00000BA0
+  GL_NORMALIZE* = 0x00000BA1
+  constGL_VIEWPORT* = 0x00000BA2
+  GL_MODELVIEW_STACK_DEPTH* = 0x00000BA3
+  GL_PROJECTION_STACK_DEPTH* = 0x00000BA4
+  GL_TEXTURE_STACK_DEPTH* = 0x00000BA5
+  GL_MODELVIEW_MATRIX* = 0x00000BA6
+  GL_PROJECTION_MATRIX* = 0x00000BA7
+  GL_TEXTURE_MATRIX* = 0x00000BA8
+  GL_ATTRIB_STACK_DEPTH* = 0x00000BB0
+  GL_CLIENT_ATTRIB_STACK_DEPTH* = 0x00000BB1
+  GL_ALPHA_TEST* = 0x00000BC0
+  GL_ALPHA_TEST_FUNC* = 0x00000BC1
+  GL_ALPHA_TEST_REF* = 0x00000BC2
+  GL_DITHER* = 0x00000BD0
+  GL_BLEND_DST* = 0x00000BE0
+  GL_BLEND_SRC* = 0x00000BE1
+  GL_BLEND* = 0x00000BE2
+  GL_LOGIC_OP_MODE* = 0x00000BF0
+  GL_INDEX_LOGIC_OP* = 0x00000BF1
+  GL_COLOR_LOGIC_OP* = 0x00000BF2
+  GL_AUX_BUFFERS* = 0x00000C00
+  constGL_DRAW_BUFFER* = 0x00000C01
+  constGL_READ_BUFFER* = 0x00000C02
+  GL_SCISSOR_BOX* = 0x00000C10
+  GL_SCISSOR_TEST* = 0x00000C11
+  GL_INDEX_CLEAR_VALUE* = 0x00000C20
+  GL_INDEX_WRITEMASK* = 0x00000C21
+  GL_COLOR_CLEAR_VALUE* = 0x00000C22
+  GL_COLOR_WRITEMASK* = 0x00000C23
+  GL_INDEX_MODE* = 0x00000C30
+  GL_RGBA_MODE* = 0x00000C31
+  GL_DOUBLEBUFFER* = 0x00000C32
+  GL_STEREO* = 0x00000C33
+  constGL_RENDER_MODE* = 0x00000C40
+  GL_PERSPECTIVE_CORRECTION_HINT* = 0x00000C50
+  GL_POINT_SMOOTH_HINT* = 0x00000C51
+  GL_LINE_SMOOTH_HINT* = 0x00000C52
+  GL_POLYGON_SMOOTH_HINT* = 0x00000C53
+  GL_FOG_HINT* = 0x00000C54
+  GL_TEXTURE_GEN_S* = 0x00000C60
+  GL_TEXTURE_GEN_T* = 0x00000C61
+  GL_TEXTURE_GEN_R* = 0x00000C62
+  GL_TEXTURE_GEN_Q* = 0x00000C63
+  GL_PIXEL_MAP_I_TO_I* = 0x00000C70
+  GL_PIXEL_MAP_S_TO_S* = 0x00000C71
+  GL_PIXEL_MAP_I_TO_R* = 0x00000C72
+  GL_PIXEL_MAP_I_TO_G* = 0x00000C73
+  GL_PIXEL_MAP_I_TO_B* = 0x00000C74
+  GL_PIXEL_MAP_I_TO_A* = 0x00000C75
+  GL_PIXEL_MAP_R_TO_R* = 0x00000C76
+  GL_PIXEL_MAP_G_TO_G* = 0x00000C77
+  GL_PIXEL_MAP_B_TO_B* = 0x00000C78
+  GL_PIXEL_MAP_A_TO_A* = 0x00000C79
+  GL_PIXEL_MAP_I_TO_I_SIZE* = 0x00000CB0
+  GL_PIXEL_MAP_S_TO_S_SIZE* = 0x00000CB1
+  GL_PIXEL_MAP_I_TO_R_SIZE* = 0x00000CB2
+  GL_PIXEL_MAP_I_TO_G_SIZE* = 0x00000CB3
+  GL_PIXEL_MAP_I_TO_B_SIZE* = 0x00000CB4
+  GL_PIXEL_MAP_I_TO_A_SIZE* = 0x00000CB5
+  GL_PIXEL_MAP_R_TO_R_SIZE* = 0x00000CB6
+  GL_PIXEL_MAP_G_TO_G_SIZE* = 0x00000CB7
+  GL_PIXEL_MAP_B_TO_B_SIZE* = 0x00000CB8
+  GL_PIXEL_MAP_A_TO_A_SIZE* = 0x00000CB9
+  GL_UNPACK_SWAP_BYTES* = 0x00000CF0
+  GL_UNPACK_LSB_FIRST* = 0x00000CF1
+  GL_UNPACK_ROW_LENGTH* = 0x00000CF2
+  GL_UNPACK_SKIP_ROWS* = 0x00000CF3
+  GL_UNPACK_SKIP_PIXELS* = 0x00000CF4
+  GL_UNPACK_ALIGNMENT* = 0x00000CF5
+  GL_PACK_SWAP_BYTES* = 0x00000D00
+  GL_PACK_LSB_FIRST* = 0x00000D01
+  GL_PACK_ROW_LENGTH* = 0x00000D02
+  GL_PACK_SKIP_ROWS* = 0x00000D03
+  GL_PACK_SKIP_PIXELS* = 0x00000D04
+  GL_PACK_ALIGNMENT* = 0x00000D05
+  GL_MAP_COLOR* = 0x00000D10
+  GL_MAP_STENCIL* = 0x00000D11
+  GL_INDEX_SHIFT* = 0x00000D12
+  GL_INDEX_OFFSET* = 0x00000D13
+  GL_RED_SCALE* = 0x00000D14
+  GL_RED_BIAS* = 0x00000D15
+  GL_ZOOM_X* = 0x00000D16
+  GL_ZOOM_Y* = 0x00000D17
+  GL_GREEN_SCALE* = 0x00000D18
+  GL_GREEN_BIAS* = 0x00000D19
+  GL_BLUE_SCALE* = 0x00000D1A
+  GL_BLUE_BIAS* = 0x00000D1B
+  GL_ALPHA_SCALE* = 0x00000D1C
+  GL_ALPHA_BIAS* = 0x00000D1D
+  GL_DEPTH_SCALE* = 0x00000D1E
+  GL_DEPTH_BIAS* = 0x00000D1F
+  GL_MAX_EVAL_ORDER* = 0x00000D30
+  GL_MAX_LIGHTS* = 0x00000D31
+  GL_MAX_CLIP_PLANES* = 0x00000D32
+  GL_MAX_TEXTURE_SIZE* = 0x00000D33
+  GL_MAX_PIXEL_MAP_TABLE* = 0x00000D34
+  GL_MAX_ATTRIB_STACK_DEPTH* = 0x00000D35
+  GL_MAX_MODELVIEW_STACK_DEPTH* = 0x00000D36
+  GL_MAX_NAME_STACK_DEPTH* = 0x00000D37
+  GL_MAX_PROJECTION_STACK_DEPTH* = 0x00000D38
+  GL_MAX_TEXTURE_STACK_DEPTH* = 0x00000D39
+  GL_MAX_VIEWPORT_DIMS* = 0x00000D3A
+  GL_MAX_CLIENT_ATTRIB_STACK_DEPTH* = 0x00000D3B
+  GL_SUBPIXEL_BITS* = 0x00000D50
+  GL_INDEX_BITS* = 0x00000D51
+  GL_RED_BITS* = 0x00000D52
+  GL_GREEN_BITS* = 0x00000D53
+  GL_BLUE_BITS* = 0x00000D54
+  GL_ALPHA_BITS* = 0x00000D55
+  GL_DEPTH_BITS* = 0x00000D56
+  GL_STENCIL_BITS* = 0x00000D57
+  GL_ACCUM_RED_BITS* = 0x00000D58
+  GL_ACCUM_GREEN_BITS* = 0x00000D59
+  GL_ACCUM_BLUE_BITS* = 0x00000D5A
+  GL_ACCUM_ALPHA_BITS* = 0x00000D5B
+  GL_NAME_STACK_DEPTH* = 0x00000D70
+  GL_AUTO_NORMAL* = 0x00000D80
+  GL_MAP1_COLOR_4* = 0x00000D90
+  GL_MAP1_INDEX* = 0x00000D91
+  GL_MAP1_NORMAL* = 0x00000D92
+  GL_MAP1_TEXTURE_COORD_1* = 0x00000D93
+  GL_MAP1_TEXTURE_COORD_2* = 0x00000D94
+  GL_MAP1_TEXTURE_COORD_3* = 0x00000D95
+  GL_MAP1_TEXTURE_COORD_4* = 0x00000D96
+  GL_MAP1_VERTEX_3* = 0x00000D97
+  GL_MAP1_VERTEX_4* = 0x00000D98
+  GL_MAP2_COLOR_4* = 0x00000DB0
+  GL_MAP2_INDEX* = 0x00000DB1
+  GL_MAP2_NORMAL* = 0x00000DB2
+  GL_MAP2_TEXTURE_COORD_1* = 0x00000DB3
+  GL_MAP2_TEXTURE_COORD_2* = 0x00000DB4
+  GL_MAP2_TEXTURE_COORD_3* = 0x00000DB5
+  GL_MAP2_TEXTURE_COORD_4* = 0x00000DB6
+  GL_MAP2_VERTEX_3* = 0x00000DB7
+  GL_MAP2_VERTEX_4* = 0x00000DB8
+  GL_MAP1_GRID_DOMAIN* = 0x00000DD0
+  GL_MAP1_GRID_SEGMENTS* = 0x00000DD1
+  GL_MAP2_GRID_DOMAIN* = 0x00000DD2
+  GL_MAP2_GRID_SEGMENTS* = 0x00000DD3
+  GL_TEXTURE_1D* = 0x00000DE0
+  GL_TEXTURE_2D* = 0x00000DE1
+  GL_FEEDBACK_BUFFER_POINTER* = 0x00000DF0
+  GL_FEEDBACK_BUFFER_SIZE* = 0x00000DF1
+  GL_FEEDBACK_BUFFER_TYPE* = 0x00000DF2
+  GL_SELECTION_BUFFER_POINTER* = 0x00000DF3
+  GL_SELECTION_BUFFER_SIZE* = 0x00000DF4 #      GL_TEXTURE_BINDING_1D
+                                         #      GL_TEXTURE_BINDING_2D
+                                         #      GL_VERTEX_ARRAY
+                                         #      GL_NORMAL_ARRAY
+                                         #      GL_COLOR_ARRAY
+                                         #      GL_INDEX_ARRAY
+                                         #      GL_TEXTURE_COORD_ARRAY
+                                         #      GL_EDGE_FLAG_ARRAY
+                                         #      GL_VERTEX_ARRAY_SIZE
+                                         #      GL_VERTEX_ARRAY_TYPE
+                                         #      GL_VERTEX_ARRAY_STRIDE
+                                         #      GL_NORMAL_ARRAY_TYPE
+                                         #      GL_NORMAL_ARRAY_STRIDE
+                                         #      GL_COLOR_ARRAY_SIZE
+                                         #      GL_COLOR_ARRAY_TYPE
+                                         #      GL_COLOR_ARRAY_STRIDE
+                                         #      GL_INDEX_ARRAY_TYPE
+                                         #      GL_INDEX_ARRAY_STRIDE
+                                         #      GL_TEXTURE_COORD_ARRAY_SIZE
+                                         #      GL_TEXTURE_COORD_ARRAY_TYPE
+                                         #      GL_TEXTURE_COORD_ARRAY_STRIDE
+                                         #      GL_EDGE_FLAG_ARRAY_STRIDE
+                                         #      GL_POLYGON_OFFSET_FACTOR
+                                         #      GL_POLYGON_OFFSET_UNITS
+                                         # GetTextureParameter
+                                         #      GL_TEXTURE_MAG_FILTER
+                                         #      GL_TEXTURE_MIN_FILTER
+                                         #      GL_TEXTURE_WRAP_S
+                                         #      GL_TEXTURE_WRAP_T
+  GL_TEXTURE_WIDTH* = 0x00001000
+  GL_TEXTURE_HEIGHT* = 0x00001001
+  GL_TEXTURE_INTERNAL_FORMAT* = 0x00001003
+  GL_TEXTURE_BORDER_COLOR* = 0x00001004
+  GL_TEXTURE_BORDER* = 0x00001005 #      GL_TEXTURE_RED_SIZE
+                                  #      GL_TEXTURE_GREEN_SIZE
+                                  #      GL_TEXTURE_BLUE_SIZE
+                                  #      GL_TEXTURE_ALPHA_SIZE
+                                  #      GL_TEXTURE_LUMINANCE_SIZE
+                                  #      GL_TEXTURE_INTENSITY_SIZE
+                                  #      GL_TEXTURE_PRIORITY
+                                  #      GL_TEXTURE_RESIDENT
+                                  # HintMode
+  GL_DONT_CARE* = 0x00001100
+  GL_FASTEST* = 0x00001101
+  GL_NICEST* = 0x00001102     # HintTarget
+                              #      GL_PERSPECTIVE_CORRECTION_HINT
+                              #      GL_POINT_SMOOTH_HINT
+                              #      GL_LINE_SMOOTH_HINT
+                              #      GL_POLYGON_SMOOTH_HINT
+                              #      GL_FOG_HINT
+                              # IndexPointerType
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # LightModelParameter
+                              #      GL_LIGHT_MODEL_AMBIENT
+                              #      GL_LIGHT_MODEL_LOCAL_VIEWER
+                              #      GL_LIGHT_MODEL_TWO_SIDE
+                              # LightName
+  GL_LIGHT0* = 0x00004000
+  GL_LIGHT1* = 0x00004001
+  GL_LIGHT2* = 0x00004002
+  GL_LIGHT3* = 0x00004003
+  GL_LIGHT4* = 0x00004004
+  GL_LIGHT5* = 0x00004005
+  GL_LIGHT6* = 0x00004006
+  GL_LIGHT7* = 0x00004007     # LightParameter
+  GL_AMBIENT* = 0x00001200
+  GL_DIFFUSE* = 0x00001201
+  GL_SPECULAR* = 0x00001202
+  GL_POSITION* = 0x00001203
+  GL_SPOT_DIRECTION* = 0x00001204
+  GL_SPOT_EXPONENT* = 0x00001205
+  GL_SPOT_CUTOFF* = 0x00001206
+  GL_CONSTANT_ATTENUATION* = 0x00001207
+  GL_LINEAR_ATTENUATION* = 0x00001208
+  GL_QUADRATIC_ATTENUATION* = 0x00001209 # InterleavedArrays
+                                         #      GL_V2F
+                                         #      GL_V3F
+                                         #      GL_C4UB_V2F
+                                         #      GL_C4UB_V3F
+                                         #      GL_C3F_V3F
+                                         #      GL_N3F_V3F
+                                         #      GL_C4F_N3F_V3F
+                                         #      GL_T2F_V3F
+                                         #      GL_T4F_V4F
+                                         #      GL_T2F_C4UB_V3F
+                                         #      GL_T2F_C3F_V3F
+                                         #      GL_T2F_N3F_V3F
+                                         #      GL_T2F_C4F_N3F_V3F
+                                         #      GL_T4F_C4F_N3F_V4F
+                                         # ListMode
+  GL_COMPILE* = 0x00001300
+  GL_COMPILE_AND_EXECUTE* = 0x00001301 # ListNameType
+                                       #      GL_BYTE
+                                       #      GL_UNSIGNED_BYTE
+                                       #      GL_SHORT
+                                       #      GL_UNSIGNED_SHORT
+                                       #      GL_INT
+                                       #      GL_UNSIGNED_INT
+                                       #      GL_FLOAT
+                                       #      GL_2_BYTES
+                                       #      GL_3_BYTES
+                                       #      GL_4_BYTES
+                                       # LogicOp
+  constGL_CLEAR* = 0x00001500
+  GL_AND* = 0x00001501
+  GL_AND_REVERSE* = 0x00001502
+  GL_COPY* = 0x00001503
+  GL_AND_INVERTED* = 0x00001504
+  GL_NOOP* = 0x00001505
+  GL_XOR* = 0x00001506
+  GL_OR* = 0x00001507
+  GL_NOR* = 0x00001508
+  GL_EQUIV* = 0x00001509
+  GL_INVERT* = 0x0000150A
+  GL_OR_REVERSE* = 0x0000150B
+  GL_COPY_INVERTED* = 0x0000150C
+  GL_OR_INVERTED* = 0x0000150D
+  GL_NAND* = 0x0000150E
+  GL_SET* = 0x0000150F        # MapTarget
+                              #      GL_MAP1_COLOR_4
+                              #      GL_MAP1_INDEX
+                              #      GL_MAP1_NORMAL
+                              #      GL_MAP1_TEXTURE_COORD_1
+                              #      GL_MAP1_TEXTURE_COORD_2
+                              #      GL_MAP1_TEXTURE_COORD_3
+                              #      GL_MAP1_TEXTURE_COORD_4
+                              #      GL_MAP1_VERTEX_3
+                              #      GL_MAP1_VERTEX_4
+                              #      GL_MAP2_COLOR_4
+                              #      GL_MAP2_INDEX
+                              #      GL_MAP2_NORMAL
+                              #      GL_MAP2_TEXTURE_COORD_1
+                              #      GL_MAP2_TEXTURE_COORD_2
+                              #      GL_MAP2_TEXTURE_COORD_3
+                              #      GL_MAP2_TEXTURE_COORD_4
+                              #      GL_MAP2_VERTEX_3
+                              #      GL_MAP2_VERTEX_4
+                              # MaterialFace
+                              #      GL_FRONT
+                              #      GL_BACK
+                              #      GL_FRONT_AND_BACK
+                              # MaterialParameter
+  GL_EMISSION* = 0x00001600
+  GL_SHININESS* = 0x00001601
+  GL_AMBIENT_AND_DIFFUSE* = 0x00001602
+  GL_COLOR_INDEXES* = 0x00001603 #      GL_AMBIENT
+                                 #      GL_DIFFUSE
+                                 #      GL_SPECULAR
+                                 # MatrixMode
+  GL_MODELVIEW* = 0x00001700
+  GL_PROJECTION* = 0x00001701
+  GL_TEXTURE* = 0x00001702    # MeshMode1
+                              #      GL_POINT
+                              #      GL_LINE
+                              # MeshMode2
+                              #      GL_POINT
+                              #      GL_LINE
+                              #      GL_FILL
+                              # NormalPointerType
+                              #      GL_BYTE
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # PixelCopyType
+  GL_COLOR* = 0x00001800
+  GL_DEPTH* = 0x00001801
+  GL_STENCIL* = 0x00001802    # PixelFormat
+  GL_COLOR_INDEX* = 0x00001900
+  GL_STENCIL_INDEX* = 0x00001901
+  GL_DEPTH_COMPONENT* = 0x00001902
+  GL_RED* = 0x00001903
+  GL_GREEN* = 0x00001904
+  GL_BLUE* = 0x00001905
+  GL_ALPHA* = 0x00001906
+  GL_RGB* = 0x00001907
+  GL_RGBA* = 0x00001908
+  GL_LUMINANCE* = 0x00001909
+  GL_LUMINANCE_ALPHA* = 0x0000190A # PixelMap
+                                   #      GL_PIXEL_MAP_I_TO_I
+                                   #      GL_PIXEL_MAP_S_TO_S
+                                   #      GL_PIXEL_MAP_I_TO_R
+                                   #      GL_PIXEL_MAP_I_TO_G
+                                   #      GL_PIXEL_MAP_I_TO_B
+                                   #      GL_PIXEL_MAP_I_TO_A
+                                   #      GL_PIXEL_MAP_R_TO_R
+                                   #      GL_PIXEL_MAP_G_TO_G
+                                   #      GL_PIXEL_MAP_B_TO_B
+                                   #      GL_PIXEL_MAP_A_TO_A
+                                   # PixelStore
+                                   #      GL_UNPACK_SWAP_BYTES
+                                   #      GL_UNPACK_LSB_FIRST
+                                   #      GL_UNPACK_ROW_LENGTH
+                                   #      GL_UNPACK_SKIP_ROWS
+                                   #      GL_UNPACK_SKIP_PIXELS
+                                   #      GL_UNPACK_ALIGNMENT
+                                   #      GL_PACK_SWAP_BYTES
+                                   #      GL_PACK_LSB_FIRST
+                                   #      GL_PACK_ROW_LENGTH
+                                   #      GL_PACK_SKIP_ROWS
+                                   #      GL_PACK_SKIP_PIXELS
+                                   #      GL_PACK_ALIGNMENT
+                                   # PixelTransfer
+                                   #      GL_MAP_COLOR
+                                   #      GL_MAP_STENCIL
+                                   #      GL_INDEX_SHIFT
+                                   #      GL_INDEX_OFFSET
+                                   #      GL_RED_SCALE
+                                   #      GL_RED_BIAS
+                                   #      GL_GREEN_SCALE
+                                   #      GL_GREEN_BIAS
+                                   #      GL_BLUE_SCALE
+                                   #      GL_BLUE_BIAS
+                                   #      GL_ALPHA_SCALE
+                                   #      GL_ALPHA_BIAS
+                                   #      GL_DEPTH_SCALE
+                                   #      GL_DEPTH_BIAS
+                                   # PixelType
+  constGL_BITMAP* = 0x00001A00
+  GL_POINT* = 0x00001B00
+  GL_LINE* = 0x00001B01
+  GL_FILL* = 0x00001B02       # ReadBufferMode
+                              #      GL_FRONT_LEFT
+                              #      GL_FRONT_RIGHT
+                              #      GL_BACK_LEFT
+                              #      GL_BACK_RIGHT
+                              #      GL_FRONT
+                              #      GL_BACK
+                              #      GL_LEFT
+                              #      GL_RIGHT
+                              #      GL_AUX0
+                              #      GL_AUX1
+                              #      GL_AUX2
+                              #      GL_AUX3
+                              # RenderingMode
+  GL_RENDER* = 0x00001C00
+  GL_FEEDBACK* = 0x00001C01
+  GL_SELECT* = 0x00001C02     # ShadingModel
+  GL_FLAT* = 0x00001D00
+  GL_SMOOTH* = 0x00001D01     # StencilFunction
+                              #      GL_NEVER
+                              #      GL_LESS
+                              #      GL_EQUAL
+                              #      GL_LEQUAL
+                              #      GL_GREATER
+                              #      GL_NOTEQUAL
+                              #      GL_GEQUAL
+                              #      GL_ALWAYS
+                              # StencilOp
+                              #      GL_ZERO
+  GL_KEEP* = 0x00001E00
+  GL_REPLACE* = 0x00001E01
+  GL_INCR* = 0x00001E02
+  GL_DECR* = 0x00001E03       #      GL_INVERT
+                              # StringName
+  GL_VENDOR* = 0x00001F00
+  GL_RENDERER* = 0x00001F01
+  GL_VERSION* = 0x00001F02
+  GL_EXTENSIONS* = 0x00001F03 # TextureCoordName
+  GL_S* = 0x00002000
+  GL_T* = 0x00002001
+  GL_R* = 0x00002002
+  GL_Q* = 0x00002003          # TexCoordPointerType
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # TextureEnvMode
+  GL_MODULATE* = 0x00002100
+  GL_DECAL* = 0x00002101      #      GL_BLEND
+                              #      GL_REPLACE
+                              # TextureEnvParameter
+  GL_TEXTURE_ENV_MODE* = 0x00002200
+  GL_TEXTURE_ENV_COLOR* = 0x00002201 # TextureEnvTarget
+  GL_TEXTURE_ENV* = 0x00002300 # TextureGenMode
+  GL_EYE_LINEAR* = 0x00002400
+  GL_OBJECT_LINEAR* = 0x00002401
+  GL_SPHERE_MAP* = 0x00002402 # TextureGenParameter
+  GL_TEXTURE_GEN_MODE* = 0x00002500
+  GL_OBJECT_PLANE* = 0x00002501
+  GL_EYE_PLANE* = 0x00002502  # TextureMagFilter
+  GL_NEAREST* = 0x00002600
+  GL_LINEAR* = 0x00002601     # TextureMinFilter
+                              #      GL_NEAREST
+                              #      GL_LINEAR
+  GL_NEAREST_MIPMAP_NEAREST* = 0x00002700
+  GL_LINEAR_MIPMAP_NEAREST* = 0x00002701
+  GL_NEAREST_MIPMAP_LINEAR* = 0x00002702
+  GL_LINEAR_MIPMAP_LINEAR* = 0x00002703 # TextureParameterName
+  GL_TEXTURE_MAG_FILTER* = 0x00002800
+  GL_TEXTURE_MIN_FILTER* = 0x00002801
+  GL_TEXTURE_WRAP_S* = 0x00002802
+  GL_TEXTURE_WRAP_T* = 0x00002803 #      GL_TEXTURE_BORDER_COLOR
+                                  #      GL_TEXTURE_PRIORITY
+                                  # TextureTarget
+                                  #      GL_TEXTURE_1D
+                                  #      GL_TEXTURE_2D
+                                  #      GL_PROXY_TEXTURE_1D
+                                  #      GL_PROXY_TEXTURE_2D
+                                  # TextureWrapMode
+  GL_CLAMP* = 0x00002900
+  GL_REPEAT* = 0x00002901     # VertexPointerType
+                              #      GL_SHORT
+                              #      GL_INT
+                              #      GL_FLOAT
+                              #      GL_DOUBLE
+                              # ClientAttribMask
+  GL_CLIENT_PIXEL_STORE_BIT* = 0x00000001
+  GL_CLIENT_VERTEX_ARRAY_BIT* = 0x00000002
+  GL_CLIENT_ALL_ATTRIB_BITS* = 0xFFFFFFFF # polygon_offset
+  GL_POLYGON_OFFSET_FACTOR* = 0x00008038
+  GL_POLYGON_OFFSET_UNITS* = 0x00002A00
+  GL_POLYGON_OFFSET_POINT* = 0x00002A01
+  GL_POLYGON_OFFSET_LINE* = 0x00002A02
+  GL_POLYGON_OFFSET_FILL* = 0x00008037 # texture
+  GL_ALPHA4* = 0x0000803B
+  GL_ALPHA8* = 0x0000803C
+  GL_ALPHA12* = 0x0000803D
+  GL_ALPHA16* = 0x0000803E
+  GL_LUMINANCE4* = 0x0000803F
+  GL_LUMINANCE8* = 0x00008040
+  GL_LUMINANCE12* = 0x00008041
+  GL_LUMINANCE16* = 0x00008042
+  GL_LUMINANCE4_ALPHA4* = 0x00008043
+  GL_LUMINANCE6_ALPHA2* = 0x00008044
+  GL_LUMINANCE8_ALPHA8* = 0x00008045
+  GL_LUMINANCE12_ALPHA4* = 0x00008046
+  GL_LUMINANCE12_ALPHA12* = 0x00008047
+  GL_LUMINANCE16_ALPHA16* = 0x00008048
+  GL_INTENSITY* = 0x00008049
+  GL_INTENSITY4* = 0x0000804A
+  GL_INTENSITY8* = 0x0000804B
+  GL_INTENSITY12* = 0x0000804C
+  GL_INTENSITY16* = 0x0000804D
+  GL_R3_G3_B2* = 0x00002A10
+  GL_RGB4* = 0x0000804F
+  GL_RGB5* = 0x00008050
+  GL_RGB8* = 0x00008051
+  GL_RGB10* = 0x00008052
+  GL_RGB12* = 0x00008053
+  GL_RGB16* = 0x00008054
+  GL_RGBA2* = 0x00008055
+  GL_RGBA4* = 0x00008056
+  GL_RGB5_A1* = 0x00008057
+  GL_RGBA8* = 0x00008058
+  GL_RGB10_A2* = 0x00008059
+  GL_RGBA12* = 0x0000805A
+  GL_RGBA16* = 0x0000805B
+  GL_TEXTURE_RED_SIZE* = 0x0000805C
+  GL_TEXTURE_GREEN_SIZE* = 0x0000805D
+  GL_TEXTURE_BLUE_SIZE* = 0x0000805E
+  GL_TEXTURE_ALPHA_SIZE* = 0x0000805F
+  GL_TEXTURE_LUMINANCE_SIZE* = 0x00008060
+  GL_TEXTURE_INTENSITY_SIZE* = 0x00008061
+  GL_PROXY_TEXTURE_1D* = 0x00008063
+  GL_PROXY_TEXTURE_2D* = 0x00008064 # texture_object
+  GL_TEXTURE_PRIORITY* = 0x00008066
+  GL_TEXTURE_RESIDENT* = 0x00008067
+  GL_TEXTURE_BINDING_1D* = 0x00008068
+  GL_TEXTURE_BINDING_2D* = 0x00008069 # vertex_array
+  GL_VERTEX_ARRAY* = 0x00008074
+  GL_NORMAL_ARRAY* = 0x00008075
+  GL_COLOR_ARRAY* = 0x00008076
+  GL_INDEX_ARRAY* = 0x00008077
+  GL_TEXTURE_COORD_ARRAY* = 0x00008078
+  GL_EDGE_FLAG_ARRAY* = 0x00008079
+  GL_VERTEX_ARRAY_SIZE* = 0x0000807A
+  GL_VERTEX_ARRAY_TYPE* = 0x0000807B
+  GL_VERTEX_ARRAY_STRIDE* = 0x0000807C
+  GL_NORMAL_ARRAY_TYPE* = 0x0000807E
+  GL_NORMAL_ARRAY_STRIDE* = 0x0000807F
+  GL_COLOR_ARRAY_SIZE* = 0x00008081
+  GL_COLOR_ARRAY_TYPE* = 0x00008082
+  GL_COLOR_ARRAY_STRIDE* = 0x00008083
+  GL_INDEX_ARRAY_TYPE* = 0x00008085
+  GL_INDEX_ARRAY_STRIDE* = 0x00008086
+  GL_TEXTURE_COORD_ARRAY_SIZE* = 0x00008088
+  GL_TEXTURE_COORD_ARRAY_TYPE* = 0x00008089
+  GL_TEXTURE_COORD_ARRAY_STRIDE* = 0x0000808A
+  GL_EDGE_FLAG_ARRAY_STRIDE* = 0x0000808C
+  GL_VERTEX_ARRAY_POINTER* = 0x0000808E
+  GL_NORMAL_ARRAY_POINTER* = 0x0000808F
+  GL_COLOR_ARRAY_POINTER* = 0x00008090
+  GL_INDEX_ARRAY_POINTER* = 0x00008091
+  GL_TEXTURE_COORD_ARRAY_POINTER* = 0x00008092
+  GL_EDGE_FLAG_ARRAY_POINTER* = 0x00008093
+  GL_V2F* = 0x00002A20
+  GL_V3F* = 0x00002A21
+  GL_C4UB_V2F* = 0x00002A22
+  GL_C4UB_V3F* = 0x00002A23
+  GL_C3F_V3F* = 0x00002A24
+  GL_N3F_V3F* = 0x00002A25
+  GL_C4F_N3F_V3F* = 0x00002A26
+  GL_T2F_V3F* = 0x00002A27
+  GL_T4F_V4F* = 0x00002A28
+  GL_T2F_C4UB_V3F* = 0x00002A29
+  GL_T2F_C3F_V3F* = 0x00002A2A
+  GL_T2F_N3F_V3F* = 0x00002A2B
+  GL_T2F_C4F_N3F_V3F* = 0x00002A2C
+  GL_T4F_C4F_N3F_V4F* = 0x00002A2D # Extensions
+  GL_EXT_vertex_array* = 1
+  GL_WIN_swap_hint* = 1
+  GL_EXT_bgra* = 1
+  GL_EXT_paletted_texture* = 1 # EXT_vertex_array
+  GL_VERTEX_ARRAY_EXT* = 0x00008074
+  GL_NORMAL_ARRAY_EXT* = 0x00008075
+  GL_COLOR_ARRAY_EXT* = 0x00008076
+  GL_INDEX_ARRAY_EXT* = 0x00008077
+  GL_TEXTURE_COORD_ARRAY_EXT* = 0x00008078
+  GL_EDGE_FLAG_ARRAY_EXT* = 0x00008079
+  GL_VERTEX_ARRAY_SIZE_EXT* = 0x0000807A
+  GL_VERTEX_ARRAY_TYPE_EXT* = 0x0000807B
+  GL_VERTEX_ARRAY_STRIDE_EXT* = 0x0000807C
+  GL_VERTEX_ARRAY_COUNT_EXT* = 0x0000807D
+  GL_NORMAL_ARRAY_TYPE_EXT* = 0x0000807E
+  GL_NORMAL_ARRAY_STRIDE_EXT* = 0x0000807F
+  GL_NORMAL_ARRAY_COUNT_EXT* = 0x00008080
+  GL_COLOR_ARRAY_SIZE_EXT* = 0x00008081
+  GL_COLOR_ARRAY_TYPE_EXT* = 0x00008082
+  GL_COLOR_ARRAY_STRIDE_EXT* = 0x00008083
+  GL_COLOR_ARRAY_COUNT_EXT* = 0x00008084
+  GL_INDEX_ARRAY_TYPE_EXT* = 0x00008085
+  GL_INDEX_ARRAY_STRIDE_EXT* = 0x00008086
+  GL_INDEX_ARRAY_COUNT_EXT* = 0x00008087
+  GL_TEXTURE_COORD_ARRAY_SIZE_EXT* = 0x00008088
+  GL_TEXTURE_COORD_ARRAY_TYPE_EXT* = 0x00008089
+  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT* = 0x0000808A
+  GL_TEXTURE_COORD_ARRAY_COUNT_EXT* = 0x0000808B
+  GL_EDGE_FLAG_ARRAY_STRIDE_EXT* = 0x0000808C
+  GL_EDGE_FLAG_ARRAY_COUNT_EXT* = 0x0000808D
+  GL_VERTEX_ARRAY_POINTER_EXT* = 0x0000808E
+  GL_NORMAL_ARRAY_POINTER_EXT* = 0x0000808F
+  GL_COLOR_ARRAY_POINTER_EXT* = 0x00008090
+  GL_INDEX_ARRAY_POINTER_EXT* = 0x00008091
+  GL_TEXTURE_COORD_ARRAY_POINTER_EXT* = 0x00008092
+  GL_EDGE_FLAG_ARRAY_POINTER_EXT* = 0x00008093
+  GL_DOUBLE_EXT* = GL_DOUBLE  # EXT_bgra
+  GL_BGR_EXT* = 0x000080E0
+  GL_BGRA_EXT* = 0x000080E1   # EXT_paletted_texture
+                              # These must match the GL_COLOR_TABLE_*_SGI enumerants
+  GL_COLOR_TABLE_FORMAT_EXT* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH_EXT* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE_EXT* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE_EXT* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE_EXT* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE_EXT* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE_EXT* = 0x000080DF
+  GL_COLOR_INDEX1_EXT* = 0x000080E2
+  GL_COLOR_INDEX2_EXT* = 0x000080E3
+  GL_COLOR_INDEX4_EXT* = 0x000080E4
+  GL_COLOR_INDEX8_EXT* = 0x000080E5
+  GL_COLOR_INDEX12_EXT* = 0x000080E6
+  GL_COLOR_INDEX16_EXT* = 0x000080E7 # For compatibility with OpenGL v1.0
+  constGL_LOGIC_OP* = GL_INDEX_LOGIC_OP
+  GL_TEXTURE_COMPONENTS* = GL_TEXTURE_INTERNAL_FORMAT
+
+proc glAccum*(op: TGLenum, value: TGLfloat){.dynlib: dllname, importc: "glAccum".}
+proc glAlphaFunc*(fun: TGLenum, theref: TGLclampf){.dynlib: dllname,
+    importc: "glAlphaFunc".}
+proc glAreTexturesResident*(n: TGLsizei, textures: PGLuint,
+                            residences: PGLboolean): TGLboolean{.
+    dynlib: dllname, importc: "glAreTexturesResident".}
+proc glArrayElement*(i: TGLint){.dynlib: dllname, importc: "glArrayElement".}
+proc glBegin*(mode: TGLenum){.dynlib: dllname, importc: "glBegin".}
+proc glBindTexture*(target: TGLenum, texture: TGLuint){.dynlib: dllname,
+    importc: "glBindTexture".}
+proc glBitmap*(width, height: TGLsizei, xorig, yorig: TGLfloat,
+               xmove, ymove: TGLfloat, bitmap: PGLubyte){.dynlib: dllname,
+    importc: "glBitmap".}
+proc glBlendFunc*(sfactor, dfactor: TGLenum){.dynlib: dllname,
+    importc: "glBlendFunc".}
+proc glCallList*(list: TGLuint){.dynlib: dllname, importc: "glCallList".}
+proc glCallLists*(n: TGLsizei, atype: TGLenum, lists: pointer){.dynlib: dllname,
+    importc: "glCallLists".}
+proc glClear*(mask: TGLbitfield){.dynlib: dllname, importc: "glClear".}
+proc glClearAccum*(red, green, blue, alpha: TGLfloat){.dynlib: dllname,
+    importc: "glClearAccum".}
+proc glClearColor*(red, green, blue, alpha: TGLclampf){.dynlib: dllname,
+    importc: "glClearColor".}
+proc glClearDepth*(depth: TGLclampd){.dynlib: dllname, importc: "glClearDepth".}
+proc glClearIndex*(c: TGLfloat){.dynlib: dllname, importc: "glClearIndex".}
+proc glClearStencil*(s: TGLint){.dynlib: dllname, importc: "glClearStencil".}
+proc glClipPlane*(plane: TGLenum, equation: PGLdouble){.dynlib: dllname,
+    importc: "glClipPlane".}
+proc glColor3b*(red, green, blue: TGlbyte){.dynlib: dllname,
+    importc: "glColor3b".}
+proc glColor3bv*(v: PGLbyte){.dynlib: dllname, importc: "glColor3bv".}
+proc glColor3d*(red, green, blue: TGLdouble){.dynlib: dllname,
+    importc: "glColor3d".}
+proc glColor3dv*(v: PGLdouble){.dynlib: dllname, importc: "glColor3dv".}
+proc glColor3f*(red, green, blue: TGLfloat){.dynlib: dllname,
+    importc: "glColor3f".}
+proc glColor3fv*(v: PGLfloat){.dynlib: dllname, importc: "glColor3fv".}
+proc glColor3i*(red, green, blue: TGLint){.dynlib: dllname, importc: "glColor3i".}
+proc glColor3iv*(v: PGLint){.dynlib: dllname, importc: "glColor3iv".}
+proc glColor3s*(red, green, blue: TGLshort){.dynlib: dllname,
+    importc: "glColor3s".}
+proc glColor3sv*(v: PGLshort){.dynlib: dllname, importc: "glColor3sv".}
+proc glColor3ub*(red, green, blue: TGLubyte){.dynlib: dllname,
+    importc: "glColor3ub".}
+proc glColor3ubv*(v: PGLubyte){.dynlib: dllname, importc: "glColor3ubv".}
+proc glColor3ui*(red, green, blue: TGLuint){.dynlib: dllname,
+    importc: "glColor3ui".}
+proc glColor3uiv*(v: PGLuint){.dynlib: dllname, importc: "glColor3uiv".}
+proc glColor3us*(red, green, blue: TGLushort){.dynlib: dllname,
+    importc: "glColor3us".}
+proc glColor3usv*(v: PGLushort){.dynlib: dllname, importc: "glColor3usv".}
+proc glColor4b*(red, green, blue, alpha: TGlbyte){.dynlib: dllname,
+    importc: "glColor4b".}
+proc glColor4bv*(v: PGLbyte){.dynlib: dllname, importc: "glColor4bv".}
+proc glColor4d*(red, green, blue, alpha: TGLdouble){.dynlib: dllname,
+    importc: "glColor4d".}
+proc glColor4dv*(v: PGLdouble){.dynlib: dllname, importc: "glColor4dv".}
+proc glColor4f*(red, green, blue, alpha: TGLfloat){.dynlib: dllname,
+    importc: "glColor4f".}
+proc glColor4fv*(v: PGLfloat){.dynlib: dllname, importc: "glColor4fv".}
+proc glColor4i*(red, green, blue, alpha: TGLint){.dynlib: dllname,
+    importc: "glColor4i".}
+proc glColor4iv*(v: PGLint){.dynlib: dllname, importc: "glColor4iv".}
+proc glColor4s*(red, green, blue, alpha: TGLshort){.dynlib: dllname,
+    importc: "glColor4s".}
+proc glColor4sv*(v: PGLshort){.dynlib: dllname, importc: "glColor4sv".}
+proc glColor4ub*(red, green, blue, alpha: TGLubyte){.dynlib: dllname,
+    importc: "glColor4ub".}
+proc glColor4ubv*(v: PGLubyte){.dynlib: dllname, importc: "glColor4ubv".}
+proc glColor4ui*(red, green, blue, alpha: TGLuint){.dynlib: dllname,
+    importc: "glColor4ui".}
+proc glColor4uiv*(v: PGLuint){.dynlib: dllname, importc: "glColor4uiv".}
+proc glColor4us*(red, green, blue, alpha: TGLushort){.dynlib: dllname,
+    importc: "glColor4us".}
+proc glColor4usv*(v: PGLushort){.dynlib: dllname, importc: "glColor4usv".}
+proc glColorMask*(red, green, blue, alpha: TGLboolean){.dynlib: dllname,
+    importc: "glColorMask".}
+proc glColorMaterial*(face, mode: TGLenum){.dynlib: dllname,
+    importc: "glColorMaterial".}
+proc glColorPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei,
+                     p: pointer){.dynlib: dllname,
+                                        importc: "glColorPointer".}
+proc glCopyPixels*(x, y: TGLint, width, height: TGLsizei, atype: TGLenum){.
+    dynlib: dllname, importc: "glCopyPixels".}
+proc glCopyTexImage1D*(target: TGLenum, level: TGLint, internalFormat: TGLenum,
+                       x, y: TGLint, width: TGLsizei, border: TGLint){.
+    dynlib: dllname, importc: "glCopyTexImage1D".}
+proc glCopyTexImage2D*(target: TGLenum, level: TGLint, internalFormat: TGLenum,
+                       x, y: TGLint, width, height: TGLsizei, border: TGLint){.
+    dynlib: dllname, importc: "glCopyTexImage2D".}
+proc glCopyTexSubImage1D*(target: TGLenum, level, xoffset, x, y: TGLint,
+                          width: TGLsizei){.dynlib: dllname,
+    importc: "glCopyTexSubImage1D".}
+proc glCopyTexSubImage2D*(target: TGLenum,
+                          level, xoffset, yoffset, x, y: TGLint,
+                          width, height: TGLsizei){.dynlib: dllname,
+    importc: "glCopyTexSubImage2D".}
+proc glCullFace*(mode: TGLenum){.dynlib: dllname, importc: "glCullFace".}
+proc glDeleteLists*(list: TGLuint, range: TGLsizei){.dynlib: dllname,
+    importc: "glDeleteLists".}
+proc glDeleteTextures*(n: TGLsizei, textures: PGLuint){.dynlib: dllname,
+    importc: "glDeleteTextures".}
+proc glDepthFunc*(fun: TGLenum){.dynlib: dllname, importc: "glDepthFunc".}
+proc glDepthMask*(flag: TGLboolean){.dynlib: dllname, importc: "glDepthMask".}
+proc glDepthRange*(zNear, zFar: TGLclampd){.dynlib: dllname,
+    importc: "glDepthRange".}
+proc glDisable*(cap: TGLenum){.dynlib: dllname, importc: "glDisable".}
+proc glDisableClientState*(aarray: TGLenum){.dynlib: dllname,
+    importc: "glDisableClientState".}
+proc glDrawArrays*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawArrays".}
+proc glDrawBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glDrawBuffer".}
+proc glDrawElements*(mode: TGLenum, count: TGLsizei, atype: TGLenum,
+                     indices: pointer){.dynlib: dllname,
+                                        importc: "glDrawElements".}
+proc glDrawPixels*(width, height: TGLsizei, format, atype: TGLenum,
+                   pixels: pointer){.dynlib: dllname, importc: "glDrawPixels".}
+proc glEdgeFlag*(flag: TGLboolean){.dynlib: dllname, importc: "glEdgeFlag".}
+proc glEdgeFlagPointer*(stride: TGLsizei, p: pointer){.dynlib: dllname,
+    importc: "glEdgeFlagPointer".}
+proc glEdgeFlagv*(flag: PGLboolean){.dynlib: dllname, importc: "glEdgeFlagv".}
+proc glEnable*(cap: TGLenum){.dynlib: dllname, importc: "glEnable".}
+proc glEnableClientState*(aarray: TGLenum){.dynlib: dllname,
+    importc: "glEnableClientState".}
+proc glEnd*(){.dynlib: dllname, importc: "glEnd".}
+proc glEndList*(){.dynlib: dllname, importc: "glEndList".}
+proc glEvalCoord1d*(u: TGLdouble){.dynlib: dllname, importc: "glEvalCoord1d".}
+proc glEvalCoord1dv*(u: PGLdouble){.dynlib: dllname, importc: "glEvalCoord1dv".}
+proc glEvalCoord1f*(u: TGLfloat){.dynlib: dllname, importc: "glEvalCoord1f".}
+proc glEvalCoord1fv*(u: PGLfloat){.dynlib: dllname, importc: "glEvalCoord1fv".}
+proc glEvalCoord2d*(u, v: TGLdouble){.dynlib: dllname, importc: "glEvalCoord2d".}
+proc glEvalCoord2dv*(u: PGLdouble){.dynlib: dllname, importc: "glEvalCoord2dv".}
+proc glEvalCoord2f*(u, v: TGLfloat){.dynlib: dllname, importc: "glEvalCoord2f".}
+proc glEvalCoord2fv*(u: PGLfloat){.dynlib: dllname, importc: "glEvalCoord2fv".}
+proc glEvalMesh1*(mode: TGLenum, i1, i2: TGLint){.dynlib: dllname,
+    importc: "glEvalMesh1".}
+proc glEvalMesh2*(mode: TGLenum, i1, i2, j1, j2: TGLint){.dynlib: dllname,
+    importc: "glEvalMesh2".}
+proc glEvalPoint1*(i: TGLint){.dynlib: dllname, importc: "glEvalPoint1".}
+proc glEvalPoint2*(i, j: TGLint){.dynlib: dllname, importc: "glEvalPoint2".}
+proc glFeedbackBuffer*(size: TGLsizei, atype: TGLenum, buffer: PGLfloat){.
+    dynlib: dllname, importc: "glFeedbackBuffer".}
+proc glFinish*(){.dynlib: dllname, importc: "glFinish".}
+proc glFlush*(){.dynlib: dllname, importc: "glFlush".}
+proc glFogf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glFogf".}
+proc glFogfv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glFogfv".}
+proc glFogi*(pname: TGLenum, param: TGLint){.dynlib: dllname, importc: "glFogi".}
+proc glFogiv*(pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glFogiv".}
+proc glFrontFace*(mode: TGLenum){.dynlib: dllname, importc: "glFrontFace".}
+proc glFrustum*(left, right, bottom, top, zNear, zFar: TGLdouble){.
+    dynlib: dllname, importc: "glFrustum".}
+proc glGenLists*(range: TGLsizei): TGLuint{.dynlib: dllname,
+    importc: "glGenLists".}
+proc glGenTextures*(n: TGLsizei, textures: PGLuint){.dynlib: dllname,
+    importc: "glGenTextures".}
+proc glGetBooleanv*(pname: TGLenum, params: PGLboolean){.dynlib: dllname,
+    importc: "glGetBooleanv".}
+proc glGetClipPlane*(plane: TGLenum, equation: PGLdouble){.dynlib: dllname,
+    importc: "glGetClipPlane".}
+proc glGetDoublev*(pname: TGLenum, params: PGLdouble){.dynlib: dllname,
+    importc: "glGetDoublev".}
+proc glGetError*(): TGLenum{.dynlib: dllname, importc: "glGetError".}
+proc glGetFloatv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glGetFloatv".}
+proc glGetIntegerv*(pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glGetIntegerv".}
+proc glGetLightfv*(light, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glGetLightfv".}
+proc glGetLightiv*(light, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glGetLightiv".}
+proc glGetMapdv*(target, query: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glGetMapdv".}
+proc glGetMapfv*(target, query: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glGetMapfv".}
+proc glGetMapiv*(target, query: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glGetMapiv".}
+proc glGetMaterialfv*(face, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glGetMaterialfv".}
+proc glGetMaterialiv*(face, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glGetMaterialiv".}
+proc glGetPixelMapfv*(map: TGLenum, values: PGLfloat){.dynlib: dllname,
+    importc: "glGetPixelMapfv".}
+proc glGetPixelMapuiv*(map: TGLenum, values: PGLuint){.dynlib: dllname,
+    importc: "glGetPixelMapuiv".}
+proc glGetPixelMapusv*(map: TGLenum, values: PGLushort){.dynlib: dllname,
+    importc: "glGetPixelMapusv".}
+proc glGetPointerv*(pname: TGLenum, params: pointer){.dynlib: dllname,
+    importc: "glGetPointerv".}
+proc glGetPolygonStipple*(mask: PGLubyte){.dynlib: dllname,
+    importc: "glGetPolygonStipple".}
+proc glGetString*(name: TGLenum): cstring{.dynlib: dllname,
+    importc: "glGetString".}
+proc glGetTexEnvfv*(target, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glGetTexEnvfv".}
+proc glGetTexEnviv*(target, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glGetTexEnviv".}
+proc glGetTexGendv*(coord, pname: TGLenum, params: PGLdouble){.dynlib: dllname,
+    importc: "glGetTexGendv".}
+proc glGetTexGenfv*(coord, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glGetTexGenfv".}
+proc glGetTexGeniv*(coord, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glGetTexGeniv".}
+proc glGetTexImage*(target: TGLenum, level: TGLint, format: TGLenum,
+                    atype: TGLenum, pixels: pointer){.dynlib: dllname,
+    importc: "glGetTexImage".}
+proc glGetTexLevelParameterfv*(target: TGLenum, level: TGLint, pname: TGLenum,
+                               params: pointer){.dynlib: dllname,
+    importc: "glGetTexLevelParameterfv".}
+proc glGetTexLevelParameteriv*(target: TGLenum, level: TGLint, pname: TGLenum,
+                               params: PGLint){.dynlib: dllname,
+    importc: "glGetTexLevelParameteriv".}
+proc glGetTexParameterfv*(target, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetTexParameterfv".}
+proc glGetTexParameteriv*(target, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetTexParameteriv".}
+proc glHint*(target, mode: TGLenum){.dynlib: dllname, importc: "glHint".}
+proc glIndexMask*(mask: TGLuint){.dynlib: dllname, importc: "glIndexMask".}
+proc glIndexPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){.
+    dynlib: dllname, importc: "glIndexPointer".}
+proc glIndexd*(c: TGLdouble){.dynlib: dllname, importc: "glIndexd".}
+proc glIndexdv*(c: PGLdouble){.dynlib: dllname, importc: "glIndexdv".}
+proc glIndexf*(c: TGLfloat){.dynlib: dllname, importc: "glIndexf".}
+proc glIndexfv*(c: PGLfloat){.dynlib: dllname, importc: "glIndexfv".}
+proc glIndexi*(c: TGLint){.dynlib: dllname, importc: "glIndexi".}
+proc glIndexiv*(c: PGLint){.dynlib: dllname, importc: "glIndexiv".}
+proc glIndexs*(c: TGLshort){.dynlib: dllname, importc: "glIndexs".}
+proc glIndexsv*(c: PGLshort){.dynlib: dllname, importc: "glIndexsv".}
+proc glIndexub*(c: TGLubyte){.dynlib: dllname, importc: "glIndexub".}
+proc glIndexubv*(c: PGLubyte){.dynlib: dllname, importc: "glIndexubv".}
+proc glInitNames*(){.dynlib: dllname, importc: "glInitNames".}
+proc glInterleavedArrays*(format: TGLenum, stride: TGLsizei, p: pointer){.
+    dynlib: dllname, importc: "glInterleavedArrays".}
+proc glIsEnabled*(cap: TGLenum): TGLboolean{.dynlib: dllname,
+    importc: "glIsEnabled".}
+proc glIsList*(list: TGLuint): TGLboolean{.dynlib: dllname, importc: "glIsList".}
+proc glIsTexture*(texture: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsTexture".}
+proc glLightModelf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glLightModelf".}
+proc glLightModelfv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glLightModelfv".}
+proc glLightModeli*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glLightModeli".}
+proc glLightModeliv*(pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glLightModeliv".}
+proc glLightf*(light, pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glLightf".}
+proc glLightfv*(light, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glLightfv".}
+proc glLighti*(light, pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glLighti".}
+proc glLightiv*(light, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glLightiv".}
+proc glLineStipple*(factor: TGLint, pattern: TGLushort){.dynlib: dllname,
+    importc: "glLineStipple".}
+proc glLineWidth*(width: TGLfloat){.dynlib: dllname, importc: "glLineWidth".}
+proc glListBase*(base: TGLuint){.dynlib: dllname, importc: "glListBase".}
+proc glLoadIdentity*(){.dynlib: dllname, importc: "glLoadIdentity".}
+proc glLoadMatrixd*(m: PGLdouble){.dynlib: dllname, importc: "glLoadMatrixd".}
+proc glLoadMatrixf*(m: PGLfloat){.dynlib: dllname, importc: "glLoadMatrixf".}
+proc glLoadName*(name: TGLuint){.dynlib: dllname, importc: "glLoadName".}
+proc glLogicOp*(opcode: TGLenum){.dynlib: dllname, importc: "glLogicOp".}
+proc glMap1d*(target: TGLenum, u1, u2: TGLdouble, stride, order: TGLint,
+              points: PGLdouble){.dynlib: dllname, importc: "glMap1d".}
+proc glMap1f*(target: TGLenum, u1, u2: TGLfloat, stride, order: TGLint,
+              points: PGLfloat){.dynlib: dllname, importc: "glMap1f".}
+proc glMap2d*(target: TGLenum, u1, u2: TGLdouble, ustride, uorder: TGLint,
+              v1, v2: TGLdouble, vstride, vorder: TGLint, points: PGLdouble){.
+    dynlib: dllname, importc: "glMap2d".}
+proc glMap2f*(target: TGLenum, u1, u2: TGLfloat, ustride, uorder: TGLint,
+              v1, v2: TGLfloat, vstride, vorder: TGLint, points: PGLfloat){.
+    dynlib: dllname, importc: "glMap2f".}
+proc glMapGrid1d*(un: TGLint, u1, u2: TGLdouble){.dynlib: dllname,
+    importc: "glMapGrid1d".}
+proc glMapGrid1f*(un: TGLint, u1, u2: TGLfloat){.dynlib: dllname,
+    importc: "glMapGrid1f".}
+proc glMapGrid2d*(un: TGLint, u1, u2: TGLdouble, vn: TGLint, v1, v2: TGLdouble){.
+    dynlib: dllname, importc: "glMapGrid2d".}
+proc glMapGrid2f*(un: TGLint, u1, u2: TGLfloat, vn: TGLint, v1, v2: TGLfloat){.
+    dynlib: dllname, importc: "glMapGrid2f".}
+proc glMaterialf*(face, pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glMaterialf".}
+proc glMaterialfv*(face, pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glMaterialfv".}
+proc glMateriali*(face, pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glMateriali".}
+proc glMaterialiv*(face, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glMaterialiv".}
+proc glMatrixMode*(mode: TGLenum){.dynlib: dllname, importc: "glMatrixMode".}
+proc glMultMatrixd*(m: PGLdouble){.dynlib: dllname, importc: "glMultMatrixd".}
+proc glMultMatrixf*(m: PGLfloat){.dynlib: dllname, importc: "glMultMatrixf".}
+proc glNewList*(list: TGLuint, mode: TGLenum){.dynlib: dllname,
+    importc: "glNewList".}
+proc glNormal3b*(nx, ny, nz: TGlbyte){.dynlib: dllname, importc: "glNormal3b".}
+proc glNormal3bv*(v: PGLbyte){.dynlib: dllname, importc: "glNormal3bv".}
+proc glNormal3d*(nx, ny, nz: TGLdouble){.dynlib: dllname, importc: "glNormal3d".}
+proc glNormal3dv*(v: PGLdouble){.dynlib: dllname, importc: "glNormal3dv".}
+proc glNormal3f*(nx, ny, nz: TGLfloat){.dynlib: dllname, importc: "glNormal3f".}
+proc glNormal3fv*(v: PGLfloat){.dynlib: dllname, importc: "glNormal3fv".}
+proc glNormal3i*(nx, ny, nz: TGLint){.dynlib: dllname, importc: "glNormal3i".}
+proc glNormal3iv*(v: PGLint){.dynlib: dllname, importc: "glNormal3iv".}
+proc glNormal3s*(nx, ny, nz: TGLshort){.dynlib: dllname, importc: "glNormal3s".}
+proc glNormal3sv*(v: PGLshort){.dynlib: dllname, importc: "glNormal3sv".}
+proc glNormalPointer*(atype: TGLenum, stride: TGLsizei, p: pointer){.
+    dynlib: dllname, importc: "glNormalPointer".}
+proc glOrtho*(left, right, bottom, top, zNear, zFar: TGLdouble){.
+    dynlib: dllname, importc: "glOrtho".}
+proc glPassThrough*(token: TGLfloat){.dynlib: dllname, importc: "glPassThrough".}
+proc glPixelMapfv*(map: TGLenum, mapsize: TGLsizei, values: PGLfloat){.
+    dynlib: dllname, importc: "glPixelMapfv".}
+proc glPixelMapuiv*(map: TGLenum, mapsize: TGLsizei, values: PGLuint){.
+    dynlib: dllname, importc: "glPixelMapuiv".}
+proc glPixelMapusv*(map: TGLenum, mapsize: TGLsizei, values: PGLushort){.
+    dynlib: dllname, importc: "glPixelMapusv".}
+proc glPixelStoref*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glPixelStoref".}
+proc glPixelStorei*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glPixelStorei".}
+proc glPixelTransferf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glPixelTransferf".}
+proc glPixelTransferi*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glPixelTransferi".}
+proc glPixelZoom*(xfactor, yfactor: TGLfloat){.dynlib: dllname,
+    importc: "glPixelZoom".}
+proc glPointSize*(size: TGLfloat){.dynlib: dllname, importc: "glPointSize".}
+proc glPolygonMode*(face, mode: TGLenum){.dynlib: dllname,
+    importc: "glPolygonMode".}
+proc glPolygonOffset*(factor, units: TGLfloat){.dynlib: dllname,
+    importc: "glPolygonOffset".}
+proc glPolygonStipple*(mask: PGLubyte){.dynlib: dllname,
+                                        importc: "glPolygonStipple".}
+proc glPopAttrib*(){.dynlib: dllname, importc: "glPopAttrib".}
+proc glPopClientAttrib*(){.dynlib: dllname, importc: "glPopClientAttrib".}
+proc glPopMatrix*(){.dynlib: dllname, importc: "glPopMatrix".}
+proc glPopName*(){.dynlib: dllname, importc: "glPopName".}
+proc glPrioritizeTextures*(n: TGLsizei, textures: PGLuint, priorities: PGLclampf){.
+    dynlib: dllname, importc: "glPrioritizeTextures".}
+proc glPushAttrib*(mask: TGLbitfield){.dynlib: dllname, importc: "glPushAttrib".}
+proc glPushClientAttrib*(mask: TGLbitfield){.dynlib: dllname,
+    importc: "glPushClientAttrib".}
+proc glPushMatrix*(){.dynlib: dllname, importc: "glPushMatrix".}
+proc glPushName*(name: TGLuint){.dynlib: dllname, importc: "glPushName".}
+proc glRasterPos2d*(x, y: TGLdouble){.dynlib: dllname, importc: "glRasterPos2d".}
+proc glRasterPos2dv*(v: PGLdouble){.dynlib: dllname, importc: "glRasterPos2dv".}
+proc glRasterPos2f*(x, y: TGLfloat){.dynlib: dllname, importc: "glRasterPos2f".}
+proc glRasterPos2fv*(v: PGLfloat){.dynlib: dllname, importc: "glRasterPos2fv".}
+proc glRasterPos2i*(x, y: TGLint){.dynlib: dllname, importc: "glRasterPos2i".}
+proc glRasterPos2iv*(v: PGLint){.dynlib: dllname, importc: "glRasterPos2iv".}
+proc glRasterPos2s*(x, y: TGLshort){.dynlib: dllname, importc: "glRasterPos2s".}
+proc glRasterPos2sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos2sv".}
+proc glRasterPos3d*(x, y, z: TGLdouble){.dynlib: dllname,
+    importc: "glRasterPos3d".}
+proc glRasterPos3dv*(v: PGLdouble){.dynlib: dllname, importc: "glRasterPos3dv".}
+proc glRasterPos3f*(x, y, z: TGLfloat){.dynlib: dllname,
+                                        importc: "glRasterPos3f".}
+proc glRasterPos3fv*(v: PGLfloat){.dynlib: dllname, importc: "glRasterPos3fv".}
+proc glRasterPos3i*(x, y, z: TGLint){.dynlib: dllname, importc: "glRasterPos3i".}
+proc glRasterPos3iv*(v: PGLint){.dynlib: dllname, importc: "glRasterPos3iv".}
+proc glRasterPos3s*(x, y, z: TGLshort){.dynlib: dllname,
+                                        importc: "glRasterPos3s".}
+proc glRasterPos3sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos3sv".}
+proc glRasterPos4d*(x, y, z, w: TGLdouble){.dynlib: dllname,
+    importc: "glRasterPos4d".}
+proc glRasterPos4dv*(v: PGLdouble){.dynlib: dllname, importc: "glRasterPos4dv".}
+proc glRasterPos4f*(x, y, z, w: TGLfloat){.dynlib: dllname,
+    importc: "glRasterPos4f".}
+proc glRasterPos4fv*(v: PGLfloat){.dynlib: dllname, importc: "glRasterPos4fv".}
+proc glRasterPos4i*(x, y, z, w: TGLint){.dynlib: dllname,
+    importc: "glRasterPos4i".}
+proc glRasterPos4iv*(v: PGLint){.dynlib: dllname, importc: "glRasterPos4iv".}
+proc glRasterPos4s*(x, y, z, w: TGLshort){.dynlib: dllname,
+    importc: "glRasterPos4s".}
+proc glRasterPos4sv*(v: PGLshort){.dynlib: dllname, importc: "glRasterPos4sv".}
+proc glReadBuffer*(mode: TGLenum){.dynlib: dllname, importc: "glReadBuffer".}
+proc glReadPixels*(x, y: TGLint, width, height: TGLsizei,
+                   format, atype: TGLenum, pixels: pointer){.dynlib: dllname,
+    importc: "glReadPixels".}
+proc glRectd*(x1, y1, x2, y2: TGLdouble){.dynlib: dllname, importc: "glRectd".}
+proc glRectdv*(v1: PGLdouble, v2: PGLdouble){.dynlib: dllname,
+    importc: "glRectdv".}
+proc glRectf*(x1, y1, x2, y2: TGLfloat){.dynlib: dllname, importc: "glRectf".}
+proc glRectfv*(v1: PGLfloat, v2: PGLfloat){.dynlib: dllname, importc: "glRectfv".}
+proc glRecti*(x1, y1, x2, y2: TGLint){.dynlib: dllname, importc: "glRecti".}
+proc glRectiv*(v1: PGLint, v2: PGLint){.dynlib: dllname, importc: "glRectiv".}
+proc glRects*(x1, y1, x2, y2: TGLshort){.dynlib: dllname, importc: "glRects".}
+proc glRectsv*(v1: PGLshort, v2: PGLshort){.dynlib: dllname, importc: "glRectsv".}
+proc glRenderMode*(mode: TGLint): TGLint{.dynlib: dllname,
+    importc: "glRenderMode".}
+proc glRotated*(angle, x, y, z: TGLdouble){.dynlib: dllname,
+    importc: "glRotated".}
+proc glRotatef*(angle, x, y, z: TGLfloat){.dynlib: dllname, importc: "glRotatef".}
+proc glScaled*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glScaled".}
+proc glScalef*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glScalef".}
+proc glScissor*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname,
+    importc: "glScissor".}
+proc glSelectBuffer*(size: TGLsizei, buffer: PGLuint){.dynlib: dllname,
+    importc: "glSelectBuffer".}
+proc glShadeModel*(mode: TGLenum){.dynlib: dllname, importc: "glShadeModel".}
+proc glStencilFunc*(fun: TGLenum, theref: TGLint, mask: TGLuint){.
+    dynlib: dllname, importc: "glStencilFunc".}
+proc glStencilMask*(mask: TGLuint){.dynlib: dllname, importc: "glStencilMask".}
+proc glStencilOp*(fail, zfail, zpass: TGLenum){.dynlib: dllname,
+    importc: "glStencilOp".}
+proc glTexCoord1d*(s: TGLdouble){.dynlib: dllname, importc: "glTexCoord1d".}
+proc glTexCoord1dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord1dv".}
+proc glTexCoord1f*(s: TGLfloat){.dynlib: dllname, importc: "glTexCoord1f".}
+proc glTexCoord1fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord1fv".}
+proc glTexCoord1i*(s: TGLint){.dynlib: dllname, importc: "glTexCoord1i".}
+proc glTexCoord1iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord1iv".}
+proc glTexCoord1s*(s: TGLshort){.dynlib: dllname, importc: "glTexCoord1s".}
+proc glTexCoord1sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord1sv".}
+proc glTexCoord2d*(s, t: TGLdouble){.dynlib: dllname, importc: "glTexCoord2d".}
+proc glTexCoord2dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord2dv".}
+proc glTexCoord2f*(s, t: TGLfloat){.dynlib: dllname, importc: "glTexCoord2f".}
+proc glTexCoord2fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord2fv".}
+proc glTexCoord2i*(s, t: TGLint){.dynlib: dllname, importc: "glTexCoord2i".}
+proc glTexCoord2iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord2iv".}
+proc glTexCoord2s*(s, t: TGLshort){.dynlib: dllname, importc: "glTexCoord2s".}
+proc glTexCoord2sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord2sv".}
+proc glTexCoord3d*(s, t, r: TGLdouble){.dynlib: dllname, importc: "glTexCoord3d".}
+proc glTexCoord3dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord3dv".}
+proc glTexCoord3f*(s, t, r: TGLfloat){.dynlib: dllname, importc: "glTexCoord3f".}
+proc glTexCoord3fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord3fv".}
+proc glTexCoord3i*(s, t, r: TGLint){.dynlib: dllname, importc: "glTexCoord3i".}
+proc glTexCoord3iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord3iv".}
+proc glTexCoord3s*(s, t, r: TGLshort){.dynlib: dllname, importc: "glTexCoord3s".}
+proc glTexCoord3sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord3sv".}
+proc glTexCoord4d*(s, t, r, q: TGLdouble){.dynlib: dllname,
+    importc: "glTexCoord4d".}
+proc glTexCoord4dv*(v: PGLdouble){.dynlib: dllname, importc: "glTexCoord4dv".}
+proc glTexCoord4f*(s, t, r, q: TGLfloat){.dynlib: dllname,
+    importc: "glTexCoord4f".}
+proc glTexCoord4fv*(v: PGLfloat){.dynlib: dllname, importc: "glTexCoord4fv".}
+proc glTexCoord4i*(s, t, r, q: TGLint){.dynlib: dllname, importc: "glTexCoord4i".}
+proc glTexCoord4iv*(v: PGLint){.dynlib: dllname, importc: "glTexCoord4iv".}
+proc glTexCoord4s*(s, t, r, q: TGLshort){.dynlib: dllname,
+    importc: "glTexCoord4s".}
+proc glTexCoord4sv*(v: PGLshort){.dynlib: dllname, importc: "glTexCoord4sv".}
+proc glTexCoordPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei,
+                        p: pointer){.dynlib: dllname,
+    importc: "glTexCoordPointer".}
+proc glTexEnvf*(target: TGLenum, pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glTexEnvf".}
+proc glTexEnvfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glTexEnvfv".}
+proc glTexEnvi*(target: TGLenum, pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glTexEnvi".}
+proc glTexEnviv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glTexEnviv".}
+proc glTexGend*(coord: TGLenum, pname: TGLenum, param: TGLdouble){.
+    dynlib: dllname, importc: "glTexGend".}
+proc glTexGendv*(coord: TGLenum, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glTexGendv".}
+proc glTexGenf*(coord: TGLenum, pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glTexGenf".}
+proc glTexGenfv*(coord: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glTexGenfv".}
+proc glTexGeni*(coord: TGLenum, pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glTexGeni".}
+proc glTexGeniv*(coord: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glTexGeniv".}
+proc glTexImage1D*(target: TGLenum, level, internalformat: TGLint,
+                   width: TGLsizei, border: TGLint, format, atype: TGLenum,
+                   pixels: pointer){.dynlib: dllname, importc: "glTexImage1D".}
+proc glTexImage2D*(target: TGLenum, level, internalformat: TGLint,
+                   width, height: TGLsizei, border: TGLint,
+                   format, atype: TGLenum, pixels: pointer){.dynlib: dllname,
+    importc: "glTexImage2D".}
+proc glTexParameterf*(target: TGLenum, pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glTexParameterf".}
+proc glTexParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glTexParameterfv".}
+proc glTexParameteri*(target: TGLenum, pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glTexParameteri".}
+proc glTexParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glTexParameteriv".}
+proc glTexSubImage1D*(target: TGLenum, level, xoffset: TGLint, width: TGLsizei,
+                      format, atype: TGLenum, pixels: pointer){.dynlib: dllname,
+    importc: "glTexSubImage1D".}
+proc glTexSubImage2D*(target: TGLenum, level, xoffset, yoffset: TGLint,
+                      width, height: TGLsizei, format, atype: TGLenum,
+                      pixels: pointer){.dynlib: dllname,
+                                        importc: "glTexSubImage2D".}
+proc glTranslated*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glTranslated".}
+proc glTranslatef*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glTranslatef".}
+proc glVertex2d*(x, y: TGLdouble){.dynlib: dllname, importc: "glVertex2d".}
+proc glVertex2dv*(v: PGLdouble){.dynlib: dllname, importc: "glVertex2dv".}
+proc glVertex2f*(x, y: TGLfloat){.dynlib: dllname, importc: "glVertex2f".}
+proc glVertex2fv*(v: PGLfloat){.dynlib: dllname, importc: "glVertex2fv".}
+proc glVertex2i*(x, y: TGLint){.dynlib: dllname, importc: "glVertex2i".}
+proc glVertex2iv*(v: PGLint){.dynlib: dllname, importc: "glVertex2iv".}
+proc glVertex2s*(x, y: TGLshort){.dynlib: dllname, importc: "glVertex2s".}
+proc glVertex2sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex2sv".}
+proc glVertex3d*(x, y, z: TGLdouble){.dynlib: dllname, importc: "glVertex3d".}
+proc glVertex3dv*(v: PGLdouble){.dynlib: dllname, importc: "glVertex3dv".}
+proc glVertex3f*(x, y, z: TGLfloat){.dynlib: dllname, importc: "glVertex3f".}
+proc glVertex3fv*(v: PGLfloat){.dynlib: dllname, importc: "glVertex3fv".}
+proc glVertex3i*(x, y, z: TGLint){.dynlib: dllname, importc: "glVertex3i".}
+proc glVertex3iv*(v: PGLint){.dynlib: dllname, importc: "glVertex3iv".}
+proc glVertex3s*(x, y, z: TGLshort){.dynlib: dllname, importc: "glVertex3s".}
+proc glVertex3sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex3sv".}
+proc glVertex4d*(x, y, z, w: TGLdouble){.dynlib: dllname, importc: "glVertex4d".}
+proc glVertex4dv*(v: PGLdouble){.dynlib: dllname, importc: "glVertex4dv".}
+proc glVertex4f*(x, y, z, w: TGLfloat){.dynlib: dllname, importc: "glVertex4f".}
+proc glVertex4fv*(v: PGLfloat){.dynlib: dllname, importc: "glVertex4fv".}
+proc glVertex4i*(x, y, z, w: TGLint){.dynlib: dllname, importc: "glVertex4i".}
+proc glVertex4iv*(v: PGLint){.dynlib: dllname, importc: "glVertex4iv".}
+proc glVertex4s*(x, y, z, w: TGLshort){.dynlib: dllname, importc: "glVertex4s".}
+proc glVertex4sv*(v: PGLshort){.dynlib: dllname, importc: "glVertex4sv".}
+proc glVertexPointer*(size: TGLint, atype: TGLenum, stride: TGLsizei,
+                      p: pointer){.dynlib: dllname,
+    importc: "glVertexPointer".}
+proc glViewport*(x, y: TGLint, width, height: TGLsizei){.dynlib: dllname,
+    importc: "glViewport".}
+type
+  PFN_GLARRAY_ELEMENT_EXTPROC* = proc (i: TGLint)
+  PFN_GLDRAW_ARRAYS_EXTPROC* = proc (mode: TGLenum, first: TGLint,
+                                     count: TGLsizei)
+  PFN_GLVERTEX_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum,
+                                        stride, count: TGLsizei,
+                                        p: pointer)
+  PFN_GLNORMAL_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei,
+                                        p: pointer)
+  PFN_GLCOLOR_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum,
+                                       stride, count: TGLsizei, p: pointer)
+  PFN_GLINDEX_POINTER_EXTPROC* = proc (atype: TGLenum, stride, count: TGLsizei,
+                                       p: pointer)
+  PFN_GLTEXCOORD_POINTER_EXTPROC* = proc (size: TGLint, atype: TGLenum,
+      stride, count: TGLsizei, p: pointer)
+  PFN_GLEDGEFLAG_POINTER_EXTPROC* = proc (stride, count: TGLsizei,
+      pointer: PGLboolean)
+  PFN_GLGET_POINTER_VEXT_PROC* = proc (pname: TGLenum, params: pointer)
+  PFN_GLARRAY_ELEMENT_ARRAY_EXTPROC* = proc (mode: TGLenum, count: TGLsizei,
+      pi: pointer)            # WIN_swap_hint
+  PFN_GLADDSWAPHINT_RECT_WINPROC* = proc (x, y: TGLint, width, height: TGLsizei)
+  PFN_GLCOLOR_TABLE_EXTPROC* = proc (target, internalFormat: TGLenum,
+                                     width: TGLsizei, format, atype: TGLenum,
+                                     data: pointer)
+  PFN_GLCOLOR_SUBTABLE_EXTPROC* = proc (target: TGLenum, start, count: TGLsizei,
+                                        format, atype: TGLenum, data: pointer)
+  PFN_GLGETCOLOR_TABLE_EXTPROC* = proc (target, format, atype: TGLenum,
+                                        data: pointer)
+  PFN_GLGETCOLOR_TABLE_PARAMETER_IVEXTPROC* = proc (target, pname: TGLenum,
+      params: PGLint)
+  PFN_GLGETCOLOR_TABLE_PARAMETER_FVEXTPROC* = proc (target, pname: TGLenum,
+      params: PGLfloat)
+
+{.pop.}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/glext.nim b/tests/manyloc/keineschweine/lib/glext.nim
new file mode 100644
index 000000000..1e1bdb958
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glext.nim
@@ -0,0 +1,4673 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#
+#
+
+#*************************************************
+# *        OpenGL extension loading library        *
+# * Generated by MetaGLext, written by Tom Nuydens *
+# *  (tom@delphi3d.net -- http://www.delphi3d.net  *
+# *************************************************
+#*** Generated on 10/11/2002
+
+when defined(windows):
+  {.push, callconv: stdcall.}
+else:
+  {.push, callconv: cdecl.}
+import
+  gl
+
+type
+  GLcharARB* = Char
+  TGLcharARB* = GLcharARB
+  PGLcharARB* = ptr GLcharARB
+  GLhandleARB* = int
+  TGLhandleARB* = GLhandleARB
+  PGLhandleARB* = ptr GLhandleARB
+  GLintptr* = int
+  TGLintptr* = GLintptr
+  PGLintptr* = ptr GLintptr
+  GLsizeiptr* = int
+  TGLsizeiptr* = GLsizeiptr
+  PGLsizeiptr* = ptr GLsizeiptr
+  GLchar* = Char
+  TGLchar* = GLchar
+  PGLchar* = cstring          #***** GL_version_1_2 *****//
+
+const
+  GL_UNSIGNED_BYTE_3_3_2* = 0x00008032
+  GL_UNSIGNED_SHORT_4_4_4_4* = 0x00008033
+  GL_UNSIGNED_SHORT_5_5_5_1* = 0x00008034
+  GL_UNSIGNED_INT_8_8_8_8* = 0x00008035
+  GL_UNSIGNED_INT_10_10_10_2* = 0x00008036
+  GL_RESCALE_NORMAL* = 0x0000803A
+  GL_UNSIGNED_BYTE_2_3_3_REV* = 0x00008362
+  GL_UNSIGNED_SHORT_5_6_5* = 0x00008363
+  GL_UNSIGNED_SHORT_5_6_5_REV* = 0x00008364
+  GL_UNSIGNED_SHORT_4_4_4_4_REV* = 0x00008365
+  GL_UNSIGNED_SHORT_1_5_5_5_REV* = 0x00008366
+  GL_UNSIGNED_INT_8_8_8_8_REV* = 0x00008367
+  GL_UNSIGNED_INT_2_10_10_10_REV* = 0x00008368
+  GL_BGR* = 0x000080E0
+  GL_BGRA* = 0x000080E1
+  GL_MAX_ELEMENTS_VERTICES* = 0x000080E8
+  GL_MAX_ELEMENTS_INDICES* = 0x000080E9
+  GL_CLAMP_TO_EDGE* = 0x0000812F
+  GL_TEXTURE_MIN_LOD* = 0x0000813A
+  GL_TEXTURE_MAX_LOD* = 0x0000813B
+  GL_TEXTURE_BASE_LEVEL* = 0x0000813C
+  GL_TEXTURE_MAX_LEVEL* = 0x0000813D
+  GL_LIGHT_MODEL_COLOR_CONTROL* = 0x000081F8
+  GL_SINGLE_COLOR* = 0x000081F9
+  GL_SEPARATE_SPECULAR_COLOR* = 0x000081FA
+  GL_SMOOTH_POINT_SIZE_RANGE* = 0x00000B12
+  GL_SMOOTH_POINT_SIZE_GRANULARITY* = 0x00000B13
+  GL_SMOOTH_LINE_WIDTH_RANGE* = 0x00000B22
+  GL_SMOOTH_LINE_WIDTH_GRANULARITY* = 0x00000B23
+  GL_ALIASED_POINT_SIZE_RANGE* = 0x0000846D
+  GL_ALIASED_LINE_WIDTH_RANGE* = 0x0000846E
+  GL_PACK_SKIP_IMAGES* = 0x0000806B
+  GL_PACK_IMAGE_HEIGHT* = 0x0000806C
+  GL_UNPACK_SKIP_IMAGES* = 0x0000806D
+  GL_UNPACK_IMAGE_HEIGHT* = 0x0000806E
+  GL_TEXTURE_3D* = 0x0000806F
+  GL_PROXY_TEXTURE_3D* = 0x00008070
+  GL_TEXTURE_DEPTH* = 0x00008071
+  GL_TEXTURE_WRAP_R* = 0x00008072
+  GL_MAX_3D_TEXTURE_SIZE* = 0x00008073
+
+proc glBlendColor*(red: TGLclampf, green: TGLclampf, blue: TGLclampf,
+                   alpha: TGLclampf){.dynlib: dllname, importc: "glBlendColor".}
+proc glBlendEquation*(mode: TGLenum){.dynlib: dllname,
+                                      importc: "glBlendEquation".}
+proc glDrawRangeElements*(mode: TGLenum, start: TGLuint, theend: TGLuint,
+                          count: TGLsizei, thetype: TGLenum, indices: PGLvoid){.
+    dynlib: dllname, importc: "glDrawRangeElements".}
+proc glColorTable*(target: TGLenum, internalformat: TGLenum, width: TGLsizei,
+                   format: TGLenum, thetype: TGLenum, table: PGLvoid){.
+    dynlib: dllname, importc: "glColorTable".}
+proc glColorTableParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glColorTableParameterfv".}
+proc glColorTableParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glColorTableParameteriv".}
+proc glCopyColorTable*(target: TGLenum, internalformat: TGLenum, x: TGLint,
+                       y: TGLint, width: TGLsizei){.dynlib: dllname,
+    importc: "glCopyColorTable".}
+proc glGetColorTable*(target: TGLenum, format: TGLenum, thetype: TGLenum,
+                      table: PGLvoid){.dynlib: dllname,
+                                       importc: "glGetColorTable".}
+proc glGetColorTableParameterfv*(target: TGLenum, pname: TGLenum,
+                                 params: PGLfloat){.dynlib: dllname,
+    importc: "glGetColorTableParameterfv".}
+proc glGetColorTableParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetColorTableParameteriv".}
+proc glColorSubTable*(target: TGLenum, start: TGLsizei, count: TGLsizei,
+                      format: TGLenum, thetype: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glColorSubTable".}
+proc glCopyColorSubTable*(target: TGLenum, start: TGLsizei, x: TGLint,
+                          y: TGLint, width: TGLsizei){.dynlib: dllname,
+    importc: "glCopyColorSubTable".}
+proc glConvolutionFilter1D*(target: TGLenum, internalformat: TGLenum,
+                            width: TGLsizei, format: TGLenum, thetype: TGLenum,
+                            image: PGLvoid){.dynlib: dllname,
+    importc: "glConvolutionFilter1D".}
+proc glConvolutionFilter2D*(target: TGLenum, internalformat: TGLenum,
+                            width: TGLsizei, height: TGLsizei, format: TGLenum,
+                            thetype: TGLenum, image: PGLvoid){.dynlib: dllname,
+    importc: "glConvolutionFilter2D".}
+proc glConvolutionParameterf*(target: TGLenum, pname: TGLenum, params: TGLfloat){.
+    dynlib: dllname, importc: "glConvolutionParameterf".}
+proc glConvolutionParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glConvolutionParameterfv".}
+proc glConvolutionParameteri*(target: TGLenum, pname: TGLenum, params: TGLint){.
+    dynlib: dllname, importc: "glConvolutionParameteri".}
+proc glConvolutionParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glConvolutionParameteriv".}
+proc glCopyConvolutionFilter1D*(target: TGLenum, internalformat: TGLenum,
+                                x: TGLint, y: TGLint, width: TGLsizei){.
+    dynlib: dllname, importc: "glCopyConvolutionFilter1D".}
+proc glCopyConvolutionFilter2D*(target: TGLenum, internalformat: TGLenum,
+                                x: TGLint, y: TGLint, width: TGLsizei,
+                                height: TGLsizei){.dynlib: dllname,
+    importc: "glCopyConvolutionFilter2D".}
+proc glGetConvolutionFilter*(target: TGLenum, format: TGLenum, thetype: TGLenum,
+                             image: PGLvoid){.dynlib: dllname,
+    importc: "glGetConvolutionFilter".}
+proc glGetConvolutionParameterfv*(target: TGLenum, pname: TGLenum,
+                                  params: PGLfloat){.dynlib: dllname,
+    importc: "glGetConvolutionParameterfv".}
+proc glGetConvolutionParameteriv*(target: TGLenum, pname: TGLenum,
+                                  params: PGLint){.dynlib: dllname,
+    importc: "glGetConvolutionParameteriv".}
+proc glGetSeparableFilter*(target: TGLenum, format: TGLenum, thetype: TGLenum,
+                           row: PGLvoid, column: PGLvoid, span: PGLvoid){.
+    dynlib: dllname, importc: "glGetSeparableFilter".}
+proc glSeparableFilter2D*(target: TGLenum, internalformat: TGLenum,
+                          width: TGLsizei, height: TGLsizei, format: TGLenum,
+                          thetype: TGLenum, row: PGLvoid, column: PGLvoid){.
+    dynlib: dllname, importc: "glSeparableFilter2D".}
+proc glGetHistogram*(target: TGLenum, reset: TGLboolean, format: TGLenum,
+                     thetype: TGLenum, values: PGLvoid){.dynlib: dllname,
+    importc: "glGetHistogram".}
+proc glGetHistogramParameterfv*(target: TGLenum, pname: TGLenum,
+                                params: PGLfloat){.dynlib: dllname,
+    importc: "glGetHistogramParameterfv".}
+proc glGetHistogramParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetHistogramParameteriv".}
+proc glGetMinmax*(target: TGLenum, reset: TGLboolean, format: TGLenum,
+                  thetype: TGLenum, values: PGLvoid){.dynlib: dllname,
+    importc: "glGetMinmax".}
+proc glGetMinmaxParameterfv*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetMinmaxParameterfv".}
+proc glGetMinmaxParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMinmaxParameteriv".}
+proc glHistogram*(target: TGLenum, width: TGLsizei, internalformat: TGLenum,
+                  sink: TGLboolean){.dynlib: dllname, importc: "glHistogram".}
+proc glMinmax*(target: TGLenum, internalformat: TGLenum, sink: TGLboolean){.
+    dynlib: dllname, importc: "glMinmax".}
+proc glResetHistogram*(target: TGLenum){.dynlib: dllname,
+    importc: "glResetHistogram".}
+proc glResetMinmax*(target: TGLenum){.dynlib: dllname, importc: "glResetMinmax".}
+proc glTexImage3D*(target: TGLenum, level: TGLint, internalformat: TGLint,
+                   width: TGLsizei, height: TGLsizei, depth: TGLsizei,
+                   border: TGLint, format: TGLenum, thetype: TGLenum,
+                   pixels: PGLvoid){.dynlib: dllname, importc: "glTexImage3D".}
+proc glTexSubImage3D*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                      yoffset: TGLint, zoffset: TGLint, width: TGLsizei,
+                      height: TGLsizei, depth: TGLsizei, format: TGLenum,
+                      thetype: TGLenum, pixels: PGLvoid){.dynlib: dllname,
+    importc: "glTexSubImage3D".}
+proc glCopyTexSubImage3D*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                          yoffset: TGLint, zoffset: TGLint, x: TGLint,
+                          y: TGLint, width: TGLsizei, height: TGLsizei){.
+    dynlib: dllname, importc: "glCopyTexSubImage3D".}
+proc glActiveTextureARB*(texture: TGLenum){.dynlib: dllname,
+    importc: "glActiveTextureARB".}
+proc glClientActiveTextureARB*(texture: TGLenum){.dynlib: dllname,
+    importc: "glClientActiveTextureARB".}
+proc glMultiTexCoord1dARB*(target: TGLenum, s: TGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord1dARB".}
+proc glMultiTexCoord1dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord1dvARB".}
+proc glMultiTexCoord1fARB*(target: TGLenum, s: TGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord1fARB".}
+proc glMultiTexCoord1fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord1fvARB".}
+proc glMultiTexCoord1iARB*(target: TGLenum, s: TGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord1iARB".}
+proc glMultiTexCoord1ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord1ivARB".}
+proc glMultiTexCoord1sARB*(target: TGLenum, s: TGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord1sARB".}
+proc glMultiTexCoord1svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord1svARB".}
+proc glMultiTexCoord2dARB*(target: TGLenum, s: TGLdouble, t: TGLdouble){.
+    dynlib: dllname, importc: "glMultiTexCoord2dARB".}
+proc glMultiTexCoord2dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord2dvARB".}
+proc glMultiTexCoord2fARB*(target: TGLenum, s: TGLfloat, t: TGLfloat){.
+    dynlib: dllname, importc: "glMultiTexCoord2fARB".}
+proc glMultiTexCoord2fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord2fvARB".}
+proc glMultiTexCoord2iARB*(target: TGLenum, s: TGLint, t: TGLint){.
+    dynlib: dllname, importc: "glMultiTexCoord2iARB".}
+proc glMultiTexCoord2ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord2ivARB".}
+proc glMultiTexCoord2sARB*(target: TGLenum, s: TGLshort, t: TGLshort){.
+    dynlib: dllname, importc: "glMultiTexCoord2sARB".}
+proc glMultiTexCoord2svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord2svARB".}
+proc glMultiTexCoord3dARB*(target: TGLenum, s: TGLdouble, t: TGLdouble,
+                           r: TGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord3dARB".}
+proc glMultiTexCoord3dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord3dvARB".}
+proc glMultiTexCoord3fARB*(target: TGLenum, s: TGLfloat, t: TGLfloat,
+                           r: TGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord3fARB".}
+proc glMultiTexCoord3fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord3fvARB".}
+proc glMultiTexCoord3iARB*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint){.
+    dynlib: dllname, importc: "glMultiTexCoord3iARB".}
+proc glMultiTexCoord3ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord3ivARB".}
+proc glMultiTexCoord3sARB*(target: TGLenum, s: TGLshort, t: TGLshort,
+                           r: TGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord3sARB".}
+proc glMultiTexCoord3svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord3svARB".}
+proc glMultiTexCoord4dARB*(target: TGLenum, s: TGLdouble, t: TGLdouble,
+                           r: TGLdouble, q: TGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord4dARB".}
+proc glMultiTexCoord4dvARB*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord4dvARB".}
+proc glMultiTexCoord4fARB*(target: TGLenum, s: TGLfloat, t: TGLfloat,
+                           r: TGLfloat, q: TGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord4fARB".}
+proc glMultiTexCoord4fvARB*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord4fvARB".}
+proc glMultiTexCoord4iARB*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint,
+                           q: TGLint){.dynlib: dllname,
+                                       importc: "glMultiTexCoord4iARB".}
+proc glMultiTexCoord4ivARB*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord4ivARB".}
+proc glMultiTexCoord4sARB*(target: TGLenum, s: TGLshort, t: TGLshort,
+                           r: TGLshort, q: TGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord4sARB".}
+proc glMultiTexCoord4svARB*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord4svARB".}
+proc glSampleCoverageARB*(value: TGLclampf, invert: TGLboolean){.
+    dynlib: dllname, importc: "glSampleCoverageARB".}
+  #***** GL_ARB_texture_env_add *****//
+proc glWeightbvARB*(size: TGLint, weights: PGLbyte){.dynlib: dllname,
+    importc: "glWeightbvARB".}
+proc glWeightsvARB*(size: TGLint, weights: PGLshort){.dynlib: dllname,
+    importc: "glWeightsvARB".}
+proc glWeightivARB*(size: TGLint, weights: PGLint){.dynlib: dllname,
+    importc: "glWeightivARB".}
+proc glWeightfvARB*(size: TGLint, weights: PGLfloat){.dynlib: dllname,
+    importc: "glWeightfvARB".}
+proc glWeightdvARB*(size: TGLint, weights: PGLdouble){.dynlib: dllname,
+    importc: "glWeightdvARB".}
+proc glWeightvARB*(size: TGLint, weights: PGLdouble){.dynlib: dllname,
+    importc: "glWeightvARB".}
+proc glWeightubvARB*(size: TGLint, weights: PGLubyte){.dynlib: dllname,
+    importc: "glWeightubvARB".}
+proc glWeightusvARB*(size: TGLint, weights: PGLushort){.dynlib: dllname,
+    importc: "glWeightusvARB".}
+proc glWeightuivARB*(size: TGLint, weights: PGLuint){.dynlib: dllname,
+    importc: "glWeightuivARB".}
+proc glWeightPointerARB*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                         pointer: PGLvoid){.dynlib: dllname,
+    importc: "glWeightPointerARB".}
+proc glVertexBlendARB*(count: TGLint){.dynlib: dllname,
+                                       importc: "glVertexBlendARB".}
+proc glVertexAttrib1sARB*(index: TGLuint, x: TGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib1sARB".}
+proc glVertexAttrib1fARB*(index: TGLuint, x: TGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib1fARB".}
+proc glVertexAttrib1dARB*(index: TGLuint, x: TGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib1dARB".}
+proc glVertexAttrib2sARB*(index: TGLuint, x: TGLshort, y: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib2sARB".}
+proc glVertexAttrib2fARB*(index: TGLuint, x: TGLfloat, y: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib2fARB".}
+proc glVertexAttrib2dARB*(index: TGLuint, x: TGLdouble, y: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib2dARB".}
+proc glVertexAttrib3sARB*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib3sARB".}
+proc glVertexAttrib3fARB*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib3fARB".}
+proc glVertexAttrib3dARB*(index: TGLuint, x: TGLdouble, y: TGLdouble,
+                          z: TGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib3dARB".}
+proc glVertexAttrib4sARB*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort,
+                          w: TGLshort){.dynlib: dllname,
+                                        importc: "glVertexAttrib4sARB".}
+proc glVertexAttrib4fARB*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat,
+                          w: TGLfloat){.dynlib: dllname,
+                                        importc: "glVertexAttrib4fARB".}
+proc glVertexAttrib4dARB*(index: TGLuint, x: TGLdouble, y: TGLdouble,
+                          z: TGLdouble, w: TGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib4dARB".}
+proc glVertexAttrib4NubARB*(index: TGLuint, x: TGLubyte, y: TGLubyte,
+                            z: TGLubyte, w: TGLubyte){.dynlib: dllname,
+    importc: "glVertexAttrib4NubARB".}
+proc glVertexAttrib1svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib1svARB".}
+proc glVertexAttrib1fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib1fvARB".}
+proc glVertexAttrib1dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib1dvARB".}
+proc glVertexAttrib2svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib2svARB".}
+proc glVertexAttrib2fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib2fvARB".}
+proc glVertexAttrib2dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib2dvARB".}
+proc glVertexAttrib3svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib3svARB".}
+proc glVertexAttrib3fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib3fvARB".}
+proc glVertexAttrib3dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib3dvARB".}
+proc glVertexAttrib4bvARB*(index: TGLuint, v: PGLbyte){.dynlib: dllname,
+    importc: "glVertexAttrib4bvARB".}
+proc glVertexAttrib4svARB*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib4svARB".}
+proc glVertexAttrib4ivARB*(index: TGLuint, v: PGLint){.dynlib: dllname,
+    importc: "glVertexAttrib4ivARB".}
+proc glVertexAttrib4ubvARB*(index: TGLuint, v: PGLubyte){.dynlib: dllname,
+    importc: "glVertexAttrib4ubvARB".}
+proc glVertexAttrib4usvARB*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib4usvARB".}
+proc glVertexAttrib4uivARB*(index: TGLuint, v: PGLuint){.dynlib: dllname,
+    importc: "glVertexAttrib4uivARB".}
+proc glVertexAttrib4fvARB*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib4fvARB".}
+proc glVertexAttrib4dvARB*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib4dvARB".}
+proc glVertexAttrib4NbvARB*(index: TGLuint, v: PGLbyte){.dynlib: dllname,
+    importc: "glVertexAttrib4NbvARB".}
+proc glVertexAttrib4NsvARB*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib4NsvARB".}
+proc glVertexAttrib4NivARB*(index: TGLuint, v: PGLint){.dynlib: dllname,
+    importc: "glVertexAttrib4NivARB".}
+proc glVertexAttrib4NubvARB*(index: TGLuint, v: PGLubyte){.dynlib: dllname,
+    importc: "glVertexAttrib4NubvARB".}
+proc glVertexAttrib4NusvARB*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib4NusvARB".}
+proc glVertexAttrib4NuivARB*(index: TGLuint, v: PGLuint){.dynlib: dllname,
+    importc: "glVertexAttrib4NuivARB".}
+proc glVertexAttribPointerARB*(index: TGLuint, size: TGLint, thetype: TGLenum,
+                               normalized: TGLboolean, stride: TGLsizei,
+                               pointer: PGLvoid){.dynlib: dllname,
+    importc: "glVertexAttribPointerARB".}
+proc glEnableVertexAttribArrayARB*(index: TGLuint){.dynlib: dllname,
+    importc: "glEnableVertexAttribArrayARB".}
+proc glDisableVertexAttribArrayARB*(index: TGLuint){.dynlib: dllname,
+    importc: "glDisableVertexAttribArrayARB".}
+proc glProgramStringARB*(target: TGLenum, format: TGLenum, length: TGLsizei,
+                         str: PGLvoid){.dynlib: dllname,
+                                        importc: "glProgramStringARB".}
+proc glBindProgramARB*(target: TGLenum, theProgram: TGLuint){.dynlib: dllname,
+    importc: "glBindProgramARB".}
+proc glDeleteProgramsARB*(n: TGLsizei, programs: PGLuint){.dynlib: dllname,
+    importc: "glDeleteProgramsARB".}
+proc glGenProgramsARB*(n: TGLsizei, programs: PGLuint){.dynlib: dllname,
+    importc: "glGenProgramsARB".}
+proc glProgramEnvParameter4dARB*(target: TGLenum, index: TGLuint, x: TGLdouble,
+                                 y: TGLdouble, z: TGLdouble, w: TGLdouble){.
+    dynlib: dllname, importc: "glProgramEnvParameter4dARB".}
+proc glProgramEnvParameter4dvARB*(target: TGLenum, index: TGLuint,
+                                  params: PGLdouble){.dynlib: dllname,
+    importc: "glProgramEnvParameter4dvARB".}
+proc glProgramEnvParameter4fARB*(target: TGLenum, index: TGLuint, x: TGLfloat,
+                                 y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glProgramEnvParameter4fARB".}
+proc glProgramEnvParameter4fvARB*(target: TGLenum, index: TGLuint,
+                                  params: PGLfloat){.dynlib: dllname,
+    importc: "glProgramEnvParameter4fvARB".}
+proc glProgramLocalParameter4dARB*(target: TGLenum, index: TGLuint,
+                                   x: TGLdouble, y: TGLdouble, z: TGLdouble,
+                                   w: TGLdouble){.dynlib: dllname,
+    importc: "glProgramLocalParameter4dARB".}
+proc glProgramLocalParameter4dvARB*(target: TGLenum, index: TGLuint,
+                                    params: PGLdouble){.dynlib: dllname,
+    importc: "glProgramLocalParameter4dvARB".}
+proc glProgramLocalParameter4fARB*(target: TGLenum, index: TGLuint, x: TGLfloat,
+                                   y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glProgramLocalParameter4fARB".}
+proc glProgramLocalParameter4fvARB*(target: TGLenum, index: TGLuint,
+                                    params: PGLfloat){.dynlib: dllname,
+    importc: "glProgramLocalParameter4fvARB".}
+proc glGetProgramEnvParameterdvARB*(target: TGLenum, index: TGLuint,
+                                    params: PGLdouble){.dynlib: dllname,
+    importc: "glGetProgramEnvParameterdvARB".}
+proc glGetProgramEnvParameterfvARB*(target: TGLenum, index: TGLuint,
+                                    params: PGLfloat){.dynlib: dllname,
+    importc: "glGetProgramEnvParameterfvARB".}
+proc glGetProgramLocalParameterdvARB*(target: TGLenum, index: TGLuint,
+                                      params: PGLdouble){.dynlib: dllname,
+    importc: "glGetProgramLocalParameterdvARB".}
+proc glGetProgramLocalParameterfvARB*(target: TGLenum, index: TGLuint,
+                                      params: PGLfloat){.dynlib: dllname,
+    importc: "glGetProgramLocalParameterfvARB".}
+proc glGetProgramivARB*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetProgramivARB".}
+proc glGetProgramStringARB*(target: TGLenum, pname: TGLenum, str: PGLvoid){.
+    dynlib: dllname, importc: "glGetProgramStringARB".}
+proc glGetVertexAttribdvARB*(index: TGLuint, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetVertexAttribdvARB".}
+proc glGetVertexAttribfvARB*(index: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVertexAttribfvARB".}
+proc glGetVertexAttribivARB*(index: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVertexAttribivARB".}
+proc glGetVertexAttribPointervARB*(index: TGLuint, pname: TGLenum,
+                                   pointer: PGLvoid){.dynlib: dllname,
+    importc: "glGetVertexAttribPointervARB".}
+proc glIsProgramARB*(theProgram: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsProgramARB".}
+  #***** GL_ARB_window_pos *****//
+proc glWindowPos2dARB*(x: TGLdouble, y: TGLdouble){.dynlib: dllname,
+    importc: "glWindowPos2dARB".}
+proc glWindowPos2fARB*(x: TGLfloat, y: TGLfloat){.dynlib: dllname,
+    importc: "glWindowPos2fARB".}
+proc glWindowPos2iARB*(x: TGLint, y: TGLint){.dynlib: dllname,
+    importc: "glWindowPos2iARB".}
+proc glWindowPos2sARB*(x: TGLshort, y: TGLshort){.dynlib: dllname,
+    importc: "glWindowPos2sARB".}
+proc glWindowPos2dvARB*(p: PGLdouble){.dynlib: dllname,
+                                       importc: "glWindowPos2dvARB".}
+proc glWindowPos2fvARB*(p: PGLfloat){.dynlib: dllname,
+                                      importc: "glWindowPos2fvARB".}
+proc glWindowPos2ivARB*(p: PGLint){.dynlib: dllname,
+                                    importc: "glWindowPos2ivARB".}
+proc glWindowPos2svARB*(p: PGLshort){.dynlib: dllname,
+                                      importc: "glWindowPos2svARB".}
+proc glWindowPos3dARB*(x: TGLdouble, y: TGLdouble, z: TGLdouble){.
+    dynlib: dllname, importc: "glWindowPos3dARB".}
+proc glWindowPos3fARB*(x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glWindowPos3fARB".}
+proc glWindowPos3iARB*(x: TGLint, y: TGLint, z: TGLint){.dynlib: dllname,
+    importc: "glWindowPos3iARB".}
+proc glWindowPos3sARB*(x: TGLshort, y: TGLshort, z: TGLshort){.dynlib: dllname,
+    importc: "glWindowPos3sARB".}
+proc glWindowPos3dvARB*(p: PGLdouble){.dynlib: dllname,
+                                       importc: "glWindowPos3dvARB".}
+proc glWindowPos3fvARB*(p: PGLfloat){.dynlib: dllname,
+                                      importc: "glWindowPos3fvARB".}
+proc glWindowPos3ivARB*(p: PGLint){.dynlib: dllname,
+                                    importc: "glWindowPos3ivARB".}
+proc glWindowPos3svARB*(p: PGLshort){.dynlib: dllname,
+                                      importc: "glWindowPos3svARB".}
+proc glBlendEquationSeparate*(modeRGB: TGLenum, modeAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendEquationSeparate".}
+proc glDrawBuffers*(n: TGLsizei, bufs: PGLenum){.dynlib: dllname,
+    importc: "glDrawBuffers".}
+proc glStencilOpSeparate*(face: TGLenum, sfail: TGLenum, dpfail: TGLenum,
+                          dppass: TGLenum){.dynlib: dllname,
+    importc: "glStencilOpSeparate".}
+proc glStencilFuncSeparate*(frontfunc: TGLenum, backfunc: TGLenum,
+                            theRef: TGLint, mask: TGLuint){.dynlib: dllname,
+    importc: "glStencilFuncSeparate".}
+proc glStencilMaskSeparate*(face: TGLenum, mask: TGLuint){.dynlib: dllname,
+    importc: "glStencilMaskSeparate".}
+proc glAttachShader*(theProgram: TGLuint, shader: TGLuint){.dynlib: dllname,
+    importc: "glAttachShader".}
+proc glBindAttribLocation*(theProgram: TGLuint, index: TGLuint, name: PGLchar){.
+    dynlib: dllname, importc: "glBindAttribLocation".}
+proc glCompileShader*(shader: TGLuint){.dynlib: dllname,
+                                        importc: "glCompileShader".}
+proc glCreateProgram*(): TGLuint{.dynlib: dllname, importc: "glCreateProgram".}
+proc glCreateShader*(thetype: TGLenum): TGLuint{.dynlib: dllname,
+    importc: "glCreateShader".}
+proc glDeleteProgram*(theProgram: TGLuint){.dynlib: dllname,
+    importc: "glDeleteProgram".}
+proc glDeleteShader*(shader: TGLuint){.dynlib: dllname,
+                                       importc: "glDeleteShader".}
+proc glDetachShader*(theProgram: TGLuint, shader: TGLuint){.dynlib: dllname,
+    importc: "glDetachShader".}
+proc glDisableVertexAttribArray*(index: TGLuint){.dynlib: dllname,
+    importc: "glDisableVertexAttribArray".}
+proc glEnableVertexAttribArray*(index: TGLuint){.dynlib: dllname,
+    importc: "glEnableVertexAttribArray".}
+proc glGetActiveAttrib*(theProgram: TGLuint, index: TGLuint, bufSize: TGLsizei,
+                        len: PGLsizei, size: PGLint, thetype: PGLenum,
+                        name: PGLchar){.dynlib: dllname,
+                                        importc: "glGetActiveAttrib".}
+proc glGetActiveUniform*(theProgram: TGLuint, index: TGLuint, bufSize: TGLsizei,
+                         len: PGLsizei, size: PGLint, thetype: PGLenum,
+                         name: PGLchar){.dynlib: dllname,
+    importc: "glGetActiveUniform".}
+proc glGetAttachedShaders*(theProgram: TGLuint, maxCount: TGLsizei,
+                           count: PGLsizei, obj: PGLuint){.dynlib: dllname,
+    importc: "glGetAttachedShaders".}
+proc glGetAttribLocation*(theProgram: TGLuint, name: PGLchar): TGLint{.
+    dynlib: dllname, importc: "glGetAttribLocation".}
+proc glGetProgramiv*(theProgram: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetProgramiv".}
+proc glGetProgramInfoLog*(theProgram: TGLuint, bufSize: TGLsizei, len: PGLsizei,
+                          infoLog: PGLchar){.dynlib: dllname,
+    importc: "glGetProgramInfoLog".}
+proc glGetShaderiv*(shader: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetShaderiv".}
+proc glGetShaderInfoLog*(shader: TGLuint, bufSize: TGLsizei, len: PGLsizei,
+                         infoLog: PGLchar){.dynlib: dllname,
+    importc: "glGetShaderInfoLog".}
+proc glGetShaderSource*(shader: TGLuint, bufSize: TGLsizei, len: PGLsizei,
+                        source: PGLchar){.dynlib: dllname,
+    importc: "glGetShaderSource".}
+proc glGetUniformLocation*(theProgram: TGLuint, name: PGLchar): TGLint{.
+    dynlib: dllname, importc: "glGetUniformLocation".}
+proc glGetUniformfv*(theProgram: TGLuint, location: TGLint, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetUniformfv".}
+proc glGetUniformiv*(theProgram: TGLuint, location: TGLint, params: PGLint){.
+    dynlib: dllname, importc: "glGetUniformiv".}
+proc glGetVertexAttribdv*(index: TGLuint, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetVertexAttribdv".}
+proc glGetVertexAttribfv*(index: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVertexAttribfv".}
+proc glGetVertexAttribiv*(index: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVertexAttribiv".}
+proc glGetVertexAttribPointerv*(index: TGLuint, pname: TGLenum, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glGetVertexAttribPointerv".}
+proc glIsProgram*(theProgram: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsProgram".}
+proc glIsShader*(shader: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsShader".}
+proc glLinkProgram*(theProgram: TGLuint){.dynlib: dllname,
+    importc: "glLinkProgram".}
+proc glShaderSource*(shader: TGLuint, count: TGLsizei, str: PGLchar, len: PGLint){.
+    dynlib: dllname, importc: "glShaderSource".}
+proc glUseProgram*(theProgram: TGLuint){.dynlib: dllname,
+    importc: "glUseProgram".}
+proc glUniform1f*(location: TGLint, v0: TGLfloat){.dynlib: dllname,
+    importc: "glUniform1f".}
+proc glUniform2f*(location: TGLint, v0: TGLfloat, v1: TGLfloat){.
+    dynlib: dllname, importc: "glUniform2f".}
+proc glUniform3f*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat){.
+    dynlib: dllname, importc: "glUniform3f".}
+proc glUniform4f*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat,
+                  v3: TGLfloat){.dynlib: dllname, importc: "glUniform4f".}
+proc glUniform1i*(location: TGLint, v0: TGLint){.dynlib: dllname,
+    importc: "glUniform1i".}
+proc glUniform2i*(location: TGLint, v0: TGLint, v1: TGLint){.dynlib: dllname,
+    importc: "glUniform2i".}
+proc glUniform3i*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint){.
+    dynlib: dllname, importc: "glUniform3i".}
+proc glUniform4i*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint,
+                  v3: TGLint){.dynlib: dllname, importc: "glUniform4i".}
+proc glUniform1fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform1fv".}
+proc glUniform2fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform2fv".}
+proc glUniform3fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform3fv".}
+proc glUniform4fv*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform4fv".}
+proc glUniform1iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform1iv".}
+proc glUniform2iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform2iv".}
+proc glUniform3iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform3iv".}
+proc glUniform4iv*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform4iv".}
+proc glUniformMatrix2fv*(location: TGLint, count: TGLsizei,
+                         transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix2fv".}
+proc glUniformMatrix3fv*(location: TGLint, count: TGLsizei,
+                         transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix3fv".}
+proc glUniformMatrix4fv*(location: TGLint, count: TGLsizei,
+                         transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix4fv".}
+proc glValidateProgram*(theProgram: TGLuint){.dynlib: dllname,
+    importc: "glValidateProgram".}
+proc glVertexAttrib1d*(index: TGLuint, x: TGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib1d".}
+proc glVertexAttrib1dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib1dv".}
+proc glVertexAttrib1f*(index: TGLuint, x: TGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib1f".}
+proc glVertexAttrib1fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib1fv".}
+proc glVertexAttrib1s*(index: TGLuint, x: TGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib1s".}
+proc glVertexAttrib1sv*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib1sv".}
+proc glVertexAttrib2d*(index: TGLuint, x: TGLdouble, y: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib2d".}
+proc glVertexAttrib2dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib2dv".}
+proc glVertexAttrib2f*(index: TGLuint, x: TGLfloat, y: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib2f".}
+proc glVertexAttrib2fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib2fv".}
+proc glVertexAttrib2s*(index: TGLuint, x: TGLshort, y: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib2s".}
+proc glVertexAttrib2sv*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib2sv".}
+proc glVertexAttrib3d*(index: TGLuint, x: TGLdouble, y: TGLdouble, z: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib3d".}
+proc glVertexAttrib3dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib3dv".}
+proc glVertexAttrib3f*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib3f".}
+proc glVertexAttrib3fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib3fv".}
+proc glVertexAttrib3s*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib3s".}
+proc glVertexAttrib3sv*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib3sv".}
+proc glVertexAttrib4Nbv*(index: TGLuint, v: PGLbyte){.dynlib: dllname,
+    importc: "glVertexAttrib4Nbv".}
+proc glVertexAttrib4Niv*(index: TGLuint, v: PGLint){.dynlib: dllname,
+    importc: "glVertexAttrib4Niv".}
+proc glVertexAttrib4Nsv*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib4Nsv".}
+proc glVertexAttrib4Nub*(index: TGLuint, x: TGLubyte, y: TGLubyte, z: TGLubyte,
+                         w: TGLubyte){.dynlib: dllname,
+                                       importc: "glVertexAttrib4Nub".}
+proc glVertexAttrib4Nubv*(index: TGLuint, v: PGLubyte){.dynlib: dllname,
+    importc: "glVertexAttrib4Nubv".}
+proc glVertexAttrib4Nuiv*(index: TGLuint, v: PGLuint){.dynlib: dllname,
+    importc: "glVertexAttrib4Nuiv".}
+proc glVertexAttrib4Nusv*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib4Nusv".}
+proc glVertexAttrib4bv*(index: TGLuint, v: PGLbyte){.dynlib: dllname,
+    importc: "glVertexAttrib4bv".}
+proc glVertexAttrib4d*(index: TGLuint, x: TGLdouble, y: TGLdouble, z: TGLdouble,
+                       w: TGLdouble){.dynlib: dllname,
+                                      importc: "glVertexAttrib4d".}
+proc glVertexAttrib4dv*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib4dv".}
+proc glVertexAttrib4f*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat,
+                       w: TGLfloat){.dynlib: dllname,
+                                     importc: "glVertexAttrib4f".}
+proc glVertexAttrib4fv*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib4fv".}
+proc glVertexAttrib4iv*(index: TGLuint, v: PGLint){.dynlib: dllname,
+    importc: "glVertexAttrib4iv".}
+proc glVertexAttrib4s*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort,
+                       w: TGLshort){.dynlib: dllname,
+                                     importc: "glVertexAttrib4s".}
+proc glVertexAttrib4sv*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib4sv".}
+proc glVertexAttrib4ubv*(index: TGLuint, v: PGLubyte){.dynlib: dllname,
+    importc: "glVertexAttrib4ubv".}
+proc glVertexAttrib4uiv*(index: TGLuint, v: PGLuint){.dynlib: dllname,
+    importc: "glVertexAttrib4uiv".}
+proc glVertexAttrib4usv*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib4usv".}
+proc glVertexAttribPointer*(index: TGLuint, size: TGLint, thetype: TGLenum,
+                            normalized: TGLboolean, stride: TGLsizei,
+                            pointer: PGLvoid){.dynlib: dllname,
+    importc: "glVertexAttribPointer".}
+const
+  GL_CONSTANT_COLOR* = 0x00008001
+  GL_ONE_MINUS_CONSTANT_COLOR* = 0x00008002
+  GL_CONSTANT_ALPHA* = 0x00008003
+  GL_ONE_MINUS_CONSTANT_ALPHA* = 0x00008004
+  constGL_BLEND_COLOR* = 0x00008005
+  GL_FUNC_ADD* = 0x00008006
+  GL_MIN* = 0x00008007
+  GL_MAX* = 0x00008008
+  constGL_BLEND_EQUATION* = 0x00008009
+  GL_FUNC_SUBTRACT* = 0x0000800A
+  GL_FUNC_REVERSE_SUBTRACT* = 0x0000800B
+  GL_CONVOLUTION_1D* = 0x00008010
+  GL_CONVOLUTION_2D* = 0x00008011
+  GL_SEPARABLE_2D* = 0x00008012
+  GL_CONVOLUTION_BORDER_MODE* = 0x00008013
+  GL_CONVOLUTION_FILTER_SCALE* = 0x00008014
+  GL_CONVOLUTION_FILTER_BIAS* = 0x00008015
+  GL_REDUCE* = 0x00008016
+  GL_CONVOLUTION_FORMAT* = 0x00008017
+  GL_CONVOLUTION_WIDTH* = 0x00008018
+  GL_CONVOLUTION_HEIGHT* = 0x00008019
+  GL_MAX_CONVOLUTION_WIDTH* = 0x0000801A
+  GL_MAX_CONVOLUTION_HEIGHT* = 0x0000801B
+  GL_POST_CONVOLUTION_RED_SCALE* = 0x0000801C
+  GL_POST_CONVOLUTION_GREEN_SCALE* = 0x0000801D
+  GL_POST_CONVOLUTION_BLUE_SCALE* = 0x0000801E
+  GL_POST_CONVOLUTION_ALPHA_SCALE* = 0x0000801F
+  GL_POST_CONVOLUTION_RED_BIAS* = 0x00008020
+  GL_POST_CONVOLUTION_GREEN_BIAS* = 0x00008021
+  GL_POST_CONVOLUTION_BLUE_BIAS* = 0x00008022
+  GL_POST_CONVOLUTION_ALPHA_BIAS* = 0x00008023
+  constGL_HISTOGRAM* = 0x00008024
+  GL_PROXY_HISTOGRAM* = 0x00008025
+  GL_HISTOGRAM_WIDTH* = 0x00008026
+  GL_HISTOGRAM_FORMAT* = 0x00008027
+  GL_HISTOGRAM_RED_SIZE* = 0x00008028
+  GL_HISTOGRAM_GREEN_SIZE* = 0x00008029
+  GL_HISTOGRAM_BLUE_SIZE* = 0x0000802A
+  GL_HISTOGRAM_ALPHA_SIZE* = 0x0000802B
+  GL_HISTOGRAM_LUMINANCE_SIZE* = 0x0000802C
+  GL_HISTOGRAM_SINK* = 0x0000802D
+  constGL_MINMAX* = 0x0000802E
+  GL_MINMAX_FORMAT* = 0x0000802F
+  GL_MINMAX_SINK* = 0x00008030
+  GL_TABLE_TOO_LARGE* = 0x00008031
+  GL_COLOR_MATRIX* = 0x000080B1
+  GL_COLOR_MATRIX_STACK_DEPTH* = 0x000080B2
+  GL_MAX_COLOR_MATRIX_STACK_DEPTH* = 0x000080B3
+  GL_POST_COLOR_MATRIX_RED_SCALE* = 0x000080B4
+  GL_POST_COLOR_MATRIX_GREEN_SCALE* = 0x000080B5
+  GL_POST_COLOR_MATRIX_BLUE_SCALE* = 0x000080B6
+  GL_POST_COLOR_MATRIX_ALPHA_SCALE* = 0x000080B7
+  GL_POST_COLOR_MATRIX_RED_BIAS* = 0x000080B8
+  GL_POST_COLOR_MATRIX_GREEN_BIAS* = 0x000080B9
+  GL_POST_COLOR_MATRIX_BLUE_BIAS* = 0x000080BA
+  GL_POST_COLOR_MATIX_ALPHA_BIAS* = 0x000080BB
+  constGL_COLOR_TABLE* = 0x000080D0
+  GL_POST_CONVOLUTION_COLOR_TABLE* = 0x000080D1
+  GL_POST_COLOR_MATRIX_COLOR_TABLE* = 0x000080D2
+  GL_PROXY_COLOR_TABLE* = 0x000080D3
+  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE* = 0x000080D4
+  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE* = 0x000080D5
+  GL_COLOR_TABLE_SCALE* = 0x000080D6
+  GL_COLOR_TABLE_BIAS* = 0x000080D7
+  GL_COLOR_TABLE_FORMAT* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE* = 0x000080DF
+  GL_IGNORE_BORDER* = 0x00008150
+  GL_CONSTANT_BORDER* = 0x00008151
+  GL_WRAP_BORDER* = 0x00008152
+  GL_REPLICATE_BORDER* = 0x00008153
+  GL_CONVOLUTION_BORDER_COLOR* = 0x00008154
+
+proc glActiveTexture*(texture: TGLenum){.dynlib: dllname,
+    importc: "glActiveTexture".}
+proc glClientActiveTexture*(texture: TGLenum){.dynlib: dllname,
+    importc: "glClientActiveTexture".}
+proc glMultiTexCoord1d*(target: TGLenum, s: TGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord1d".}
+proc glMultiTexCoord1dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord1dv".}
+proc glMultiTexCoord1f*(target: TGLenum, s: TGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord1f".}
+proc glMultiTexCoord1fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord1fv".}
+proc glMultiTexCoord1i*(target: TGLenum, s: TGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord1i".}
+proc glMultiTexCoord1iv*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord1iv".}
+proc glMultiTexCoord1s*(target: TGLenum, s: TGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord1s".}
+proc glMultiTexCoord1sv*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord1sv".}
+proc glMultiTexCoord2d*(target: TGLenum, s: TGLdouble, t: TGLdouble){.
+    dynlib: dllname, importc: "glMultiTexCoord2d".}
+proc glMultiTexCoord2dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord2dv".}
+proc glMultiTexCoord2f*(target: TGLenum, s: TGLfloat, t: TGLfloat){.
+    dynlib: dllname, importc: "glMultiTexCoord2f".}
+proc glMultiTexCoord2fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord2fv".}
+proc glMultiTexCoord2i*(target: TGLenum, s: TGLint, t: TGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord2i".}
+proc glMultiTexCoord2iv*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord2iv".}
+proc glMultiTexCoord2s*(target: TGLenum, s: TGLshort, t: TGLshort){.
+    dynlib: dllname, importc: "glMultiTexCoord2s".}
+proc glMultiTexCoord2sv*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord2sv".}
+proc glMultiTexCoord3d*(target: TGLenum, s: TGLdouble, t: TGLdouble,
+                        r: TGLdouble){.dynlib: dllname,
+                                       importc: "glMultiTexCoord3d".}
+proc glMultiTexCoord3dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord3dv".}
+proc glMultiTexCoord3f*(target: TGLenum, s: TGLfloat, t: TGLfloat, r: TGLfloat){.
+    dynlib: dllname, importc: "glMultiTexCoord3f".}
+proc glMultiTexCoord3fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord3fv".}
+proc glMultiTexCoord3i*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint){.
+    dynlib: dllname, importc: "glMultiTexCoord3i".}
+proc glMultiTexCoord3iv*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord3iv".}
+proc glMultiTexCoord3s*(target: TGLenum, s: TGLshort, t: TGLshort, r: TGLshort){.
+    dynlib: dllname, importc: "glMultiTexCoord3s".}
+proc glMultiTexCoord3sv*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord3sv".}
+proc glMultiTexCoord4d*(target: TGLenum, s: TGLdouble, t: TGLdouble,
+                        r: TGLdouble, q: TGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord4d".}
+proc glMultiTexCoord4dv*(target: TGLenum, v: PGLdouble){.dynlib: dllname,
+    importc: "glMultiTexCoord4dv".}
+proc glMultiTexCoord4f*(target: TGLenum, s: TGLfloat, t: TGLfloat, r: TGLfloat,
+                        q: TGLfloat){.dynlib: dllname,
+                                      importc: "glMultiTexCoord4f".}
+proc glMultiTexCoord4fv*(target: TGLenum, v: PGLfloat){.dynlib: dllname,
+    importc: "glMultiTexCoord4fv".}
+proc glMultiTexCoord4i*(target: TGLenum, s: TGLint, t: TGLint, r: TGLint,
+                        q: TGLint){.dynlib: dllname,
+                                    importc: "glMultiTexCoord4i".}
+proc glMultiTexCoord4iv*(target: TGLenum, v: PGLint){.dynlib: dllname,
+    importc: "glMultiTexCoord4iv".}
+proc glMultiTexCoord4s*(target: TGLenum, s: TGLshort, t: TGLshort, r: TGLshort,
+                        q: TGLshort){.dynlib: dllname,
+                                      importc: "glMultiTexCoord4s".}
+proc glMultiTexCoord4sv*(target: TGLenum, v: PGLshort){.dynlib: dllname,
+    importc: "glMultiTexCoord4sv".}
+proc glLoadTransposeMatrixf*(m: PGLfloat){.dynlib: dllname,
+    importc: "glLoadTransposeMatrixf".}
+proc glLoadTransposeMatrixd*(m: PGLdouble){.dynlib: dllname,
+    importc: "glLoadTransposeMatrixd".}
+proc glMultTransposeMatrixf*(m: PGLfloat){.dynlib: dllname,
+    importc: "glMultTransposeMatrixf".}
+proc glMultTransposeMatrixd*(m: PGLdouble){.dynlib: dllname,
+    importc: "glMultTransposeMatrixd".}
+proc glSampleCoverage*(value: TGLclampf, invert: TGLboolean){.dynlib: dllname,
+    importc: "glSampleCoverage".}
+proc glCompressedTexImage3D*(target: TGLenum, level: TGLint,
+                             internalformat: TGLenum, width: TGLsizei,
+                             height: TGLsizei, depth: TGLsizei, border: TGLint,
+                             imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage3D".}
+proc glCompressedTexImage2D*(target: TGLenum, level: TGLint,
+                             internalformat: TGLenum, width: TGLsizei,
+                             height: TGLsizei, border: TGLint,
+                             imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage2D".}
+proc glCompressedTexImage1D*(target: TGLenum, level: TGLint,
+                             internalformat: TGLenum, width: TGLsizei,
+                             border: TGLint, imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage1D".}
+proc glCompressedTexSubImage3D*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                                yoffset: TGLint, zoffset: TGLint,
+                                width: TGLsizei, height: TGLsizei,
+                                depth: TGLsizei, format: TGLenum,
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexSubImage3D".}
+proc glCompressedTexSubImage2D*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                                yoffset: TGLint, width: TGLsizei,
+                                height: TGLsizei, format: TGLenum,
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexSubImage2D".}
+proc glCompressedTexSubImage1D*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                                width: TGLsizei, format: TGLenum,
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexSubImage1D".}
+proc glGetCompressedTexImage*(target: TGLenum, level: TGLint, img: PGLvoid){.
+    dynlib: dllname, importc: "glGetCompressedTexImage".}
+  #***** GL_version_1_3 *****//
+const
+  GL_TEXTURE0* = 0x000084C0
+  GL_TEXTURE1* = 0x000084C1
+  GL_TEXTURE2* = 0x000084C2
+  GL_TEXTURE3* = 0x000084C3
+  GL_TEXTURE4* = 0x000084C4
+  GL_TEXTURE5* = 0x000084C5
+  GL_TEXTURE6* = 0x000084C6
+  GL_TEXTURE7* = 0x000084C7
+  GL_TEXTURE8* = 0x000084C8
+  GL_TEXTURE9* = 0x000084C9
+  GL_TEXTURE10* = 0x000084CA
+  GL_TEXTURE11* = 0x000084CB
+  GL_TEXTURE12* = 0x000084CC
+  GL_TEXTURE13* = 0x000084CD
+  GL_TEXTURE14* = 0x000084CE
+  GL_TEXTURE15* = 0x000084CF
+  GL_TEXTURE16* = 0x000084D0
+  GL_TEXTURE17* = 0x000084D1
+  GL_TEXTURE18* = 0x000084D2
+  GL_TEXTURE19* = 0x000084D3
+  GL_TEXTURE20* = 0x000084D4
+  GL_TEXTURE21* = 0x000084D5
+  GL_TEXTURE22* = 0x000084D6
+  GL_TEXTURE23* = 0x000084D7
+  GL_TEXTURE24* = 0x000084D8
+  GL_TEXTURE25* = 0x000084D9
+  GL_TEXTURE26* = 0x000084DA
+  GL_TEXTURE27* = 0x000084DB
+  GL_TEXTURE28* = 0x000084DC
+  GL_TEXTURE29* = 0x000084DD
+  GL_TEXTURE30* = 0x000084DE
+  GL_TEXTURE31* = 0x000084DF
+  constGL_ACTIVE_TEXTURE* = 0x000084E0
+  constGL_CLIENT_ACTIVE_TEXTURE* = 0x000084E1
+  GL_MAX_TEXTURE_UNITS* = 0x000084E2
+  GL_TRANSPOSE_MODELVIEW_MATRIX* = 0x000084E3
+  GL_TRANSPOSE_PROJECTION_MATRIX* = 0x000084E4
+  GL_TRANSPOSE_TEXTURE_MATRIX* = 0x000084E5
+  GL_TRANSPOSE_COLOR_MATRIX* = 0x000084E6
+  GL_MULTISAMPLE* = 0x0000809D
+  GL_SAMPLE_ALPHA_TO_COVERAGE* = 0x0000809E
+  GL_SAMPLE_ALPHA_TO_ONE* = 0x0000809F
+  constGL_SAMPLE_COVERAGE* = 0x000080A0
+  GL_SAMPLE_BUFFERS* = 0x000080A8
+  GL_SAMPLES* = 0x000080A9
+  GL_SAMPLE_COVERAGE_VALUE* = 0x000080AA
+  GL_SAMPLE_COVERAGE_INVERT* = 0x000080AB
+  GL_MULTISAMPLE_BIT* = 0x20000000
+  GL_NORMAL_MAP* = 0x00008511
+  GL_REFLECTION_MAP* = 0x00008512
+  GL_TEXTURE_CUBE_MAP* = 0x00008513
+  GL_TEXTURE_BINDING_CUBE_MAP* = 0x00008514
+  GL_TEXTURE_CUBE_MAP_POSITIVE_X* = 0x00008515
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_X* = 0x00008516
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Y* = 0x00008517
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y* = 0x00008518
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Z* = 0x00008519
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z* = 0x0000851A
+  GL_PROXY_TEXTURE_CUBE_MAP* = 0x0000851B
+  GL_MAX_CUBE_MAP_TEXTURE_SIZE* = 0x0000851C
+  GL_COMPRESSED_ALPHA* = 0x000084E9
+  GL_COMPRESSED_LUMINANCE* = 0x000084EA
+  GL_COMPRESSED_LUMINANCE_ALPHA* = 0x000084EB
+  GL_COMPRESSED_INTENSITY* = 0x000084EC
+  GL_COMPRESSED_RGB* = 0x000084ED
+  GL_COMPRESSED_RGBA* = 0x000084EE
+  GL_TEXTURE_COMPRESSION_HINT* = 0x000084EF
+  GL_TEXTURE_COMPRESSED_IMAGE_SIZE* = 0x000086A0
+  GL_TEXTURE_COMPRESSED* = 0x000086A1
+  GL_NUM_COMPRESSED_TEXTURE_FORMATS* = 0x000086A2
+  GL_COMPRESSED_TEXTURE_FORMATS* = 0x000086A3
+  GL_CLAMP_TO_BORDER* = 0x0000812D
+  GL_CLAMP_TO_BORDER_SGIS* = 0x0000812D
+  GL_COMBINE* = 0x00008570
+  GL_COMBINE_RGB* = 0x00008571
+  GL_COMBINE_ALPHA* = 0x00008572
+  GL_SOURCE0_RGB* = 0x00008580
+  GL_SOURCE1_RGB* = 0x00008581
+  GL_SOURCE2_RGB* = 0x00008582
+  GL_SOURCE0_ALPHA* = 0x00008588
+  GL_SOURCE1_ALPHA* = 0x00008589
+  GL_SOURCE2_ALPHA* = 0x0000858A
+  GL_OPERAND0_RGB* = 0x00008590
+  GL_OPERAND1_RGB* = 0x00008591
+  GL_OPERAND2_RGB* = 0x00008592
+  GL_OPERAND0_ALPHA* = 0x00008598
+  GL_OPERAND1_ALPHA* = 0x00008599
+  GL_OPERAND2_ALPHA* = 0x0000859A
+  GL_RGB_SCALE* = 0x00008573
+  GL_ADD_SIGNED* = 0x00008574
+  GL_INTERPOLATE* = 0x00008575
+  GL_SUBTRACT* = 0x000084E7
+  GL_CONSTANT* = 0x00008576
+  GL_PRIMARY_COLOR* = 0x00008577
+  GL_PREVIOUS* = 0x00008578
+  GL_DOT3_RGB* = 0x000086AE
+  GL_DOT3_RGBA* = 0x000086AF
+
+const
+  GL_TEXTURE0_ARB* = 0x000084C0
+  GL_TEXTURE1_ARB* = 0x000084C1
+  GL_TEXTURE2_ARB* = 0x000084C2
+  GL_TEXTURE3_ARB* = 0x000084C3
+  GL_TEXTURE4_ARB* = 0x000084C4
+  GL_TEXTURE5_ARB* = 0x000084C5
+  GL_TEXTURE6_ARB* = 0x000084C6
+  GL_TEXTURE7_ARB* = 0x000084C7
+  GL_TEXTURE8_ARB* = 0x000084C8
+  GL_TEXTURE9_ARB* = 0x000084C9
+  GL_TEXTURE10_ARB* = 0x000084CA
+  GL_TEXTURE11_ARB* = 0x000084CB
+  GL_TEXTURE12_ARB* = 0x000084CC
+  GL_TEXTURE13_ARB* = 0x000084CD
+  GL_TEXTURE14_ARB* = 0x000084CE
+  GL_TEXTURE15_ARB* = 0x000084CF
+  GL_TEXTURE16_ARB* = 0x000084D0
+  GL_TEXTURE17_ARB* = 0x000084D1
+  GL_TEXTURE18_ARB* = 0x000084D2
+  GL_TEXTURE19_ARB* = 0x000084D3
+  GL_TEXTURE20_ARB* = 0x000084D4
+  GL_TEXTURE21_ARB* = 0x000084D5
+  GL_TEXTURE22_ARB* = 0x000084D6
+  GL_TEXTURE23_ARB* = 0x000084D7
+  GL_TEXTURE24_ARB* = 0x000084D8
+  GL_TEXTURE25_ARB* = 0x000084D9
+  GL_TEXTURE26_ARB* = 0x000084DA
+  GL_TEXTURE27_ARB* = 0x000084DB
+  GL_TEXTURE28_ARB* = 0x000084DC
+  GL_TEXTURE29_ARB* = 0x000084DD
+  GL_TEXTURE30_ARB* = 0x000084DE
+  GL_TEXTURE31_ARB* = 0x000084DF
+  constGL_ACTIVE_TEXTURE_ARB* = 0x000084E0
+  constGL_CLIENT_ACTIVE_TEXTURE_ARB* = 0x000084E1
+  GL_MAX_TEXTURE_UNITS_ARB* = 0x000084E2
+  #***** GL_ARB_transpose_matrix *****//
+
+const
+  GL_TRANSPOSE_MODELVIEW_MATRIX_ARB* = 0x000084E3
+  GL_TRANSPOSE_PROJECTION_MATRIX_ARB* = 0x000084E4
+  GL_TRANSPOSE_TEXTURE_MATRIX_ARB* = 0x000084E5
+  GL_TRANSPOSE_COLOR_MATRIX_ARB* = 0x000084E6
+
+proc glLoadTransposeMatrixfARB*(m: PGLfloat){.dynlib: dllname,
+    importc: "glLoadTransposeMatrixfARB".}
+proc glLoadTransposeMatrixdARB*(m: PGLdouble){.dynlib: dllname,
+    importc: "glLoadTransposeMatrixdARB".}
+proc glMultTransposeMatrixfARB*(m: PGLfloat){.dynlib: dllname,
+    importc: "glMultTransposeMatrixfARB".}
+proc glMultTransposeMatrixdARB*(m: PGLdouble){.dynlib: dllname,
+    importc: "glMultTransposeMatrixdARB".}
+const
+  WGL_SAMPLE_BUFFERS_ARB* = 0x00002041
+  WGL_SAMPLES_ARB* = 0x00002042
+  GL_MULTISAMPLE_ARB* = 0x0000809D
+  GL_SAMPLE_ALPHA_TO_COVERAGE_ARB* = 0x0000809E
+  GL_SAMPLE_ALPHA_TO_ONE_ARB* = 0x0000809F
+  constGL_SAMPLE_COVERAGE_ARB* = 0x000080A0
+  GL_MULTISAMPLE_BIT_ARB* = 0x20000000
+  GL_SAMPLE_BUFFERS_ARB* = 0x000080A8
+  GL_SAMPLES_ARB* = 0x000080A9
+  GL_SAMPLE_COVERAGE_VALUE_ARB* = 0x000080AA
+  GL_SAMPLE_COVERAGE_INVERT_ARB* = 0x000080AB
+
+const
+  GL_NORMAL_MAP_ARB* = 0x00008511
+  GL_REFLECTION_MAP_ARB* = 0x00008512
+  GL_TEXTURE_CUBE_MAP_ARB* = 0x00008513
+  GL_TEXTURE_BINDING_CUBE_MAP_ARB* = 0x00008514
+  GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB* = 0x00008515
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB* = 0x00008516
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB* = 0x00008517
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB* = 0x00008518
+  GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB* = 0x00008519
+  GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB* = 0x0000851A
+  GL_PROXY_TEXTURE_CUBE_MAP_ARB* = 0x0000851B
+  GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB* = 0x0000851C
+
+const
+  GL_DEPTH_COMPONENT16_ARB* = 0x000081A5
+  GL_DEPTH_COMPONENT24_ARB* = 0x000081A6
+  GL_DEPTH_COMPONENT32_ARB* = 0x000081A7
+  GL_TEXTURE_DEPTH_SIZE_ARB* = 0x0000884A
+  GL_DEPTH_TEXTURE_MODE_ARB* = 0x0000884B
+  #***** GL_ARB_point_parameters *****//
+
+const
+  GL_POINT_SIZE_MIN_ARB* = 0x00008126
+  GL_POINT_SIZE_MAX_ARB* = 0x00008127
+  GL_POINT_FADE_THRESHOLD_SIZE_ARB* = 0x00008128
+  GL_POINT_DISTANCE_ATTENUATION_ARB* = 0x00008129
+
+proc glPointParameterfARB*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glPointParameterfARB".}
+proc glPointParameterfvARB*(pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glPointParameterfvARB".}
+const
+  GL_TEXTURE_COMPARE_MODE_ARB* = 0x0000884C
+  GL_TEXTURE_COMPARE_FUNC_ARB* = 0x0000884D
+  GL_COMPARE_R_TO_TEXTURE_ARB* = 0x0000884E
+
+const
+  GL_TEXTURE_COMPARE_FAIL_VALUE_ARB* = 0x000080BF
+  GL_CLAMP_TO_BORDER_ARB* = 0x0000812D
+
+const
+  GL_COMPRESSED_ALPHA_ARB* = 0x000084E9
+  GL_COMPRESSED_LUMINANCE_ARB* = 0x000084EA
+  GL_COMPRESSED_LUMINANCE_ALPHA_ARB* = 0x000084EB
+  GL_COMPRESSED_INTENSITY_ARB* = 0x000084EC
+  GL_COMPRESSED_RGB_ARB* = 0x000084ED
+  GL_COMPRESSED_RGBA_ARB* = 0x000084EE
+  GL_TEXTURE_COMPRESSION_HINT_ARB* = 0x000084EF
+  GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB* = 0x000086A0
+  GL_TEXTURE_COMPRESSED_ARB* = 0x000086A1
+  GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB* = 0x000086A2
+  GL_COMPRESSED_TEXTURE_FORMATS_ARB* = 0x000086A3
+
+proc glCompressedTexImage3DARB*(target: TGLenum, level: TGLint,
+                                internalformat: TGLenum, width: TGLsizei,
+                                height: TGLsizei, depth: TGLsizei,
+                                border: TGLint, imageSize: TGLsizei,
+                                data: PGLvoid){.dynlib: dllname,
+    importc: "glCompressedTexImage3DARB".}
+proc glCompressedTexImage2DARB*(target: TGLenum, level: TGLint,
+                                internalformat: TGLenum, width: TGLsizei,
+                                height: TGLsizei, border: TGLint,
+                                imageSize: TGLsizei, data: PGLvoid){.
+    dynlib: dllname, importc: "glCompressedTexImage2DARB".}
+proc glCompressedTexImage1DARB*(target: TGLenum, level: TGLint,
+                                internalformat: TGLenum, width: TGLsizei,
+                                border: TGLint, imageSize: TGLsizei,
+                                data: PGLvoid){.dynlib: dllname,
+    importc: "glCompressedTexImage1DARB".}
+proc glCompressedTexSubImage3DARB*(target: TGLenum, level: TGLint,
+                                   xoffset: TGLint, yoffset: TGLint,
+                                   zoffset: TGLint, width: TGLsizei,
+                                   height: TGLsizei, depth: TGLsizei,
+                                   format: TGLenum, imageSize: TGLsizei,
+                                   data: PGLvoid){.dynlib: dllname,
+    importc: "glCompressedTexSubImage3DARB".}
+proc glCompressedTexSubImage2DARB*(target: TGLenum, level: TGLint,
+                                   xoffset: TGLint, yoffset: TGLint,
+                                   width: TGLsizei, height: TGLsizei,
+                                   format: TGLenum, imageSize: TGLsizei,
+                                   data: PGLvoid){.dynlib: dllname,
+    importc: "glCompressedTexSubImage2DARB".}
+proc glCompressedTexSubImage1DARB*(target: TGLenum, level: TGLint,
+                                   xoffset: TGLint, width: TGLsizei,
+                                   format: TGLenum, imageSize: TGLsizei,
+                                   data: PGLvoid){.dynlib: dllname,
+    importc: "glCompressedTexSubImage1DARB".}
+proc glGetCompressedTexImageARB*(target: TGLenum, lod: TGLint, img: PGLvoid){.
+    dynlib: dllname, importc: "glGetCompressedTexImageARB".}
+  #***** GL_ARB_texture_env_combine *****//
+const
+  GL_COMBINE_ARB* = 0x00008570
+  GL_COMBINE_RGB_ARB* = 0x00008571
+  GL_COMBINE_ALPHA_ARB* = 0x00008572
+  GL_SOURCE0_RGB_ARB* = 0x00008580
+  GL_SOURCE1_RGB_ARB* = 0x00008581
+  GL_SOURCE2_RGB_ARB* = 0x00008582
+  GL_SOURCE0_ALPHA_ARB* = 0x00008588
+  GL_SOURCE1_ALPHA_ARB* = 0x00008589
+  GL_SOURCE2_ALPHA_ARB* = 0x0000858A
+  GL_OPERAND0_RGB_ARB* = 0x00008590
+  GL_OPERAND1_RGB_ARB* = 0x00008591
+  GL_OPERAND2_RGB_ARB* = 0x00008592
+  GL_OPERAND0_ALPHA_ARB* = 0x00008598
+  GL_OPERAND1_ALPHA_ARB* = 0x00008599
+  GL_OPERAND2_ALPHA_ARB* = 0x0000859A
+  GL_RGB_SCALE_ARB* = 0x00008573
+  GL_ADD_SIGNED_ARB* = 0x00008574
+  GL_INTERPOLATE_ARB* = 0x00008575
+  GL_SUBTRACT_ARB* = 0x000084E7
+  GL_CONSTANT_ARB* = 0x00008576
+  GL_PRIMARY_COLOR_ARB* = 0x00008577
+  GL_PREVIOUS_ARB* = 0x00008578
+  #***** GL_ARB_texture_env_crossbar *****//
+  #***** GL_ARB_texture_env_dot3 *****//
+
+const
+  GL_DOT3_RGB_ARB* = 0x000086AE
+  GL_DOT3_RGBA_ARB* = 0x000086AF
+  #***** GL_ARB_texture_mirrored_repeat *****//
+
+const
+  GL_MIRRORED_REPEAT_ARB* = 0x00008370
+  #***** GL_ARB_vertex_blend *****//
+
+const
+  GL_MAX_VERTEX_UNITS_ARB* = 0x000086A4
+  GL_ACTIVE_VERTEX_UNITS_ARB* = 0x000086A5
+  GL_WEIGHT_SUM_UNITY_ARB* = 0x000086A6
+  constGL_VERTEX_BLEND_ARB* = 0x000086A7
+  GL_MODELVIEW0_ARB* = 0x00001700
+  GL_MODELVIEW1_ARB* = 0x0000850A
+  GL_MODELVIEW2_ARB* = 0x00008722
+  GL_MODELVIEW3_ARB* = 0x00008723
+  GL_MODELVIEW4_ARB* = 0x00008724
+  GL_MODELVIEW5_ARB* = 0x00008725
+  GL_MODELVIEW6_ARB* = 0x00008726
+  GL_MODELVIEW7_ARB* = 0x00008727
+  GL_MODELVIEW8_ARB* = 0x00008728
+  GL_MODELVIEW9_ARB* = 0x00008729
+  GL_MODELVIEW10_ARB* = 0x0000872A
+  GL_MODELVIEW11_ARB* = 0x0000872B
+  GL_MODELVIEW12_ARB* = 0x0000872C
+  GL_MODELVIEW13_ARB* = 0x0000872D
+  GL_MODELVIEW14_ARB* = 0x0000872E
+  GL_MODELVIEW15_ARB* = 0x0000872F
+  GL_MODELVIEW16_ARB* = 0x00008730
+  GL_MODELVIEW17_ARB* = 0x00008731
+  GL_MODELVIEW18_ARB* = 0x00008732
+  GL_MODELVIEW19_ARB* = 0x00008733
+  GL_MODELVIEW20_ARB* = 0x00008734
+  GL_MODELVIEW21_ARB* = 0x00008735
+  GL_MODELVIEW22_ARB* = 0x00008736
+  GL_MODELVIEW23_ARB* = 0x00008737
+  GL_MODELVIEW24_ARB* = 0x00008738
+  GL_MODELVIEW25_ARB* = 0x00008739
+  GL_MODELVIEW26_ARB* = 0x0000873A
+  GL_MODELVIEW27_ARB* = 0x0000873B
+  GL_MODELVIEW28_ARB* = 0x0000873C
+  GL_MODELVIEW29_ARB* = 0x0000873D
+  GL_MODELVIEW30_ARB* = 0x0000873E
+  GL_MODELVIEW31_ARB* = 0x0000873F
+  GL_CURRENT_WEIGHT_ARB* = 0x000086A8
+  GL_WEIGHT_ARRAY_TYPE_ARB* = 0x000086A9
+  GL_WEIGHT_ARRAY_STRIDE_ARB* = 0x000086AA
+  GL_WEIGHT_ARRAY_SIZE_ARB* = 0x000086AB
+  GL_WEIGHT_ARRAY_POINTER_ARB* = 0x000086AC
+  GL_WEIGHT_ARRAY_ARB* = 0x000086AD
+
+const
+  GL_VERTEX_PROGRAM_ARB* = 0x00008620
+  GL_VERTEX_PROGRAM_POINT_SIZE_ARB* = 0x00008642
+  GL_VERTEX_PROGRAM_TWO_SIDE_ARB* = 0x00008643
+  GL_COLOR_SUM_ARB* = 0x00008458
+  GL_PROGRAM_FORMAT_ASCII_ARB* = 0x00008875
+  GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB* = 0x00008622
+  GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB* = 0x00008623
+  GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB* = 0x00008624
+  GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB* = 0x00008625
+  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB* = 0x0000886A
+  GL_CURRENT_VERTEX_ATTRIB_ARB* = 0x00008626
+  GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB* = 0x00008645
+  GL_PROGRAM_LENGTH_ARB* = 0x00008627
+  GL_PROGRAM_FORMAT_ARB* = 0x00008876
+  GL_PROGRAM_BINDING_ARB* = 0x00008677
+  GL_PROGRAM_INSTRUCTIONS_ARB* = 0x000088A0
+  GL_MAX_PROGRAM_INSTRUCTIONS_ARB* = 0x000088A1
+  GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB* = 0x000088A2
+  GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB* = 0x000088A3
+  GL_PROGRAM_TEMPORARIES_ARB* = 0x000088A4
+  GL_MAX_PROGRAM_TEMPORARIES_ARB* = 0x000088A5
+  GL_PROGRAM_NATIVE_TEMPORARIES_ARB* = 0x000088A6
+  GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB* = 0x000088A7
+  GL_PROGRAM_PARAMETERS_ARB* = 0x000088A8
+  GL_MAX_PROGRAM_PARAMETERS_ARB* = 0x000088A9
+  GL_PROGRAM_NATIVE_PARAMETERS_ARB* = 0x000088AA
+  GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB* = 0x000088AB
+  GL_PROGRAM_ATTRIBS_ARB* = 0x000088AC
+  GL_MAX_PROGRAM_ATTRIBS_ARB* = 0x000088AD
+  GL_PROGRAM_NATIVE_ATTRIBS_ARB* = 0x000088AE
+  GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB* = 0x000088AF
+  GL_PROGRAM_ADDRESS_REGISTERS_ARB* = 0x000088B0
+  GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB* = 0x000088B1
+  GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB* = 0x000088B2
+  GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB* = 0x000088B3
+  GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB* = 0x000088B4
+  GL_MAX_PROGRAM_ENV_PARAMETERS_ARB* = 0x000088B5
+  GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB* = 0x000088B6
+  constGL_PROGRAM_STRING_ARB* = 0x00008628
+  GL_PROGRAM_ERROR_POSITION_ARB* = 0x0000864B
+  GL_CURRENT_MATRIX_ARB* = 0x00008641
+  GL_TRANSPOSE_CURRENT_MATRIX_ARB* = 0x000088B7
+  GL_CURRENT_MATRIX_STACK_DEPTH_ARB* = 0x00008640
+  GL_MAX_VERTEX_ATTRIBS_ARB* = 0x00008869
+  GL_MAX_PROGRAM_MATRICES_ARB* = 0x0000862F
+  GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB* = 0x0000862E
+  GL_PROGRAM_ERROR_STRING_ARB* = 0x00008874
+  GL_MATRIX0_ARB* = 0x000088C0
+  GL_MATRIX1_ARB* = 0x000088C1
+  GL_MATRIX2_ARB* = 0x000088C2
+  GL_MATRIX3_ARB* = 0x000088C3
+  GL_MATRIX4_ARB* = 0x000088C4
+  GL_MATRIX5_ARB* = 0x000088C5
+  GL_MATRIX6_ARB* = 0x000088C6
+  GL_MATRIX7_ARB* = 0x000088C7
+  GL_MATRIX8_ARB* = 0x000088C8
+  GL_MATRIX9_ARB* = 0x000088C9
+  GL_MATRIX10_ARB* = 0x000088CA
+  GL_MATRIX11_ARB* = 0x000088CB
+  GL_MATRIX12_ARB* = 0x000088CC
+  GL_MATRIX13_ARB* = 0x000088CD
+  GL_MATRIX14_ARB* = 0x000088CE
+  GL_MATRIX15_ARB* = 0x000088CF
+  GL_MATRIX16_ARB* = 0x000088D0
+  GL_MATRIX17_ARB* = 0x000088D1
+  GL_MATRIX18_ARB* = 0x000088D2
+  GL_MATRIX19_ARB* = 0x000088D3
+  GL_MATRIX20_ARB* = 0x000088D4
+  GL_MATRIX21_ARB* = 0x000088D5
+  GL_MATRIX22_ARB* = 0x000088D6
+  GL_MATRIX23_ARB* = 0x000088D7
+  GL_MATRIX24_ARB* = 0x000088D8
+  GL_MATRIX25_ARB* = 0x000088D9
+  GL_MATRIX26_ARB* = 0x000088DA
+  GL_MATRIX27_ARB* = 0x000088DB
+  GL_MATRIX28_ARB* = 0x000088DC
+  GL_MATRIX29_ARB* = 0x000088DD
+  GL_MATRIX30_ARB* = 0x000088DE
+  GL_MATRIX31_ARB* = 0x000088DF
+
+const
+  GL_422_EXT* = 0x000080CC
+  GL_422_REV_EXT* = 0x000080CD
+  GL_422_AVERAGE_EXT* = 0x000080CE
+  GL_422_REV_AVERAGE_EXT* = 0x000080CF
+  #***** GL_EXT_abgr *****//
+
+const
+  GL_ABGR_EXT* = 0x00008000
+  #***** GL_EXT_bgra *****//
+
+const
+  GL_BGR_EXT* = 0x000080E0
+  GL_BGRA_EXT* = 0x000080E1
+  #***** GL_EXT_blend_color *****//
+
+const
+  GL_CONSTANT_COLOR_EXT* = 0x00008001
+  GL_ONE_MINUS_CONSTANT_COLOR_EXT* = 0x00008002
+  GL_CONSTANT_ALPHA_EXT* = 0x00008003
+  GL_ONE_MINUS_CONSTANT_ALPHA_EXT* = 0x00008004
+  constGL_BLEND_COLOR_EXT* = 0x00008005
+
+proc glBlendColorEXT*(red: TGLclampf, green: TGLclampf, blue: TGLclampf,
+                      alpha: TGLclampf){.dynlib: dllname,
+    importc: "glBlendColorEXT".}
+  #***** GL_EXT_blend_func_separate *****//
+const
+  GL_BLEND_DST_RGB_EXT* = 0x000080C8
+  GL_BLEND_SRC_RGB_EXT* = 0x000080C9
+  GL_BLEND_DST_ALPHA_EXT* = 0x000080CA
+  GL_BLEND_SRC_ALPHA_EXT* = 0x000080CB
+
+proc glBlendFuncSeparateEXT*(sfactorRGB: TGLenum, dfactorRGB: TGLenum,
+                             sfactorAlpha: TGLenum, dfactorAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendFuncSeparateEXT".}
+  #***** GL_EXT_blend_logic_op *****//
+  #***** GL_EXT_blend_minmax *****//
+const
+  GL_FUNC_ADD_EXT* = 0x00008006
+  GL_MIN_EXT* = 0x00008007
+  GL_MAX_EXT* = 0x00008008
+  constGL_BLEND_EQUATION_EXT* = 0x00008009
+
+proc glBlendEquationEXT*(mode: TGLenum){.dynlib: dllname,
+    importc: "glBlendEquationEXT".}
+  #***** GL_EXT_blend_subtract *****//
+const
+  GL_FUNC_SUBTRACT_EXT* = 0x0000800A
+  GL_FUNC_REVERSE_SUBTRACT_EXT* = 0x0000800B
+  #***** GL_EXT_clip_volume_hint *****//
+
+const
+  GL_CLIP_VOLUME_CLIPPING_HINT_EXT* = 0x000080F0
+  #***** GL_EXT_color_subtable *****//
+
+proc glColorSubTableEXT*(target: TGLenum, start: TGLsizei, count: TGLsizei,
+                         format: TGLenum, thetype: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glColorSubTableEXT".}
+proc glCopyColorSubTableEXT*(target: TGLenum, start: TGLsizei, x: TGLint,
+                             y: TGLint, width: TGLsizei){.dynlib: dllname,
+    importc: "glCopyColorSubTableEXT".}
+  #***** GL_EXT_compiled_vertex_array *****//
+const
+  GL_ARRAY_ELEMENT_LOCK_FIRST_EXT* = 0x000081A8
+  GL_ARRAY_ELEMENT_LOCK_COUNT_EXT* = 0x000081A9
+
+proc glLockArraysEXT*(first: TGLint, count: TGLsizei){.dynlib: dllname,
+    importc: "glLockArraysEXT".}
+proc glUnlockArraysEXT*(){.dynlib: dllname, importc: "glUnlockArraysEXT".}
+  #***** GL_EXT_convolution *****//
+const
+  GL_CONVOLUTION_1D_EXT* = 0x00008010
+  GL_CONVOLUTION_2D_EXT* = 0x00008011
+  GL_SEPARABLE_2D_EXT* = 0x00008012
+  GL_CONVOLUTION_BORDER_MODE_EXT* = 0x00008013
+  GL_CONVOLUTION_FILTER_SCALE_EXT* = 0x00008014
+  GL_CONVOLUTION_FILTER_BIAS_EXT* = 0x00008015
+  GL_REDUCE_EXT* = 0x00008016
+  GL_CONVOLUTION_FORMAT_EXT* = 0x00008017
+  GL_CONVOLUTION_WIDTH_EXT* = 0x00008018
+  GL_CONVOLUTION_HEIGHT_EXT* = 0x00008019
+  GL_MAX_CONVOLUTION_WIDTH_EXT* = 0x0000801A
+  GL_MAX_CONVOLUTION_HEIGHT_EXT* = 0x0000801B
+  GL_POST_CONVOLUTION_RED_SCALE_EXT* = 0x0000801C
+  GL_POST_CONVOLUTION_GREEN_SCALE_EXT* = 0x0000801D
+  GL_POST_CONVOLUTION_BLUE_SCALE_EXT* = 0x0000801E
+  GL_POST_CONVOLUTION_ALPHA_SCALE_EXT* = 0x0000801F
+  GL_POST_CONVOLUTION_RED_BIAS_EXT* = 0x00008020
+  GL_POST_CONVOLUTION_GREEN_BIAS_EXT* = 0x00008021
+  GL_POST_CONVOLUTION_BLUE_BIAS_EXT* = 0x00008022
+  GL_POST_CONVOLUTION_ALPHA_BIAS_EXT* = 0x00008023
+
+proc glConvolutionFilter1DEXT*(target: TGLenum, internalformat: TGLenum,
+                               width: TGLsizei, format: TGLenum,
+                               thetype: TGLenum, image: PGLvoid){.
+    dynlib: dllname, importc: "glConvolutionFilter1DEXT".}
+proc glConvolutionFilter2DEXT*(target: TGLenum, internalformat: TGLenum,
+                               width: TGLsizei, height: TGLsizei,
+                               format: TGLenum, thetype: TGLenum, image: PGLvoid){.
+    dynlib: dllname, importc: "glConvolutionFilter2DEXT".}
+proc glCopyConvolutionFilter1DEXT*(target: TGLenum, internalformat: TGLenum,
+                                   x: TGLint, y: TGLint, width: TGLsizei){.
+    dynlib: dllname, importc: "glCopyConvolutionFilter1DEXT".}
+proc glCopyConvolutionFilter2DEXT*(target: TGLenum, internalformat: TGLenum,
+                                   x: TGLint, y: TGLint, width: TGLsizei,
+                                   height: TGLsizei){.dynlib: dllname,
+    importc: "glCopyConvolutionFilter2DEXT".}
+proc glGetConvolutionFilterEXT*(target: TGLenum, format: TGLenum,
+                                thetype: TGLenum, image: PGLvoid){.
+    dynlib: dllname, importc: "glGetConvolutionFilterEXT".}
+proc glSeparableFilter2DEXT*(target: TGLenum, internalformat: TGLenum,
+                             width: TGLsizei, height: TGLsizei, format: TGLenum,
+                             thetype: TGLenum, row: PGLvoid, column: PGLvoid){.
+    dynlib: dllname, importc: "glSeparableFilter2DEXT".}
+proc glGetSeparableFilterEXT*(target: TGLenum, format: TGLenum,
+                              thetype: TGLenum, row: PGLvoid, column: PGLvoid,
+                              span: PGLvoid){.dynlib: dllname,
+    importc: "glGetSeparableFilterEXT".}
+proc glConvolutionParameteriEXT*(target: TGLenum, pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glConvolutionParameteriEXT".}
+proc glConvolutionParameterivEXT*(target: TGLenum, pname: TGLenum,
+                                  params: PGLint){.dynlib: dllname,
+    importc: "glConvolutionParameterivEXT".}
+proc glConvolutionParameterfEXT*(target: TGLenum, pname: TGLenum,
+                                 param: TGLfloat){.dynlib: dllname,
+    importc: "glConvolutionParameterfEXT".}
+proc glConvolutionParameterfvEXT*(target: TGLenum, pname: TGLenum,
+                                  params: PGLfloat){.dynlib: dllname,
+    importc: "glConvolutionParameterfvEXT".}
+proc glGetConvolutionParameterivEXT*(target: TGLenum, pname: TGLenum,
+                                     params: PGLint){.dynlib: dllname,
+    importc: "glGetConvolutionParameterivEXT".}
+proc glGetConvolutionParameterfvEXT*(target: TGLenum, pname: TGLenum,
+                                     params: PGLfloat){.dynlib: dllname,
+    importc: "glGetConvolutionParameterfvEXT".}
+  #***** GL_EXT_fog_coord *****//
+const
+  GL_FOG_COORDINATE_SOURCE_EXT* = 0x00008450
+  GL_FOG_COORDINATE_EXT* = 0x00008451
+  GL_FRAGMENT_DEPTH_EXT* = 0x00008452
+  GL_CURRENT_FOG_COORDINATE_EXT* = 0x00008453
+  GL_FOG_COORDINATE_ARRAY_TYPE_EXT* = 0x00008454
+  GL_FOG_COORDINATE_ARRAY_STRIDE_EXT* = 0x00008455
+  GL_FOG_COORDINATE_ARRAY_POINTER_EXT* = 0x00008456
+  GL_FOG_COORDINATE_ARRAY_EXT* = 0x00008457
+
+proc glFogCoordfEXfloat*(coord: TGLfloat){.dynlib: dllname,
+    importc: "glFogCoordfEXfloat".}
+proc glFogCoorddEXdouble*(coord: TGLdouble){.dynlib: dllname,
+    importc: "glFogCoorddEXdouble".}
+proc glFogCoordfvEXfloat*(coord: TGLfloat){.dynlib: dllname,
+    importc: "glFogCoordfvEXfloat".}
+proc glFogCoorddvEXdouble*(coord: TGLdouble){.dynlib: dllname,
+    importc: "glFogCoorddvEXdouble".}
+proc glFogCoordPointerEXT*(thetype: TGLenum, stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glFogCoordPointerEXT".}
+  #***** GL_EXT_histogram *****//
+const
+  constGL_HISTOGRAM_EXT* = 0x00008024
+  GL_PROXY_HISTOGRAM_EXT* = 0x00008025
+  GL_HISTOGRAM_WIDTH_EXT* = 0x00008026
+  GL_HISTOGRAM_FORMAT_EXT* = 0x00008027
+  GL_HISTOGRAM_RED_SIZE_EXT* = 0x00008028
+  GL_HISTOGRAM_GREEN_SIZE_EXT* = 0x00008029
+  GL_HISTOGRAM_BLUE_SIZE_EXT* = 0x0000802A
+  GL_HISTOGRAM_ALPHA_SIZE_EXT* = 0x0000802B
+  GL_HISTOGRAM_LUMINANCE_SIZE_EXT* = 0x0000802C
+  GL_HISTOGRAM_SINK_EXT* = 0x0000802D
+  constGL_MINMAX_EXT* = 0x0000802E
+  GL_MINMAX_FORMAT_EXT* = 0x0000802F
+  GL_MINMAX_SINK_EXT* = 0x00008030
+
+proc glHistogramEXT*(target: TGLenum, width: TGLsizei, internalformat: TGLenum,
+                     sink: TGLboolean){.dynlib: dllname,
+                                        importc: "glHistogramEXT".}
+proc glResetHistogramEXT*(target: TGLenum){.dynlib: dllname,
+    importc: "glResetHistogramEXT".}
+proc glGetHistogramEXT*(target: TGLenum, reset: TGLboolean, format: TGLenum,
+                        thetype: TGLenum, values: PGLvoid){.dynlib: dllname,
+    importc: "glGetHistogramEXT".}
+proc glGetHistogramParameterivEXT*(target: TGLenum, pname: TGLenum,
+                                   params: PGLint){.dynlib: dllname,
+    importc: "glGetHistogramParameterivEXT".}
+proc glGetHistogramParameterfvEXT*(target: TGLenum, pname: TGLenum,
+                                   params: PGLfloat){.dynlib: dllname,
+    importc: "glGetHistogramParameterfvEXT".}
+proc glMinmaxEXT*(target: TGLenum, internalformat: TGLenum, sink: TGLboolean){.
+    dynlib: dllname, importc: "glMinmaxEXT".}
+proc glResetMinmaxEXT*(target: TGLenum){.dynlib: dllname,
+    importc: "glResetMinmaxEXT".}
+proc glGetMinmaxEXT*(target: TGLenum, reset: TGLboolean, format: TGLenum,
+                     thetype: TGLenum, values: PGLvoid){.dynlib: dllname,
+    importc: "glGetMinmaxEXT".}
+proc glGetMinmaxParameterivEXT*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMinmaxParameterivEXT".}
+proc glGetMinmaxParameterfvEXT*(target: TGLenum, pname: TGLenum,
+                                params: PGLfloat){.dynlib: dllname,
+    importc: "glGetMinmaxParameterfvEXT".}
+  #***** GL_EXT_multi_draw_arrays *****//
+proc glMultiDrawArraysEXT*(mode: TGLenum, first: PGLint, count: PGLsizei,
+                           primcount: TGLsizei){.dynlib: dllname,
+    importc: "glMultiDrawArraysEXT".}
+proc glMultiDrawElementsEXT*(mode: TGLenum, count: PGLsizei, thetype: TGLenum,
+                             indices: PGLvoid, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawElementsEXT".}
+  #***** GL_EXT_packed_pixels *****//
+const
+  GL_UNSIGNED_BYTE_3_3_2_EXT* = 0x00008032
+  GL_UNSIGNED_SHORT_4_4_4_4_EXT* = 0x00008033
+  GL_UNSIGNED_SHORT_5_5_5_1_EXT* = 0x00008034
+  GL_UNSIGNED_INT_8_8_8_8_EXT* = 0x00008035
+  GL_UNSIGNED_INT_10_10_10_2_EXT* = 0x00008036
+  #***** GL_EXT_paletted_texture *****//
+
+const
+  GL_COLOR_INDEX1_EXT* = 0x000080E2
+  GL_COLOR_INDEX2_EXT* = 0x000080E3
+  GL_COLOR_INDEX4_EXT* = 0x000080E4
+  GL_COLOR_INDEX8_EXT* = 0x000080E5
+  GL_COLOR_INDEX12_EXT* = 0x000080E6
+  GL_COLOR_INDEX16_EXT* = 0x000080E7
+  GL_COLOR_TABLE_FORMAT_EXT* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH_EXT* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE_EXT* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE_EXT* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE_EXT* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE_EXT* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE_EXT* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE_EXT* = 0x000080DF
+  GL_TEXTURE_INDEX_SIZE_EXT* = 0x000080ED
+  GL_TEXTURE_1D* = 0x00000DE0
+  GL_TEXTURE_2D* = 0x00000DE1
+  GL_TEXTURE_3D_EXT* = 0x0000806F # GL_TEXTURE_CUBE_MAP_ARB  { already defined }
+  GL_PROXY_TEXTURE_1D* = 0x00008063
+  GL_PROXY_TEXTURE_2D* = 0x00008064
+  GL_PROXY_TEXTURE_3D_EXT* = 0x00008070 # GL_PROXY_TEXTURE_CUBE_MAP_ARB  { already defined }
+                                        # GL_TEXTURE_1D  { already defined }
+                                        # GL_TEXTURE_2D  { already defined }
+                                        # GL_TEXTURE_3D_EXT  { already defined }
+                                        # GL_TEXTURE_CUBE_MAP_ARB  { already defined }
+
+proc glColorTableEXT*(target: TGLenum, internalFormat: TGLenum, width: TGLsizei,
+                      format: TGLenum, thetype: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glColorTableEXT".}
+  # glColorSubTableEXT  { already defined }
+proc glGetColorTableEXT*(target: TGLenum, format: TGLenum, thetype: TGLenum,
+                         data: PGLvoid){.dynlib: dllname,
+    importc: "glGetColorTableEXT".}
+proc glGetColorTableParameterivEXT*(target: TGLenum, pname: TGLenum,
+                                    params: PGLint){.dynlib: dllname,
+    importc: "glGetColorTableParameterivEXT".}
+proc glGetColorTableParameterfvEXT*(target: TGLenum, pname: TGLenum,
+                                    params: PGLfloat){.dynlib: dllname,
+    importc: "glGetColorTableParameterfvEXT".}
+  #***** GL_EXT_point_parameters *****//
+const
+  GL_POINT_SIZE_MIN_EXT* = 0x00008126
+  GL_POINT_SIZE_MAX_EXT* = 0x00008127
+  GL_POINT_FADE_THRESHOLD_SIZE_EXT* = 0x00008128
+  GL_DISTANCE_ATTENUATION_EXT* = 0x00008129
+
+proc glPointParameterfEXT*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glPointParameterfEXT".}
+proc glPointParameterfvEXT*(pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glPointParameterfvEXT".}
+  #***** GL_EXT_polygon_offset *****//
+const
+  constGL_POLYGON_OFFSET_EXT* = 0x00008037
+  GL_POLYGON_OFFSET_FACTOR_EXT* = 0x00008038
+  GL_POLYGON_OFFSET_BIAS_EXT* = 0x00008039
+
+proc glPolygonOffsetEXT*(factor: TGLfloat, bias: TGLfloat){.dynlib: dllname,
+    importc: "glPolygonOffsetEXT".}
+  #***** GL_EXT_secondary_color *****//
+const
+  GL_COLOR_SUM_EXT* = 0x00008458
+  GL_CURRENT_SECONDARY_COLOR_EXT* = 0x00008459
+  GL_SECONDARY_COLOR_ARRAY_SIZE_EXT* = 0x0000845A
+  GL_SECONDARY_COLOR_ARRAY_TYPE_EXT* = 0x0000845B
+  GL_SECONDARY_COLOR_ARRAY_STRIDE_EXT* = 0x0000845C
+  GL_SECONDARY_COLOR_ARRAY_POINTER_EXT* = 0x0000845D
+  GL_SECONDARY_COLOR_ARRAY_EXT* = 0x0000845E
+
+proc glSecondaryColor3bEXT*(components: TGLbyte){.dynlib: dllname,
+    importc: "glSecondaryColor3bEXT".}
+proc glSecondaryColor3sEXT*(components: TGLshort){.dynlib: dllname,
+    importc: "glSecondaryColor3sEXT".}
+proc glSecondaryColor3iEXT*(components: TGLint){.dynlib: dllname,
+    importc: "glSecondaryColor3iEXT".}
+proc glSecondaryColor3fEXT*(components: TGLfloat){.dynlib: dllname,
+    importc: "glSecondaryColor3fEXT".}
+proc glSecondaryColor3dEXT*(components: TGLdouble){.dynlib: dllname,
+    importc: "glSecondaryColor3dEXT".}
+proc glSecondaryColor3ubEXT*(components: TGLubyte){.dynlib: dllname,
+    importc: "glSecondaryColor3ubEXT".}
+proc glSecondaryColor3usEXT*(components: TGLushort){.dynlib: dllname,
+    importc: "glSecondaryColor3usEXT".}
+proc glSecondaryColor3uiEXT*(components: TGLuint){.dynlib: dllname,
+    importc: "glSecondaryColor3uiEXT".}
+proc glSecondaryColor3bvEXT*(components: TGLbyte){.dynlib: dllname,
+    importc: "glSecondaryColor3bvEXT".}
+proc glSecondaryColor3svEXT*(components: TGLshort){.dynlib: dllname,
+    importc: "glSecondaryColor3svEXT".}
+proc glSecondaryColor3ivEXT*(components: TGLint){.dynlib: dllname,
+    importc: "glSecondaryColor3ivEXT".}
+proc glSecondaryColor3fvEXT*(components: TGLfloat){.dynlib: dllname,
+    importc: "glSecondaryColor3fvEXT".}
+proc glSecondaryColor3dvEXT*(components: TGLdouble){.dynlib: dllname,
+    importc: "glSecondaryColor3dvEXT".}
+proc glSecondaryColor3ubvEXT*(components: TGLubyte){.dynlib: dllname,
+    importc: "glSecondaryColor3ubvEXT".}
+proc glSecondaryColor3usvEXT*(components: TGLushort){.dynlib: dllname,
+    importc: "glSecondaryColor3usvEXT".}
+proc glSecondaryColor3uivEXT*(components: TGLuint){.dynlib: dllname,
+    importc: "glSecondaryColor3uivEXT".}
+proc glSecondaryColorPointerEXT*(size: TGLint, thetype: TGLenum,
+                                 stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glSecondaryColorPointerEXT".}
+  #***** GL_EXT_separate_specular_color *****//
+const
+  GL_LIGHT_MODEL_COLOR_CONTROL_EXT* = 0x000081F8
+  GL_SINGLE_COLOR_EXT* = 0x000081F9
+  GL_SEPARATE_SPECULAR_COLOR_EXT* = 0x000081FA
+  #***** GL_EXT_shadow_funcs *****//
+  #***** GL_EXT_shared_texture_palette *****//
+
+const
+  GL_SHARED_TEXTURE_PALETTE_EXT* = 0x000081FB
+  #***** GL_EXT_stencil_two_side *****//
+
+const
+  GL_STENCIL_TEST_TWO_SIDE_EXT* = 0x00008910
+  constGL_ACTIVE_STENCIL_FACE_EXT* = 0x00008911
+
+proc glActiveStencilFaceEXT*(face: TGLenum){.dynlib: dllname,
+    importc: "glActiveStencilFaceEXT".}
+  #***** GL_EXT_stencil_wrap *****//
+const
+  GL_INCR_WRAP_EXT* = 0x00008507
+  GL_DECR_WRAP_EXT* = 0x00008508
+  #***** GL_EXT_subtexture *****//
+
+proc glTexSubImage1DEXT*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                         width: TGLsizei, format: TGLenum, thetype: TGLenum,
+                         pixels: PGLvoid){.dynlib: dllname,
+    importc: "glTexSubImage1DEXT".}
+proc glTexSubImage2DEXT*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                         yoffset: TGLint, width: TGLsizei, height: TGLsizei,
+                         format: TGLenum, thetype: TGLenum, pixels: PGLvoid){.
+    dynlib: dllname, importc: "glTexSubImage2DEXT".}
+proc glTexSubImage3DEXT*(target: TGLenum, level: TGLint, xoffset: TGLint,
+                         yoffset: TGLint, zoffset: TGLint, width: TGLsizei,
+                         height: TGLsizei, depth: TGLsizei, format: TGLenum,
+                         thetype: TGLenum, pixels: PGLvoid){.dynlib: dllname,
+    importc: "glTexSubImage3DEXT".}
+  #***** GL_EXT_texture3D *****//
+const
+  GL_PACK_SKIP_IMAGES_EXT* = 0x0000806B
+  GL_PACK_IMAGE_HEIGHT_EXT* = 0x0000806C
+  GL_UNPACK_SKIP_IMAGES_EXT* = 0x0000806D
+  GL_UNPACK_IMAGE_HEIGHT_EXT* = 0x0000806E # GL_TEXTURE_3D_EXT  { already defined }
+                                           # GL_PROXY_TEXTURE_3D_EXT  { already defined }
+  GL_TEXTURE_DEPTH_EXT* = 0x00008071
+  GL_TEXTURE_WRAP_R_EXT* = 0x00008072
+  GL_MAX_3D_TEXTURE_SIZE_EXT* = 0x00008073
+
+proc glTexImage3DEXT*(target: TGLenum, level: TGLint, internalformat: TGLenum,
+                      width: TGLsizei, height: TGLsizei, depth: TGLsizei,
+                      border: TGLint, format: TGLenum, thetype: TGLenum,
+                      pixels: PGLvoid){.dynlib: dllname,
+                                        importc: "glTexImage3DEXT".}
+  #***** GL_EXT_texture_compression_s3tc *****//
+const
+  GL_COMPRESSED_RGB_S3TC_DXT1_EXT* = 0x000083F0
+  GL_COMPRESSED_RGBA_S3TC_DXT1_EXT* = 0x000083F1
+  GL_COMPRESSED_RGBA_S3TC_DXT3_EXT* = 0x000083F2
+  GL_COMPRESSED_RGBA_S3TC_DXT5_EXT* = 0x000083F3
+  #***** GL_EXT_texture_env_add *****//
+  #***** GL_EXT_texture_env_combine *****//
+
+const
+  GL_COMBINE_EXT* = 0x00008570
+  GL_COMBINE_RGB_EXT* = 0x00008571
+  GL_COMBINE_ALPHA_EXT* = 0x00008572
+  GL_SOURCE0_RGB_EXT* = 0x00008580
+  GL_SOURCE1_RGB_EXT* = 0x00008581
+  GL_SOURCE2_RGB_EXT* = 0x00008582
+  GL_SOURCE0_ALPHA_EXT* = 0x00008588
+  GL_SOURCE1_ALPHA_EXT* = 0x00008589
+  GL_SOURCE2_ALPHA_EXT* = 0x0000858A
+  GL_OPERAND0_RGB_EXT* = 0x00008590
+  GL_OPERAND1_RGB_EXT* = 0x00008591
+  GL_OPERAND2_RGB_EXT* = 0x00008592
+  GL_OPERAND0_ALPHA_EXT* = 0x00008598
+  GL_OPERAND1_ALPHA_EXT* = 0x00008599
+  GL_OPERAND2_ALPHA_EXT* = 0x0000859A
+  GL_RGB_SCALE_EXT* = 0x00008573
+  GL_ADD_SIGNED_EXT* = 0x00008574
+  GL_INTERPOLATE_EXT* = 0x00008575
+  GL_CONSTANT_EXT* = 0x00008576
+  GL_PRIMARY_COLOR_EXT* = 0x00008577
+  GL_PREVIOUS_EXT* = 0x00008578
+  #***** GL_EXT_texture_env_dot3 *****//
+
+const
+  GL_DOT3_RGB_EXT* = 0x00008740
+  GL_DOT3_RGBA_EXT* = 0x00008741
+  #***** GL_EXT_texture_filter_anisotropic *****//
+
+const
+  GL_TEXTURE_MAX_ANISOTROPY_EXT* = 0x000084FE
+  GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT* = 0x000084FF
+  #***** GL_EXT_texture_lod_bias *****//
+
+const
+  GL_TEXTURE_FILTER_CONTROL_EXT* = 0x00008500
+  GL_TEXTURE_LOD_BIAS_EXT* = 0x00008501
+  GL_MAX_TEXTURE_LOD_BIAS_EXT* = 0x000084FD
+  #***** GL_EXT_texture_object *****//
+
+const
+  GL_TEXTURE_PRIORITY_EXT* = 0x00008066
+  GL_TEXTURE_RESIDENT_EXT* = 0x00008067
+  GL_TEXTURE_1D_BINDING_EXT* = 0x00008068
+  GL_TEXTURE_2D_BINDING_EXT* = 0x00008069
+  GL_TEXTURE_3D_BINDING_EXT* = 0x0000806A
+
+proc glGenTexturesEXT*(n: TGLsizei, textures: PGLuint){.dynlib: dllname,
+    importc: "glGenTexturesEXT".}
+proc glDeleteTexturesEXT*(n: TGLsizei, textures: PGLuint){.dynlib: dllname,
+    importc: "glDeleteTexturesEXT".}
+proc glBindTextureEXT*(target: TGLenum, texture: TGLuint){.dynlib: dllname,
+    importc: "glBindTextureEXT".}
+proc glPrioritizeTexturesEXT*(n: TGLsizei, textures: PGLuint,
+                              priorities: PGLclampf){.dynlib: dllname,
+    importc: "glPrioritizeTexturesEXT".}
+proc glAreTexturesResidentEXT*(n: TGLsizei, textures: PGLuint,
+                               residences: PGLboolean): TGLboolean{.
+    dynlib: dllname, importc: "glAreTexturesResidentEXT".}
+proc glIsTextureEXT*(texture: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsTextureEXT".}
+  #***** GL_EXT_vertex_array *****//
+const
+  GL_VERTEX_ARRAY_EXT* = 0x00008074
+  GL_NORMAL_ARRAY_EXT* = 0x00008075
+  GL_COLOR_ARRAY_EXT* = 0x00008076
+  GL_INDEX_ARRAY_EXT* = 0x00008077
+  GL_TEXTURE_COORD_ARRAY_EXT* = 0x00008078
+  GL_EDGE_FLAG_ARRAY_EXT* = 0x00008079
+  GL_DOUBLE_EXT* = 0x0000140A
+  GL_VERTEX_ARRAY_SIZE_EXT* = 0x0000807A
+  GL_VERTEX_ARRAY_TYPE_EXT* = 0x0000807B
+  GL_VERTEX_ARRAY_STRIDE_EXT* = 0x0000807C
+  GL_VERTEX_ARRAY_COUNT_EXT* = 0x0000807D
+  GL_NORMAL_ARRAY_TYPE_EXT* = 0x0000807E
+  GL_NORMAL_ARRAY_STRIDE_EXT* = 0x0000807F
+  GL_NORMAL_ARRAY_COUNT_EXT* = 0x00008080
+  GL_COLOR_ARRAY_SIZE_EXT* = 0x00008081
+  GL_COLOR_ARRAY_TYPE_EXT* = 0x00008082
+  GL_COLOR_ARRAY_STRIDE_EXT* = 0x00008083
+  GL_COLOR_ARRAY_COUNT_EXT* = 0x00008084
+  GL_INDEX_ARRAY_TYPE_EXT* = 0x00008085
+  GL_INDEX_ARRAY_STRIDE_EXT* = 0x00008086
+  GL_INDEX_ARRAY_COUNT_EXT* = 0x00008087
+  GL_TEXTURE_COORD_ARRAY_SIZE_EXT* = 0x00008088
+  GL_TEXTURE_COORD_ARRAY_TYPE_EXT* = 0x00008089
+  GL_TEXTURE_COORD_ARRAY_STRIDE_EXT* = 0x0000808A
+  GL_TEXTURE_COORD_ARRAY_COUNT_EXT* = 0x0000808B
+  GL_EDGE_FLAG_ARRAY_STRIDE_EXT* = 0x0000808C
+  GL_EDGE_FLAG_ARRAY_COUNT_EXT* = 0x0000808D
+  GL_VERTEX_ARRAY_POINTER_EXT* = 0x0000808E
+  GL_NORMAL_ARRAY_POINTER_EXT* = 0x0000808F
+  GL_COLOR_ARRAY_POINTER_EXT* = 0x00008090
+  GL_INDEX_ARRAY_POINTER_EXT* = 0x00008091
+  GL_TEXTURE_COORD_ARRAY_POINTER_EXT* = 0x00008092
+  GL_EDGE_FLAG_ARRAY_POINTER_EXT* = 0x00008093
+
+proc glArrayElementEXT*(i: TGLint){.dynlib: dllname,
+                                    importc: "glArrayElementEXT".}
+proc glDrawArraysEXT*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawArraysEXT".}
+proc glVertexPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                         count: TGLsizei, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glVertexPointerEXT".}
+proc glNormalPointerEXT*(thetype: TGLenum, stride: TGLsizei, count: TGLsizei,
+                         pointer: PGLvoid){.dynlib: dllname,
+    importc: "glNormalPointerEXT".}
+proc glColorPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                        count: TGLsizei, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glColorPointerEXT".}
+proc glIndexPointerEXT*(thetype: TGLenum, stride: TGLsizei, count: TGLsizei,
+                        pointer: PGLvoid){.dynlib: dllname,
+    importc: "glIndexPointerEXT".}
+proc glTexCoordPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                           count: TGLsizei, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glTexCoordPointerEXT".}
+proc glEdgeFlagPointerEXT*(stride: TGLsizei, count: TGLsizei,
+                           pointer: PGLboolean){.dynlib: dllname,
+    importc: "glEdgeFlagPointerEXT".}
+proc glGetPointervEXT*(pname: TGLenum, params: PGLvoid){.dynlib: dllname,
+    importc: "glGetPointervEXT".}
+  #***** GL_EXT_vertex_shader *****//
+const
+  GL_VERTEX_SHADER_EXT* = 0x00008780
+  GL_VARIANT_VALUE_EXT* = 0x000087E4
+  GL_VARIANT_DATATYPE_EXT* = 0x000087E5
+  GL_VARIANT_ARRAY_STRIDE_EXT* = 0x000087E6
+  GL_VARIANT_ARRAY_TYPE_EXT* = 0x000087E7
+  GL_VARIANT_ARRAY_EXT* = 0x000087E8
+  GL_VARIANT_ARRAY_POINTER_EXT* = 0x000087E9
+  GL_INVARIANT_VALUE_EXT* = 0x000087EA
+  GL_INVARIANT_DATATYPE_EXT* = 0x000087EB
+  GL_LOCAL_CONSTANT_VALUE_EXT* = 0x000087EC
+  GL_LOCAL_CONSTANT_DATATYPE_EXT* = 0x000087ED
+  GL_OP_INDEX_EXT* = 0x00008782
+  GL_OP_NEGATE_EXT* = 0x00008783
+  GL_OP_DOT3_EXT* = 0x00008784
+  GL_OP_DOT4_EXT* = 0x00008785
+  GL_OP_MUL_EXT* = 0x00008786
+  GL_OP_ADD_EXT* = 0x00008787
+  GL_OP_MADD_EXT* = 0x00008788
+  GL_OP_FRAC_EXT* = 0x00008789
+  GL_OP_MAX_EXT* = 0x0000878A
+  GL_OP_MIN_EXT* = 0x0000878B
+  GL_OP_SET_GE_EXT* = 0x0000878C
+  GL_OP_SET_LT_EXT* = 0x0000878D
+  GL_OP_CLAMP_EXT* = 0x0000878E
+  GL_OP_FLOOR_EXT* = 0x0000878F
+  GL_OP_ROUND_EXT* = 0x00008790
+  GL_OP_EXP_BASE_2_EXT* = 0x00008791
+  GL_OP_LOG_BASE_2_EXT* = 0x00008792
+  GL_OP_POWER_EXT* = 0x00008793
+  GL_OP_RECIP_EXT* = 0x00008794
+  GL_OP_RECIP_SQRT_EXT* = 0x00008795
+  GL_OP_SUB_EXT* = 0x00008796
+  GL_OP_CROSS_PRODUCT_EXT* = 0x00008797
+  GL_OP_MULTIPLY_MATRIX_EXT* = 0x00008798
+  GL_OP_MOV_EXT* = 0x00008799
+  GL_OUTPUT_VERTEX_EXT* = 0x0000879A
+  GL_OUTPUT_COLOR0_EXT* = 0x0000879B
+  GL_OUTPUT_COLOR1_EXT* = 0x0000879C
+  GL_OUTPUT_TEXTURE_COORD0_EXT* = 0x0000879D
+  GL_OUTPUT_TEXTURE_COORD1_EXT* = 0x0000879E
+  GL_OUTPUT_TEXTURE_COORD2_EXT* = 0x0000879F
+  GL_OUTPUT_TEXTURE_COORD3_EXT* = 0x000087A0
+  GL_OUTPUT_TEXTURE_COORD4_EXT* = 0x000087A1
+  GL_OUTPUT_TEXTURE_COORD5_EXT* = 0x000087A2
+  GL_OUTPUT_TEXTURE_COORD6_EXT* = 0x000087A3
+  GL_OUTPUT_TEXTURE_COORD7_EXT* = 0x000087A4
+  GL_OUTPUT_TEXTURE_COORD8_EXT* = 0x000087A5
+  GL_OUTPUT_TEXTURE_COORD9_EXT* = 0x000087A6
+  GL_OUTPUT_TEXTURE_COORD10_EXT* = 0x000087A7
+  GL_OUTPUT_TEXTURE_COORD11_EXT* = 0x000087A8
+  GL_OUTPUT_TEXTURE_COORD12_EXT* = 0x000087A9
+  GL_OUTPUT_TEXTURE_COORD13_EXT* = 0x000087AA
+  GL_OUTPUT_TEXTURE_COORD14_EXT* = 0x000087AB
+  GL_OUTPUT_TEXTURE_COORD15_EXT* = 0x000087AC
+  GL_OUTPUT_TEXTURE_COORD16_EXT* = 0x000087AD
+  GL_OUTPUT_TEXTURE_COORD17_EXT* = 0x000087AE
+  GL_OUTPUT_TEXTURE_COORD18_EXT* = 0x000087AF
+  GL_OUTPUT_TEXTURE_COORD19_EXT* = 0x000087B0
+  GL_OUTPUT_TEXTURE_COORD20_EXT* = 0x000087B1
+  GL_OUTPUT_TEXTURE_COORD21_EXT* = 0x000087B2
+  GL_OUTPUT_TEXTURE_COORD22_EXT* = 0x000087B3
+  GL_OUTPUT_TEXTURE_COORD23_EXT* = 0x000087B4
+  GL_OUTPUT_TEXTURE_COORD24_EXT* = 0x000087B5
+  GL_OUTPUT_TEXTURE_COORD25_EXT* = 0x000087B6
+  GL_OUTPUT_TEXTURE_COORD26_EXT* = 0x000087B7
+  GL_OUTPUT_TEXTURE_COORD27_EXT* = 0x000087B8
+  GL_OUTPUT_TEXTURE_COORD28_EXT* = 0x000087B9
+  GL_OUTPUT_TEXTURE_COORD29_EXT* = 0x000087BA
+  GL_OUTPUT_TEXTURE_COORD30_EXT* = 0x000087BB
+  GL_OUTPUT_TEXTURE_COORD31_EXT* = 0x000087BC
+  GL_OUTPUT_FOG_EXT* = 0x000087BD
+  GL_SCALAR_EXT* = 0x000087BE
+  GL_VECTOR_EXT* = 0x000087BF
+  GL_MATRIX_EXT* = 0x000087C0
+  GL_VARIANT_EXT* = 0x000087C1
+  GL_INVARIANT_EXT* = 0x000087C2
+  GL_LOCAL_CONSTANT_EXT* = 0x000087C3
+  GL_LOCAL_EXT* = 0x000087C4
+  GL_MAX_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x000087C5
+  GL_MAX_VERTEX_SHADER_VARIANTS_EXT* = 0x000087C6
+  GL_MAX_VERTEX_SHADER_INVARIANTS_EXT* = 0x000087C7
+  GL_MAX_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x000087C8
+  GL_MAX_VERTEX_SHADER_LOCALS_EXT* = 0x000087C9
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x000087CA
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_VARIANTS_EXT* = 0x000087CB
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x000087CC
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_INVARIANTS_EXT* = 0x000087CD
+  GL_MAX_OPTIMIZED_VERTEX_SHADER_LOCALS_EXT* = 0x000087CE
+  GL_VERTEX_SHADER_INSTRUCTIONS_EXT* = 0x000087CF
+  GL_VERTEX_SHADER_VARIANTS_EXT* = 0x000087D0
+  GL_VERTEX_SHADER_INVARIANTS_EXT* = 0x000087D1
+  GL_VERTEX_SHADER_LOCAL_CONSTANTS_EXT* = 0x000087D2
+  GL_VERTEX_SHADER_LOCALS_EXT* = 0x000087D3
+  GL_VERTEX_SHADER_BINDING_EXT* = 0x00008781
+  GL_VERTEX_SHADER_OPTIMIZED_EXT* = 0x000087D4
+  GL_X_EXT* = 0x000087D5
+  GL_Y_EXT* = 0x000087D6
+  GL_Z_EXT* = 0x000087D7
+  GL_W_EXT* = 0x000087D8
+  GL_NEGATIVE_X_EXT* = 0x000087D9
+  GL_NEGATIVE_Y_EXT* = 0x000087DA
+  GL_NEGATIVE_Z_EXT* = 0x000087DB
+  GL_NEGATIVE_W_EXT* = 0x000087DC
+  GL_ZERO_EXT* = 0x000087DD
+  GL_ONE_EXT* = 0x000087DE
+  GL_NEGATIVE_ONE_EXT* = 0x000087DF
+  GL_NORMALIZED_RANGE_EXT* = 0x000087E0
+  GL_FULL_RANGE_EXT* = 0x000087E1
+  GL_CURRENT_VERTEX_EXT* = 0x000087E2
+  GL_MVP_MATRIX_EXT* = 0x000087E3
+
+proc glBeginVertexShaderEXT*(){.dynlib: dllname,
+                                importc: "glBeginVertexShaderEXT".}
+proc glEndVertexShaderEXT*(){.dynlib: dllname, importc: "glEndVertexShaderEXT".}
+proc glBindVertexShaderEXT*(id: TGLuint){.dynlib: dllname,
+    importc: "glBindVertexShaderEXT".}
+proc glGenVertexShadersEXT*(range: TGLuint): TGLuint{.dynlib: dllname,
+    importc: "glGenVertexShadersEXT".}
+proc glDeleteVertexShaderEXT*(id: TGLuint){.dynlib: dllname,
+    importc: "glDeleteVertexShaderEXT".}
+proc glShaderOp1EXT*(op: TGLenum, res: TGLuint, arg1: TGLuint){.dynlib: dllname,
+    importc: "glShaderOp1EXT".}
+proc glShaderOp2EXT*(op: TGLenum, res: TGLuint, arg1: TGLuint, arg2: TGLuint){.
+    dynlib: dllname, importc: "glShaderOp2EXT".}
+proc glShaderOp3EXT*(op: TGLenum, res: TGLuint, arg1: TGLuint, arg2: TGLuint,
+                     arg3: TGLuint){.dynlib: dllname, importc: "glShaderOp3EXT".}
+proc glSwizzleEXT*(res: TGLuint, theIn: TGLuint, outX: TGLenum, outY: TGLenum,
+                   outZ: TGLenum, outW: TGLenum){.dynlib: dllname,
+    importc: "glSwizzleEXT".}
+proc glWriteMaskEXT*(res: TGLuint, theIn: TGLuint, outX: TGLenum, outY: TGLenum,
+                     outZ: TGLenum, outW: TGLenum){.dynlib: dllname,
+    importc: "glWriteMaskEXT".}
+proc glInsertComponentEXT*(res: TGLuint, src: TGLuint, num: TGLuint){.
+    dynlib: dllname, importc: "glInsertComponentEXT".}
+proc glExtractComponentEXT*(res: TGLuint, src: TGLuint, num: TGLuint){.
+    dynlib: dllname, importc: "glExtractComponentEXT".}
+proc glGenSymbolsEXT*(datatype: TGLenum, storagetype: TGLenum, range: TGLenum,
+                      components: TGLuint): TGLuint{.dynlib: dllname,
+    importc: "glGenSymbolsEXT".}
+proc glSetInvariantEXT*(id: TGLuint, thetype: TGLenum, address: PGLvoid){.
+    dynlib: dllname, importc: "glSetInvariantEXT".}
+proc glSetLocalConstantEXT*(id: TGLuint, thetype: TGLenum, address: PGLvoid){.
+    dynlib: dllname, importc: "glSetLocalConstantEXT".}
+proc glVariantbvEXT*(id: TGLuint, address: PGLbyte){.dynlib: dllname,
+    importc: "glVariantbvEXT".}
+proc glVariantsvEXT*(id: TGLuint, address: PGLshort){.dynlib: dllname,
+    importc: "glVariantsvEXT".}
+proc glVariantivEXT*(id: TGLuint, address: PGLint){.dynlib: dllname,
+    importc: "glVariantivEXT".}
+proc glVariantfvEXT*(id: TGLuint, address: PGLfloat){.dynlib: dllname,
+    importc: "glVariantfvEXT".}
+proc glVariantdvEXT*(id: TGLuint, address: PGLdouble){.dynlib: dllname,
+    importc: "glVariantdvEXT".}
+proc glVariantubvEXT*(id: TGLuint, address: PGLubyte){.dynlib: dllname,
+    importc: "glVariantubvEXT".}
+proc glVariantusvEXT*(id: TGLuint, address: PGLushort){.dynlib: dllname,
+    importc: "glVariantusvEXT".}
+proc glVariantuivEXT*(id: TGLuint, address: PGLuint){.dynlib: dllname,
+    importc: "glVariantuivEXT".}
+proc glVariantPointerEXT*(id: TGLuint, thetype: TGLenum, stride: TGLuint,
+                          address: PGLvoid){.dynlib: dllname,
+    importc: "glVariantPointerEXT".}
+proc glEnableVariantClientStateEXT*(id: TGLuint){.dynlib: dllname,
+    importc: "glEnableVariantClientStateEXT".}
+proc glDisableVariantClientStateEXT*(id: TGLuint){.dynlib: dllname,
+    importc: "glDisableVariantClientStateEXT".}
+proc glBindLightParameterEXT*(light: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindLightParameterEXT".}
+proc glBindMaterialParameterEXT*(face: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindMaterialParameterEXT".}
+proc glBindTexGenParameterEXT*(theunit: TGLenum, coord: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindTexGenParameterEXT".}
+proc glBindTextureUnitParameterEXT*(theunit: TGLenum, value: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glBindTextureUnitParameterEXT".}
+proc glBindParameterEXT*(value: TGLenum): TGLuint{.dynlib: dllname,
+    importc: "glBindParameterEXT".}
+proc glIsVariantEnabledEXT*(id: TGLuint, cap: TGLenum): TGLboolean{.
+    dynlib: dllname, importc: "glIsVariantEnabledEXT".}
+proc glGetVariantBooleanvEXT*(id: TGLuint, value: TGLenum, data: PGLboolean){.
+    dynlib: dllname, importc: "glGetVariantBooleanvEXT".}
+proc glGetVariantIntegervEXT*(id: TGLuint, value: TGLenum, data: PGLint){.
+    dynlib: dllname, importc: "glGetVariantIntegervEXT".}
+proc glGetVariantFloatvEXT*(id: TGLuint, value: TGLenum, data: PGLfloat){.
+    dynlib: dllname, importc: "glGetVariantFloatvEXT".}
+proc glGetVariantPointervEXT*(id: TGLuint, value: TGLenum, data: PGLvoid){.
+    dynlib: dllname, importc: "glGetVariantPointervEXT".}
+proc glGetInvariantBooleanvEXT*(id: TGLuint, value: TGLenum, data: PGLboolean){.
+    dynlib: dllname, importc: "glGetInvariantBooleanvEXT".}
+proc glGetInvariantIntegervEXT*(id: TGLuint, value: TGLenum, data: PGLint){.
+    dynlib: dllname, importc: "glGetInvariantIntegervEXT".}
+proc glGetInvariantFloatvEXT*(id: TGLuint, value: TGLenum, data: PGLfloat){.
+    dynlib: dllname, importc: "glGetInvariantFloatvEXT".}
+proc glGetLocalConstantBooleanvEXT*(id: TGLuint, value: TGLenum,
+                                    data: PGLboolean){.dynlib: dllname,
+    importc: "glGetLocalConstantBooleanvEXT".}
+proc glGetLocalConstantIntegervEXT*(id: TGLuint, value: TGLenum, data: PGLint){.
+    dynlib: dllname, importc: "glGetLocalConstantIntegervEXT".}
+proc glGetLocalConstantFloatvEXT*(id: TGLuint, value: TGLenum, data: PGLfloat){.
+    dynlib: dllname, importc: "glGetLocalConstantFloatvEXT".}
+  #***** GL_EXT_vertex_weighting *****//
+const
+  GL_VERTEX_WEIGHTING_EXT* = 0x00008509
+  GL_MODELVIEW0_EXT* = 0x00001700
+  GL_MODELVIEW1_EXT* = 0x0000850A
+  GL_MODELVIEW0_MATRIX_EXT* = 0x00000BA6
+  GL_MODELVIEW1_MATRIX_EXT* = 0x00008506
+  GL_CURRENT_VERTEX_WEIGHT_EXT* = 0x0000850B
+  GL_VERTEX_WEIGHT_ARRAY_EXT* = 0x0000850C
+  GL_VERTEX_WEIGHT_ARRAY_SIZE_EXT* = 0x0000850D
+  GL_VERTEX_WEIGHT_ARRAY_TYPE_EXT* = 0x0000850E
+  GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT* = 0x0000850F
+  GL_MODELVIEW0_STACK_DEPTH_EXT* = 0x00000BA3
+  GL_MODELVIEW1_STACK_DEPTH_EXT* = 0x00008502
+  GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT* = 0x00008510
+
+proc glVertexWeightfEXT*(weight: TGLfloat){.dynlib: dllname,
+    importc: "glVertexWeightfEXT".}
+proc glVertexWeightfvEXT*(weight: PGLfloat){.dynlib: dllname,
+    importc: "glVertexWeightfvEXT".}
+proc glVertexWeightPointerEXT*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                               pointer: PGLvoid){.dynlib: dllname,
+    importc: "glVertexWeightPointerEXT".}
+  #***** GL_HP_occlusion_test *****//
+const
+  GL_OCCLUSION_TEST_HP* = 0x00008165
+  GL_OCCLUSION_TEST_RESULT_HP* = 0x00008166
+  #***** GL_NV_blend_square *****//
+  #***** GL_NV_copy_depth_to_color *****//
+
+const
+  GL_DEPTH_STENCIL_TO_RGBA_NV* = 0x0000886E
+  GL_DEPTH_STENCIL_TO_BGRA_NV* = 0x0000886F
+  #***** GL_NV_depth_clamp *****//
+
+const
+  GL_DEPTH_CLAMP_NV* = 0x0000864F
+  #***** GL_NV_evaluators *****//
+
+const
+  GL_EVAL_2D_NV* = 0x000086C0
+  GL_EVAL_TRIANGULAR_2D_NV* = 0x000086C1
+  GL_MAP_TESSELLATION_NV* = 0x000086C2
+  GL_MAP_ATTRIB_U_ORDER_NV* = 0x000086C3
+  GL_MAP_ATTRIB_V_ORDER_NV* = 0x000086C4
+  GL_EVAL_FRACTIONAL_TESSELLATION_NV* = 0x000086C5
+  GL_EVAL_VERTEX_ATTRIB0_NV* = 0x000086C6
+  GL_EVAL_VERTEX_ATTRIB1_NV* = 0x000086C7
+  GL_EVAL_VERTEX_ATTRIB2_NV* = 0x000086C8
+  GL_EVAL_VERTEX_ATTRIB3_NV* = 0x000086C9
+  GL_EVAL_VERTEX_ATTRIB4_NV* = 0x000086CA
+  GL_EVAL_VERTEX_ATTRIB5_NV* = 0x000086CB
+  GL_EVAL_VERTEX_ATTRIB6_NV* = 0x000086CC
+  GL_EVAL_VERTEX_ATTRIB7_NV* = 0x000086CD
+  GL_EVAL_VERTEX_ATTRIB8_NV* = 0x000086CE
+  GL_EVAL_VERTEX_ATTRIB9_NV* = 0x000086CF
+  GL_EVAL_VERTEX_ATTRIB10_NV* = 0x000086D0
+  GL_EVAL_VERTEX_ATTRIB11_NV* = 0x000086D1
+  GL_EVAL_VERTEX_ATTRIB12_NV* = 0x000086D2
+  GL_EVAL_VERTEX_ATTRIB13_NV* = 0x000086D3
+  GL_EVAL_VERTEX_ATTRIB14_NV* = 0x000086D4
+  GL_EVAL_VERTEX_ATTRIB15_NV* = 0x000086D5
+  GL_MAX_MAP_TESSELLATION_NV* = 0x000086D6
+  GL_MAX_RATIONAL_EVAL_ORDER_NV* = 0x000086D7
+
+proc glMapControlPointsNV*(target: TGLenum, index: TGLuint, thetype: TGLenum,
+                           ustride: TGLsizei, vstride: TGLsizei, uorder: TGLint,
+                           vorder: TGLint, thepacked: TGLboolean,
+                           points: PGLvoid){.dynlib: dllname,
+    importc: "glMapControlPointsNV".}
+proc glMapParameterivNV*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glMapParameterivNV".}
+proc glMapParameterfvNV*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glMapParameterfvNV".}
+proc glGetMapControlPointsNV*(target: TGLenum, index: TGLuint, thetype: TGLenum,
+                              ustride: TGLsizei, vstride: TGLsizei,
+                              thepacked: TGLboolean, points: PGLvoid){.
+    dynlib: dllname, importc: "glGetMapControlPointsNV".}
+proc glGetMapParameterivNV*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMapParameterivNV".}
+proc glGetMapParameterfvNV*(target: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetMapParameterfvNV".}
+proc glGetMapAttribParameterivNV*(target: TGLenum, index: TGLuint,
+                                  pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetMapAttribParameterivNV".}
+proc glGetMapAttribParameterfvNV*(target: TGLenum, index: TGLuint,
+                                  pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetMapAttribParameterfvNV".}
+proc glEvalMapsNV*(target: TGLenum, mode: TGLenum){.dynlib: dllname,
+    importc: "glEvalMapsNV".}
+  #***** GL_NV_fence *****//
+const
+  GL_ALL_COMPLETED_NV* = 0x000084F2
+  GL_FENCE_STATUS_NV* = 0x000084F3
+  GL_FENCE_CONDITION_NV* = 0x000084F4
+
+proc glGenFencesNV*(n: TGLsizei, fences: PGLuint){.dynlib: dllname,
+    importc: "glGenFencesNV".}
+proc glDeleteFencesNV*(n: TGLsizei, fences: PGLuint){.dynlib: dllname,
+    importc: "glDeleteFencesNV".}
+proc glSetFenceNV*(fence: TGLuint, condition: TGLenum){.dynlib: dllname,
+    importc: "glSetFenceNV".}
+proc glTestFenceNV*(fence: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glTestFenceNV".}
+proc glFinishFenceNV*(fence: TGLuint){.dynlib: dllname,
+                                       importc: "glFinishFenceNV".}
+proc glIsFenceNV*(fence: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsFenceNV".}
+proc glGetFenceivNV*(fence: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetFenceivNV".}
+  #***** GL_NV_fog_distance *****//
+const
+  GL_FOG_DISTANCE_MODE_NV* = 0x0000855A
+  GL_EYE_RADIAL_NV* = 0x0000855B
+  GL_EYE_PLANE_ABSOLUTE_NV* = 0x0000855C
+  #***** GL_NV_light_max_exponent *****//
+
+const
+  GL_MAX_SHININESS_NV* = 0x00008504
+  GL_MAX_SPOT_EXPONENT_NV* = 0x00008505
+  #***** GL_NV_multisample_filter_hint *****//
+
+const
+  GL_MULTISAMPLE_FILTER_HINT_NV* = 0x00008534
+  #***** GL_NV_occlusion_query *****//
+  # GL_OCCLUSION_TEST_HP  { already defined }
+  # GL_OCCLUSION_TEST_RESULT_HP  { already defined }
+
+const
+  GL_PIXEL_COUNTER_BITS_NV* = 0x00008864
+  GL_CURRENT_OCCLUSION_QUERY_ID_NV* = 0x00008865
+  GL_PIXEL_COUNT_NV* = 0x00008866
+  GL_PIXEL_COUNT_AVAILABLE_NV* = 0x00008867
+
+proc glGenOcclusionQueriesNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glGenOcclusionQueriesNV".}
+proc glDeleteOcclusionQueriesNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glDeleteOcclusionQueriesNV".}
+proc glIsOcclusionQueryNV*(id: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsOcclusionQueryNV".}
+proc glBeginOcclusionQueryNV*(id: TGLuint){.dynlib: dllname,
+    importc: "glBeginOcclusionQueryNV".}
+proc glEndOcclusionQueryNV*(){.dynlib: dllname, importc: "glEndOcclusionQueryNV".}
+proc glGetOcclusionQueryivNV*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetOcclusionQueryivNV".}
+proc glGetOcclusionQueryuivNV*(id: TGLuint, pname: TGLenum, params: PGLuint){.
+    dynlib: dllname, importc: "glGetOcclusionQueryuivNV".}
+  #***** GL_NV_packed_depth_stencil *****//
+const
+  GL_DEPTH_STENCIL_NV* = 0x000084F9
+  GL_UNSIGNED_INT_24_8_NV* = 0x000084FA
+  #***** GL_NV_point_sprite *****//
+
+const
+  GL_POINT_SPRITE_NV* = 0x00008861
+  GL_COORD_REPLACE_NV* = 0x00008862
+  GL_POINT_SPRITE_R_MODE_NV* = 0x00008863
+
+proc glPointParameteriNV*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glPointParameteriNV".}
+proc glPointParameterivNV*(pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glPointParameterivNV".}
+  #***** GL_NV_register_combiners *****//
+const
+  GL_REGISTER_COMBINERS_NV* = 0x00008522
+  GL_COMBINER0_NV* = 0x00008550
+  GL_COMBINER1_NV* = 0x00008551
+  GL_COMBINER2_NV* = 0x00008552
+  GL_COMBINER3_NV* = 0x00008553
+  GL_COMBINER4_NV* = 0x00008554
+  GL_COMBINER5_NV* = 0x00008555
+  GL_COMBINER6_NV* = 0x00008556
+  GL_COMBINER7_NV* = 0x00008557
+  GL_VARIABLE_A_NV* = 0x00008523
+  GL_VARIABLE_B_NV* = 0x00008524
+  GL_VARIABLE_C_NV* = 0x00008525
+  GL_VARIABLE_D_NV* = 0x00008526
+  GL_VARIABLE_E_NV* = 0x00008527
+  GL_VARIABLE_F_NV* = 0x00008528
+  GL_VARIABLE_G_NV* = 0x00008529
+  GL_CONSTANT_COLOR0_NV* = 0x0000852A
+  GL_CONSTANT_COLOR1_NV* = 0x0000852B
+  GL_PRIMARY_COLOR_NV* = 0x0000852C
+  GL_SECONDARY_COLOR_NV* = 0x0000852D
+  GL_SPARE0_NV* = 0x0000852E
+  GL_SPARE1_NV* = 0x0000852F
+  GL_UNSIGNED_IDENTITY_NV* = 0x00008536
+  GL_UNSIGNED_INVERT_NV* = 0x00008537
+  GL_EXPAND_NORMAL_NV* = 0x00008538
+  GL_EXPAND_NEGATE_NV* = 0x00008539
+  GL_HALF_BIAS_NORMAL_NV* = 0x0000853A
+  GL_HALF_BIAS_NEGATE_NV* = 0x0000853B
+  GL_SIGNED_IDENTITY_NV* = 0x0000853C
+  GL_SIGNED_NEGATE_NV* = 0x0000853D
+  GL_E_TIMES_F_NV* = 0x00008531
+  GL_SPARE0_PLUS_SECONDARY_COLOR_NV* = 0x00008532
+  GL_SCALE_BY_TWO_NV* = 0x0000853E
+  GL_SCALE_BY_FOUR_NV* = 0x0000853F
+  GL_SCALE_BY_ONE_HALF_NV* = 0x00008540
+  GL_BIAS_BY_NEGATIVE_ONE_HALF_NV* = 0x00008541
+  GL_DISCARD_NV* = 0x00008530
+  constGL_COMBINER_INPUT_NV* = 0x00008542
+  GL_COMBINER_MAPPING_NV* = 0x00008543
+  GL_COMBINER_COMPONENT_USAGE_NV* = 0x00008544
+  GL_COMBINER_AB_DOT_PRODUCT_NV* = 0x00008545
+  GL_COMBINER_CD_DOT_PRODUCT_NV* = 0x00008546
+  GL_COMBINER_MUX_SUM_NV* = 0x00008547
+  GL_COMBINER_SCALE_NV* = 0x00008548
+  GL_COMBINER_BIAS_NV* = 0x00008549
+  GL_COMBINER_AB_OUTPUT_NV* = 0x0000854A
+  GL_COMBINER_CD_OUTPUT_NV* = 0x0000854B
+  GL_COMBINER_SUM_OUTPUT_NV* = 0x0000854C
+  GL_NUM_GENERAL_COMBINERS_NV* = 0x0000854E
+  GL_COLOR_SUM_CLAMP_NV* = 0x0000854F
+  GL_MAX_GENERAL_COMBINERS_NV* = 0x0000854D
+
+proc glCombinerParameterfvNV*(pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glCombinerParameterfvNV".}
+proc glCombinerParameterivNV*(pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glCombinerParameterivNV".}
+proc glCombinerParameterfNV*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glCombinerParameterfNV".}
+proc glCombinerParameteriNV*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glCombinerParameteriNV".}
+proc glCombinerInputNV*(stage: TGLenum, portion: TGLenum, variable: TGLenum,
+                        input: TGLenum, mapping: TGLenum,
+                        componentUsage: TGLenum){.dynlib: dllname,
+    importc: "glCombinerInputNV".}
+proc glCombinerOutputNV*(stage: TGLenum, portion: TGLenum, abOutput: TGLenum,
+                         cdOutput: TGLenum, sumOutput: TGLenum, scale: TGLenum,
+                         bias: TGLenum, abDotProduct: TGLboolean,
+                         cdDotProduct: TGLboolean, muxSum: TGLboolean){.
+    dynlib: dllname, importc: "glCombinerOutputNV".}
+proc glFinalCombinerInputNV*(variable: TGLenum, input: TGLenum,
+                             mapping: TGLenum, componentUsage: TGLenum){.
+    dynlib: dllname, importc: "glFinalCombinerInputNV".}
+proc glGetCombinerInputParameterfvNV*(stage: TGLenum, portion: TGLenum,
+                                      variable: TGLenum, pname: TGLenum,
+                                      params: PGLfloat){.dynlib: dllname,
+    importc: "glGetCombinerInputParameterfvNV".}
+proc glGetCombinerInputParameterivNV*(stage: TGLenum, portion: TGLenum,
+                                      variable: TGLenum, pname: TGLenum,
+                                      params: PGLint){.dynlib: dllname,
+    importc: "glGetCombinerInputParameterivNV".}
+proc glGetCombinerOutputParameterfvNV*(stage: TGLenum, portion: TGLenum,
+                                       pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetCombinerOutputParameterfvNV".}
+proc glGetCombinerOutputParameterivNV*(stage: TGLenum, portion: TGLenum,
+                                       pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetCombinerOutputParameterivNV".}
+proc glGetFinalCombinerInputParameterfvNV*(variable: TGLenum, pname: TGLenum,
+    params: PGLfloat){.dynlib: dllname,
+                       importc: "glGetFinalCombinerInputParameterfvNV".}
+proc glGetFinalCombinerInputParameterivNV*(variable: TGLenum, pname: TGLenum,
+    params: PGLint){.dynlib: dllname,
+                     importc: "glGetFinalCombinerInputParameterivNV".}
+  #***** GL_NV_register_combiners2 *****//
+const
+  GL_PER_STAGE_CONSTANTS_NV* = 0x00008535
+
+proc glCombinerStageParameterfvNV*(stage: TGLenum, pname: TGLenum,
+                                   params: PGLfloat){.dynlib: dllname,
+    importc: "glCombinerStageParameterfvNV".}
+proc glGetCombinerStageParameterfvNV*(stage: TGLenum, pname: TGLenum,
+                                      params: PGLfloat){.dynlib: dllname,
+    importc: "glGetCombinerStageParameterfvNV".}
+  #***** GL_NV_texgen_emboss *****//
+const
+  GL_EMBOSS_MAP_NV* = 0x0000855F
+  GL_EMBOSS_LIGHT_NV* = 0x0000855D
+  GL_EMBOSS_CONSTANT_NV* = 0x0000855E
+  #***** GL_NV_texgen_reflection *****//
+
+const
+  GL_NORMAL_MAP_NV* = 0x00008511
+  GL_REFLECTION_MAP_NV* = 0x00008512
+  #***** GL_NV_texture_compression_vtc *****//
+  # GL_COMPRESSED_RGB_S3TC_DXT1_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT3_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT5_EXT  { already defined }
+  #***** GL_NV_texture_env_combine4 *****//
+
+const
+  GL_COMBINE4_NV* = 0x00008503
+  GL_SOURCE3_RGB_NV* = 0x00008583
+  GL_SOURCE3_ALPHA_NV* = 0x0000858B
+  GL_OPERAND3_RGB_NV* = 0x00008593
+  GL_OPERAND3_ALPHA_NV* = 0x0000859B
+  #***** GL_NV_texture_rectangle *****//
+
+const
+  GL_TEXTURE_RECTANGLE_NV* = 0x000084F5
+  GL_TEXTURE_BINDING_RECTANGLE_NV* = 0x000084F6
+  GL_PROXY_TEXTURE_RECTANGLE_NV* = 0x000084F7
+  GL_MAX_RECTANGLE_TEXTURE_SIZE_NV* = 0x000084F8
+  #***** GL_NV_texture_shader *****//
+
+const
+  GL_TEXTURE_SHADER_NV* = 0x000086DE
+  GL_RGBA_UNSIGNED_DOT_PRODUCT_MAPPING_NV* = 0x000086D9
+  GL_SHADER_OPERATION_NV* = 0x000086DF
+  GL_CULL_MODES_NV* = 0x000086E0
+  GL_OFFSET_TEXTURE_MATRIX_NV* = 0x000086E1
+  GL_OFFSET_TEXTURE_SCALE_NV* = 0x000086E2
+  GL_OFFSET_TEXTURE_BIAS_NV* = 0x000086E3
+  GL_PREVIOUS_TEXTURE_INPUT_NV* = 0x000086E4
+  GL_CONST_EYE_NV* = 0x000086E5
+  GL_SHADER_CONSISTENT_NV* = 0x000086DD
+  GL_PASS_THROUGH_NV* = 0x000086E6
+  GL_CULL_FRAGMENT_NV* = 0x000086E7
+  GL_OFFSET_TEXTURE_2D_NV* = 0x000086E8
+  GL_OFFSET_TEXTURE_RECTANGLE_NV* = 0x0000864C
+  GL_OFFSET_TEXTURE_RECTANGLE_SCALE_NV* = 0x0000864D
+  GL_DEPENDENT_AR_TEXTURE_2D_NV* = 0x000086E9
+  GL_DEPENDENT_GB_TEXTURE_2D_NV* = 0x000086EA
+  GL_DOT_PRODUCT_NV* = 0x000086EC
+  GL_DOT_PRODUCT_DEPTH_REPLACE_NV* = 0x000086ED
+  GL_DOT_PRODUCT_TEXTURE_2D_NV* = 0x000086EE
+  GL_DOT_PRODUCT_TEXTURE_RECTANGLE_NV* = 0x0000864E
+  GL_DOT_PRODUCT_TEXTURE_CUBE_MAP_NV* = 0x000086F0
+  GL_DOT_PRODUCT_DIFFUSE_CUBE_MAP_NV* = 0x000086F1
+  GL_DOT_PRODUCT_REFLECT_CUBE_MAP_NV* = 0x000086F2
+  GL_DOT_PRODUCT_CONST_EYE_REFLECT_CUBE_MAP_NV* = 0x000086F3
+  GL_HILO_NV* = 0x000086F4
+  GL_DSDT_NV* = 0x000086F5
+  GL_DSDT_MAG_NV* = 0x000086F6
+  GL_DSDT_MAG_VIB_NV* = 0x000086F7
+  GL_UNSIGNED_INT_S8_S8_8_8_NV* = 0x000086DA
+  GL_UNSIGNED_INT_8_8_S8_S8_REV_NV* = 0x000086DB
+  GL_SIGNED_RGBA_NV* = 0x000086FB
+  GL_SIGNED_RGBA8_NV* = 0x000086FC
+  GL_SIGNED_RGB_NV* = 0x000086FE
+  GL_SIGNED_RGB8_NV* = 0x000086FF
+  GL_SIGNED_LUMINANCE_NV* = 0x00008701
+  GL_SIGNED_LUMINANCE8_NV* = 0x00008702
+  GL_SIGNED_LUMINANCE_ALPHA_NV* = 0x00008703
+  GL_SIGNED_LUMINANCE8_ALPHA8_NV* = 0x00008704
+  GL_SIGNED_ALPHA_NV* = 0x00008705
+  GL_SIGNED_ALPHA8_NV* = 0x00008706
+  GL_SIGNED_INTENSITY_NV* = 0x00008707
+  GL_SIGNED_INTENSITY8_NV* = 0x00008708
+  GL_SIGNED_RGB_UNSIGNED_ALPHA_NV* = 0x0000870C
+  GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV* = 0x0000870D
+  GL_HILO16_NV* = 0x000086F8
+  GL_SIGNED_HILO_NV* = 0x000086F9
+  GL_SIGNED_HILO16_NV* = 0x000086FA
+  GL_DSDT8_NV* = 0x00008709
+  GL_DSDT8_MAG8_NV* = 0x0000870A
+  GL_DSDT_MAG_INTENSITY_NV* = 0x000086DC
+  GL_DSDT8_MAG8_INTENSITY8_NV* = 0x0000870B
+  GL_HI_SCALE_NV* = 0x0000870E
+  GL_LO_SCALE_NV* = 0x0000870F
+  GL_DS_SCALE_NV* = 0x00008710
+  GL_DT_SCALE_NV* = 0x00008711
+  GL_MAGNITUDE_SCALE_NV* = 0x00008712
+  GL_VIBRANCE_SCALE_NV* = 0x00008713
+  GL_HI_BIAS_NV* = 0x00008714
+  GL_LO_BIAS_NV* = 0x00008715
+  GL_DS_BIAS_NV* = 0x00008716
+  GL_DT_BIAS_NV* = 0x00008717
+  GL_MAGNITUDE_BIAS_NV* = 0x00008718
+  GL_VIBRANCE_BIAS_NV* = 0x00008719
+  GL_TEXTURE_BORDER_VALUES_NV* = 0x0000871A
+  GL_TEXTURE_HI_SIZE_NV* = 0x0000871B
+  GL_TEXTURE_LO_SIZE_NV* = 0x0000871C
+  GL_TEXTURE_DS_SIZE_NV* = 0x0000871D
+  GL_TEXTURE_DT_SIZE_NV* = 0x0000871E
+  GL_TEXTURE_MAG_SIZE_NV* = 0x0000871F
+  #***** GL_NV_texture_shader2 *****//
+
+const
+  GL_DOT_PRODUCT_TEXTURE_3D_NV* = 0x000086EF # GL_HILO_NV  { already defined }
+                                             # GL_DSDT_NV  { already defined }
+                                             # GL_DSDT_MAG_NV  { already defined }
+                                             # GL_DSDT_MAG_VIB_NV  { already defined }
+                                             # GL_UNSIGNED_INT_S8_S8_8_8_NV  { already defined }
+                                             # GL_UNSIGNED_INT_8_8_S8_S8_REV_NV  { already defined }
+                                             # GL_SIGNED_RGBA_NV  { already defined }
+                                             # GL_SIGNED_RGBA8_NV  { already defined }
+                                             # GL_SIGNED_RGB_NV  { already defined }
+                                             # GL_SIGNED_RGB8_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE8_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE_ALPHA_NV  { already defined }
+                                             # GL_SIGNED_LUMINANCE8_ALPHA8_NV  { already defined }
+                                             # GL_SIGNED_ALPHA_NV  { already defined }
+                                             # GL_SIGNED_ALPHA8_NV  { already defined }
+                                             # GL_SIGNED_INTENSITY_NV  { already defined }
+                                             # GL_SIGNED_INTENSITY8_NV  { already defined }
+                                             # GL_SIGNED_RGB_UNSIGNED_ALPHA_NV  { already defined }
+                                             # GL_SIGNED_RGB8_UNSIGNED_ALPHA8_NV  { already defined }
+                                             # GL_HILO16_NV  { already defined }
+                                             # GL_SIGNED_HILO_NV  { already defined }
+                                             # GL_SIGNED_HILO16_NV  { already defined }
+                                             # GL_DSDT8_NV  { already defined }
+                                             # GL_DSDT8_MAG8_NV  { already defined }
+                                             # GL_DSDT_MAG_INTENSITY_NV  { already defined }
+                                             # GL_DSDT8_MAG8_INTENSITY8_NV  { already defined }
+  #***** GL_NV_texture_shader3 *****//
+
+const
+  GL_OFFSET_PROJECTIVE_TEXTURE_2D_NV* = 0x00008850
+  GL_OFFSET_PROJECTIVE_TEXTURE_2D_SCALE_NV* = 0x00008851
+  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_NV* = 0x00008852
+  GL_OFFSET_PROJECTIVE_TEXTURE_RECTANGLE_SCALE_NV* = 0x00008853
+  GL_OFFSET_HILO_TEXTURE_2D_NV* = 0x00008854
+  GL_OFFSET_HILO_TEXTURE_RECTANGLE_NV* = 0x00008855
+  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_2D_NV* = 0x00008856
+  GL_OFFSET_HILO_PROJECTIVE_TEXTURE_RECTANGLE_NV* = 0x00008857
+  GL_DEPENDENT_HILO_TEXTURE_2D_NV* = 0x00008858
+  GL_DEPENDENT_RGB_TEXTURE_3D_NV* = 0x00008859
+  GL_DEPENDENT_RGB_TEXTURE_CUBE_MAP_NV* = 0x0000885A
+  GL_DOT_PRODUCT_PASS_THROUGH_NV* = 0x0000885B
+  GL_DOT_PRODUCT_TEXTURE_1D_NV* = 0x0000885C
+  GL_DOT_PRODUCT_AFFINE_DEPTH_REPLACE_NV* = 0x0000885D
+  GL_HILO8_NV* = 0x0000885E
+  GL_SIGNED_HILO8_NV* = 0x0000885F
+  GL_FORCE_BLUE_TO_ONE_NV* = 0x00008860
+  #***** GL_NV_vertex_array_range *****//
+
+const
+  constGL_VERTEX_ARRAY_RANGE_NV* = 0x0000851D
+  GL_VERTEX_ARRAY_RANGE_LENGTH_NV* = 0x0000851E
+  GL_VERTEX_ARRAY_RANGE_VALID_NV* = 0x0000851F
+  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_NV* = 0x00008520
+  GL_VERTEX_ARRAY_RANGE_POINTER_NV* = 0x00008521
+
+proc glVertexArrayRangeNV*(len: TGLsizei, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glVertexArrayRangeNV".}
+proc glFlushVertexArrayRangeNV*(){.dynlib: dllname,
+                                   importc: "glFlushVertexArrayRangeNV".}
+  #***** GL_NV_vertex_array_range2 *****//
+const
+  GL_VERTEX_ARRAY_RANGE_WITHOUT_FLUSH_NV* = 0x00008533
+  #***** GL_NV_vertex_program *****//
+
+const
+  GL_VERTEX_PROGRAM_NV* = 0x00008620
+  GL_VERTEX_PROGRAM_POINT_SIZE_NV* = 0x00008642
+  GL_VERTEX_PROGRAM_TWO_SIDE_NV* = 0x00008643
+  GL_VERTEX_STATE_PROGRAM_NV* = 0x00008621
+  GL_ATTRIB_ARRAY_SIZE_NV* = 0x00008623
+  GL_ATTRIB_ARRAY_STRIDE_NV* = 0x00008624
+  GL_ATTRIB_ARRAY_TYPE_NV* = 0x00008625
+  GL_CURRENT_ATTRIB_NV* = 0x00008626
+  GL_PROGRAM_PARAMETER_NV* = 0x00008644
+  GL_ATTRIB_ARRAY_POINTER_NV* = 0x00008645
+  GL_PROGRAM_TARGET_NV* = 0x00008646
+  GL_PROGRAM_LENGTH_NV* = 0x00008627
+  GL_PROGRAM_RESIDENT_NV* = 0x00008647
+  GL_PROGRAM_STRING_NV* = 0x00008628
+  constGL_TRACK_MATRIX_NV* = 0x00008648
+  GL_TRACK_MATRIX_TRANSFORM_NV* = 0x00008649
+  GL_MAX_TRACK_MATRIX_STACK_DEPTH_NV* = 0x0000862E
+  GL_MAX_TRACK_MATRICES_NV* = 0x0000862F
+  GL_CURRENT_MATRIX_STACK_DEPTH_NV* = 0x00008640
+  GL_CURRENT_MATRIX_NV* = 0x00008641
+  GL_VERTEX_PROGRAM_BINDING_NV* = 0x0000864A
+  GL_PROGRAM_ERROR_POSITION_NV* = 0x0000864B
+  GL_MODELVIEW_PROJECTION_NV* = 0x00008629
+  GL_MATRIX0_NV* = 0x00008630
+  GL_MATRIX1_NV* = 0x00008631
+  GL_MATRIX2_NV* = 0x00008632
+  GL_MATRIX3_NV* = 0x00008633
+  GL_MATRIX4_NV* = 0x00008634
+  GL_MATRIX5_NV* = 0x00008635
+  GL_MATRIX6_NV* = 0x00008636
+  GL_MATRIX7_NV* = 0x00008637
+  GL_IDENTITY_NV* = 0x0000862A
+  GL_INVERSE_NV* = 0x0000862B
+  GL_TRANSPOSE_NV* = 0x0000862C
+  GL_INVERSE_TRANSPOSE_NV* = 0x0000862D
+  GL_VERTEX_ATTRIB_ARRAY0_NV* = 0x00008650
+  GL_VERTEX_ATTRIB_ARRAY1_NV* = 0x00008651
+  GL_VERTEX_ATTRIB_ARRAY2_NV* = 0x00008652
+  GL_VERTEX_ATTRIB_ARRAY3_NV* = 0x00008653
+  GL_VERTEX_ATTRIB_ARRAY4_NV* = 0x00008654
+  GL_VERTEX_ATTRIB_ARRAY5_NV* = 0x00008655
+  GL_VERTEX_ATTRIB_ARRAY6_NV* = 0x00008656
+  GL_VERTEX_ATTRIB_ARRAY7_NV* = 0x00008657
+  GL_VERTEX_ATTRIB_ARRAY8_NV* = 0x00008658
+  GL_VERTEX_ATTRIB_ARRAY9_NV* = 0x00008659
+  GL_VERTEX_ATTRIB_ARRAY10_NV* = 0x0000865A
+  GL_VERTEX_ATTRIB_ARRAY11_NV* = 0x0000865B
+  GL_VERTEX_ATTRIB_ARRAY12_NV* = 0x0000865C
+  GL_VERTEX_ATTRIB_ARRAY13_NV* = 0x0000865D
+  GL_VERTEX_ATTRIB_ARRAY14_NV* = 0x0000865E
+  GL_VERTEX_ATTRIB_ARRAY15_NV* = 0x0000865F
+  GL_MAP1_VERTEX_ATTRIB0_4_NV* = 0x00008660
+  GL_MAP1_VERTEX_ATTRIB1_4_NV* = 0x00008661
+  GL_MAP1_VERTEX_ATTRIB2_4_NV* = 0x00008662
+  GL_MAP1_VERTEX_ATTRIB3_4_NV* = 0x00008663
+  GL_MAP1_VERTEX_ATTRIB4_4_NV* = 0x00008664
+  GL_MAP1_VERTEX_ATTRIB5_4_NV* = 0x00008665
+  GL_MAP1_VERTEX_ATTRIB6_4_NV* = 0x00008666
+  GL_MAP1_VERTEX_ATTRIB7_4_NV* = 0x00008667
+  GL_MAP1_VERTEX_ATTRIB8_4_NV* = 0x00008668
+  GL_MAP1_VERTEX_ATTRIB9_4_NV* = 0x00008669
+  GL_MAP1_VERTEX_ATTRIB10_4_NV* = 0x0000866A
+  GL_MAP1_VERTEX_ATTRIB11_4_NV* = 0x0000866B
+  GL_MAP1_VERTEX_ATTRIB12_4_NV* = 0x0000866C
+  GL_MAP1_VERTEX_ATTRIB13_4_NV* = 0x0000866D
+  GL_MAP1_VERTEX_ATTRIB14_4_NV* = 0x0000866E
+  GL_MAP1_VERTEX_ATTRIB15_4_NV* = 0x0000866F
+  GL_MAP2_VERTEX_ATTRIB0_4_NV* = 0x00008670
+  GL_MAP2_VERTEX_ATTRIB1_4_NV* = 0x00008671
+  GL_MAP2_VERTEX_ATTRIB2_4_NV* = 0x00008672
+  GL_MAP2_VERTEX_ATTRIB3_4_NV* = 0x00008673
+  GL_MAP2_VERTEX_ATTRIB4_4_NV* = 0x00008674
+  GL_MAP2_VERTEX_ATTRIB5_4_NV* = 0x00008675
+  GL_MAP2_VERTEX_ATTRIB6_4_NV* = 0x00008676
+  GL_MAP2_VERTEX_ATTRIB7_4_NV* = 0x00008677
+  GL_MAP2_VERTEX_ATTRIB8_4_NV* = 0x00008678
+  GL_MAP2_VERTEX_ATTRIB9_4_NV* = 0x00008679
+  GL_MAP2_VERTEX_ATTRIB10_4_NV* = 0x0000867A
+  GL_MAP2_VERTEX_ATTRIB11_4_NV* = 0x0000867B
+  GL_MAP2_VERTEX_ATTRIB12_4_NV* = 0x0000867C
+  GL_MAP2_VERTEX_ATTRIB13_4_NV* = 0x0000867D
+  GL_MAP2_VERTEX_ATTRIB14_4_NV* = 0x0000867E
+  GL_MAP2_VERTEX_ATTRIB15_4_NV* = 0x0000867F
+
+proc glBindProgramNV*(target: TGLenum, id: TGLuint){.dynlib: dllname,
+    importc: "glBindProgramNV".}
+proc glDeleteProgramsNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glDeleteProgramsNV".}
+proc glExecuteProgramNV*(target: TGLenum, id: TGLuint, params: PGLfloat){.
+    dynlib: dllname, importc: "glExecuteProgramNV".}
+proc glGenProgramsNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glGenProgramsNV".}
+proc glAreProgramsResidentNV*(n: TGLsizei, ids: PGLuint, residences: PGLboolean): TGLboolean{.
+    dynlib: dllname, importc: "glAreProgramsResidentNV".}
+proc glRequestResidentProgramsNV*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glRequestResidentProgramsNV".}
+proc glGetProgramParameterfvNV*(target: TGLenum, index: TGLuint, pname: TGLenum,
+                                params: PGLfloat){.dynlib: dllname,
+    importc: "glGetProgramParameterfvNV".}
+proc glGetProgramParameterdvNV*(target: TGLenum, index: TGLuint, pname: TGLenum,
+                                params: PGLdouble){.dynlib: dllname,
+    importc: "glGetProgramParameterdvNV".}
+proc glGetProgramivNV*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetProgramivNV".}
+proc glGetProgramStringNV*(id: TGLuint, pname: TGLenum, theProgram: PGLubyte){.
+    dynlib: dllname, importc: "glGetProgramStringNV".}
+proc glGetTrackMatrixivNV*(target: TGLenum, address: TGLuint, pname: TGLenum,
+                           params: PGLint){.dynlib: dllname,
+    importc: "glGetTrackMatrixivNV".}
+proc glGetVertexAttribdvNV*(index: TGLuint, pname: TGLenum, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetVertexAttribdvNV".}
+proc glGetVertexAttribfvNV*(index: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVertexAttribfvNV".}
+proc glGetVertexAttribivNV*(index: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVertexAttribivNV".}
+proc glGetVertexAttribPointervNV*(index: TGLuint, pname: TGLenum,
+                                  pointer: PGLvoid){.dynlib: dllname,
+    importc: "glGetVertexAttribPointervNV".}
+proc glIsProgramNV*(id: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsProgramNV".}
+proc glLoadProgramNV*(target: TGLenum, id: TGLuint, length: TGLsizei,
+                      theProgram: PGLubyte){.dynlib: dllname,
+    importc: "glLoadProgramNV".}
+proc glProgramParameter4fNV*(target: TGLenum, index: TGLuint, x: TGLfloat,
+                             y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glProgramParameter4fNV".}
+proc glProgramParameter4fvNV*(target: TGLenum, index: TGLuint, params: PGLfloat){.
+    dynlib: dllname, importc: "glProgramParameter4fvNV".}
+proc glProgramParameters4dvNV*(target: TGLenum, index: TGLuint, num: TGLuint,
+                               params: PGLdouble){.dynlib: dllname,
+    importc: "glProgramParameters4dvNV".}
+proc glProgramParameters4fvNV*(target: TGLenum, index: TGLuint, num: TGLuint,
+                               params: PGLfloat){.dynlib: dllname,
+    importc: "glProgramParameters4fvNV".}
+proc glTrackMatrixNV*(target: TGLenum, address: TGLuint, matrix: TGLenum,
+                      transform: TGLenum){.dynlib: dllname,
+    importc: "glTrackMatrixNV".}
+proc glVertexAttribPointerNV*(index: TGLuint, size: TGLint, thetype: TGLenum,
+                              stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glVertexAttribPointerNV".}
+proc glVertexAttrib1sNV*(index: TGLuint, x: TGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib1sNV".}
+proc glVertexAttrib1fNV*(index: TGLuint, x: TGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib1fNV".}
+proc glVertexAttrib1dNV*(index: TGLuint, x: TGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib1dNV".}
+proc glVertexAttrib2sNV*(index: TGLuint, x: TGLshort, y: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib2sNV".}
+proc glVertexAttrib2fNV*(index: TGLuint, x: TGLfloat, y: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib2fNV".}
+proc glVertexAttrib2dNV*(index: TGLuint, x: TGLdouble, y: TGLdouble){.
+    dynlib: dllname, importc: "glVertexAttrib2dNV".}
+proc glVertexAttrib3sNV*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort){.
+    dynlib: dllname, importc: "glVertexAttrib3sNV".}
+proc glVertexAttrib3fNV*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glVertexAttrib3fNV".}
+proc glVertexAttrib3dNV*(index: TGLuint, x: TGLdouble, y: TGLdouble,
+                         z: TGLdouble){.dynlib: dllname,
+                                        importc: "glVertexAttrib3dNV".}
+proc glVertexAttrib4sNV*(index: TGLuint, x: TGLshort, y: TGLshort, z: TGLshort,
+                         w: TGLshort){.dynlib: dllname,
+                                       importc: "glVertexAttrib4sNV".}
+proc glVertexAttrib4fNV*(index: TGLuint, x: TGLfloat, y: TGLfloat, z: TGLfloat,
+                         w: TGLfloat){.dynlib: dllname,
+                                       importc: "glVertexAttrib4fNV".}
+proc glVertexAttrib4dNV*(index: TGLuint, x: TGLdouble, y: TGLdouble,
+                         z: TGLdouble, w: TGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib4dNV".}
+proc glVertexAttrib4ubNV*(index: TGLuint, x: TGLubyte, y: TGLubyte, z: TGLubyte,
+                          w: TGLubyte){.dynlib: dllname,
+                                        importc: "glVertexAttrib4ubNV".}
+proc glVertexAttrib1svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib1svNV".}
+proc glVertexAttrib1fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib1fvNV".}
+proc glVertexAttrib1dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib1dvNV".}
+proc glVertexAttrib2svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib2svNV".}
+proc glVertexAttrib2fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib2fvNV".}
+proc glVertexAttrib2dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib2dvNV".}
+proc glVertexAttrib3svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib3svNV".}
+proc glVertexAttrib3fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib3fvNV".}
+proc glVertexAttrib3dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib3dvNV".}
+proc glVertexAttrib4svNV*(index: TGLuint, v: PGLshort){.dynlib: dllname,
+    importc: "glVertexAttrib4svNV".}
+proc glVertexAttrib4fvNV*(index: TGLuint, v: PGLfloat){.dynlib: dllname,
+    importc: "glVertexAttrib4fvNV".}
+proc glVertexAttrib4dvNV*(index: TGLuint, v: PGLdouble){.dynlib: dllname,
+    importc: "glVertexAttrib4dvNV".}
+proc glVertexAttrib4ubvNV*(index: TGLuint, v: PGLubyte){.dynlib: dllname,
+    importc: "glVertexAttrib4ubvNV".}
+proc glVertexAttribs1svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs1svNV".}
+proc glVertexAttribs1fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs1fvNV".}
+proc glVertexAttribs1dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs1dvNV".}
+proc glVertexAttribs2svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs2svNV".}
+proc glVertexAttribs2fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs2fvNV".}
+proc glVertexAttribs2dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs2dvNV".}
+proc glVertexAttribs3svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs3svNV".}
+proc glVertexAttribs3fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs3fvNV".}
+proc glVertexAttribs3dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs3dvNV".}
+proc glVertexAttribs4svNV*(index: TGLuint, n: TGLsizei, v: PGLshort){.
+    dynlib: dllname, importc: "glVertexAttribs4svNV".}
+proc glVertexAttribs4fvNV*(index: TGLuint, n: TGLsizei, v: PGLfloat){.
+    dynlib: dllname, importc: "glVertexAttribs4fvNV".}
+proc glVertexAttribs4dvNV*(index: TGLuint, n: TGLsizei, v: PGLdouble){.
+    dynlib: dllname, importc: "glVertexAttribs4dvNV".}
+proc glVertexAttribs4ubvNV*(index: TGLuint, n: TGLsizei, v: PGLubyte){.
+    dynlib: dllname, importc: "glVertexAttribs4ubvNV".}
+  #***** GL_NV_vertex_program1_1 *****//
+  #***** GL_ATI_element_array *****//
+const
+  GL_ELEMENT_ARRAY_ATI* = 0x00008768
+  GL_ELEMENT_ARRAY_TYPE_ATI* = 0x00008769
+  GL_ELEMENT_ARRAY_POINTER_ATI* = 0x0000876A
+
+proc glElementPointerATI*(thetype: TGLenum, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glElementPointerATI".}
+proc glDrawElementArrayATI*(mode: TGLenum, count: TGLsizei){.dynlib: dllname,
+    importc: "glDrawElementArrayATI".}
+proc glDrawRangeElementArrayATI*(mode: TGLenum, start: TGLuint, theend: TGLuint,
+                                 count: TGLsizei){.dynlib: dllname,
+    importc: "glDrawRangeElementArrayATI".}
+  #***** GL_ATI_envmap_bumpmap *****//
+const
+  GL_BUMP_ROT_MATRIX_ATI* = 0x00008775
+  GL_BUMP_ROT_MATRIX_SIZE_ATI* = 0x00008776
+  GL_BUMP_NUM_TEX_UNITS_ATI* = 0x00008777
+  GL_BUMP_TEX_UNITS_ATI* = 0x00008778
+  GL_DUDV_ATI* = 0x00008779
+  GL_DU8DV8_ATI* = 0x0000877A
+  GL_BUMP_ENVMAP_ATI* = 0x0000877B
+  GL_BUMP_TARGET_ATI* = 0x0000877C
+
+proc glTexBumpParameterivATI*(pname: TGLenum, param: PGLint){.dynlib: dllname,
+    importc: "glTexBumpParameterivATI".}
+proc glTexBumpParameterfvATI*(pname: TGLenum, param: PGLfloat){.dynlib: dllname,
+    importc: "glTexBumpParameterfvATI".}
+proc glGetTexBumpParameterivATI*(pname: TGLenum, param: PGLint){.
+    dynlib: dllname, importc: "glGetTexBumpParameterivATI".}
+proc glGetTexBumpParameterfvATI*(pname: TGLenum, param: PGLfloat){.
+    dynlib: dllname, importc: "glGetTexBumpParameterfvATI".}
+  #***** GL_ATI_fragment_shader *****//
+const
+  GL_FRAGMENT_SHADER_ATI* = 0x00008920
+  GL_REG_0_ATI* = 0x00008921
+  GL_REG_1_ATI* = 0x00008922
+  GL_REG_2_ATI* = 0x00008923
+  GL_REG_3_ATI* = 0x00008924
+  GL_REG_4_ATI* = 0x00008925
+  GL_REG_5_ATI* = 0x00008926
+  GL_CON_0_ATI* = 0x00008941
+  GL_CON_1_ATI* = 0x00008942
+  GL_CON_2_ATI* = 0x00008943
+  GL_CON_3_ATI* = 0x00008944
+  GL_CON_4_ATI* = 0x00008945
+  GL_CON_5_ATI* = 0x00008946
+  GL_CON_6_ATI* = 0x00008947
+  GL_CON_7_ATI* = 0x00008948
+  GL_MOV_ATI* = 0x00008961
+  GL_ADD_ATI* = 0x00008963
+  GL_MUL_ATI* = 0x00008964
+  GL_SUB_ATI* = 0x00008965
+  GL_DOT3_ATI* = 0x00008966
+  GL_DOT4_ATI* = 0x00008967
+  GL_MAD_ATI* = 0x00008968
+  GL_LERP_ATI* = 0x00008969
+  GL_CND_ATI* = 0x0000896A
+  GL_CND0_ATI* = 0x0000896B
+  GL_DOT2_ADD_ATI* = 0x0000896C
+  GL_SECONDARY_INTERPOLATOR_ATI* = 0x0000896D
+  GL_SWIZZLE_STR_ATI* = 0x00008976
+  GL_SWIZZLE_STQ_ATI* = 0x00008977
+  GL_SWIZZLE_STR_DR_ATI* = 0x00008978
+  GL_SWIZZLE_STQ_DQ_ATI* = 0x00008979
+  GL_RED_BIT_ATI* = 0x00000001
+  GL_GREEN_BIT_ATI* = 0x00000002
+  GL_BLUE_BIT_ATI* = 0x00000004
+  GL_2X_BIT_ATI* = 0x00000001
+  GL_4X_BIT_ATI* = 0x00000002
+  GL_8X_BIT_ATI* = 0x00000004
+  GL_HALF_BIT_ATI* = 0x00000008
+  GL_QUARTER_BIT_ATI* = 0x00000010
+  GL_EIGHTH_BIT_ATI* = 0x00000020
+  GL_SATURATE_BIT_ATI* = 0x00000040 # GL_2X_BIT_ATI  { already defined }
+  GL_COMP_BIT_ATI* = 0x00000002
+  GL_NEGATE_BIT_ATI* = 0x00000004
+  GL_BIAS_BIT_ATI* = 0x00000008
+
+proc glGenFragmentShadersATI*(range: TGLuint): TGLuint{.dynlib: dllname,
+    importc: "glGenFragmentShadersATI".}
+proc glBindFragmentShaderATI*(id: TGLuint){.dynlib: dllname,
+    importc: "glBindFragmentShaderATI".}
+proc glDeleteFragmentShaderATI*(id: TGLuint){.dynlib: dllname,
+    importc: "glDeleteFragmentShaderATI".}
+proc glBeginFragmentShaderATI*(){.dynlib: dllname,
+                                  importc: "glBeginFragmentShaderATI".}
+proc glEndFragmentShaderATI*(){.dynlib: dllname,
+                                importc: "glEndFragmentShaderATI".}
+proc glPassTexCoordATI*(dst: TGLuint, coord: TGLuint, swizzle: TGLenum){.
+    dynlib: dllname, importc: "glPassTexCoordATI".}
+proc glSampleMapATI*(dst: TGLuint, interp: TGLuint, swizzle: TGLenum){.
+    dynlib: dllname, importc: "glSampleMapATI".}
+proc glColorFragmentOp1ATI*(op: TGLenum, dst: TGLuint, dstMask: TGLuint,
+                            dstMod: TGLuint, arg1: TGLuint, arg1Rep: TGLuint,
+                            arg1Mod: TGLuint){.dynlib: dllname,
+    importc: "glColorFragmentOp1ATI".}
+proc glColorFragmentOp2ATI*(op: TGLenum, dst: TGLuint, dstMask: TGLuint,
+                            dstMod: TGLuint, arg1: TGLuint, arg1Rep: TGLuint,
+                            arg1Mod: TGLuint, arg2: TGLuint, arg2Rep: TGLuint,
+                            arg2Mod: TGLuint){.dynlib: dllname,
+    importc: "glColorFragmentOp2ATI".}
+proc glColorFragmentOp3ATI*(op: TGLenum, dst: TGLuint, dstMask: TGLuint,
+                            dstMod: TGLuint, arg1: TGLuint, arg1Rep: TGLuint,
+                            arg1Mod: TGLuint, arg2: TGLuint, arg2Rep: TGLuint,
+                            arg2Mod: TGLuint, arg3: TGLuint, arg3Rep: TGLuint,
+                            arg3Mod: TGLuint){.dynlib: dllname,
+    importc: "glColorFragmentOp3ATI".}
+proc glAlphaFragmentOp1ATI*(op: TGLenum, dst: TGLuint, dstMod: TGLuint,
+                            arg1: TGLuint, arg1Rep: TGLuint, arg1Mod: TGLuint){.
+    dynlib: dllname, importc: "glAlphaFragmentOp1ATI".}
+proc glAlphaFragmentOp2ATI*(op: TGLenum, dst: TGLuint, dstMod: TGLuint,
+                            arg1: TGLuint, arg1Rep: TGLuint, arg1Mod: TGLuint,
+                            arg2: TGLuint, arg2Rep: TGLuint, arg2Mod: TGLuint){.
+    dynlib: dllname, importc: "glAlphaFragmentOp2ATI".}
+proc glAlphaFragmentOp3ATI*(op: TGLenum, dst: TGLuint, dstMod: TGLuint,
+                            arg1: TGLuint, arg1Rep: TGLuint, arg1Mod: TGLuint,
+                            arg2: TGLuint, arg2Rep: TGLuint, arg2Mod: TGLuint,
+                            arg3: TGLuint, arg3Rep: TGLuint, arg3Mod: TGLuint){.
+    dynlib: dllname, importc: "glAlphaFragmentOp3ATI".}
+proc glSetFragmentShaderConstantATI*(dst: TGLuint, value: PGLfloat){.
+    dynlib: dllname, importc: "glSetFragmentShaderConstantATI".}
+  #***** GL_ATI_pn_triangles *****//
+const
+  GL_PN_TRIANGLES_ATI* = 0x000087F0
+  GL_MAX_PN_TRIANGLES_TESSELATION_LEVEL_ATI* = 0x000087F1
+  GL_PN_TRIANGLES_POINT_MODE_ATI* = 0x000087F2
+  GL_PN_TRIANGLES_NORMAL_MODE_ATI* = 0x000087F3
+  GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI* = 0x000087F4
+  GL_PN_TRIANGLES_POINT_MODE_LINEAR_ATI* = 0x000087F5
+  GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI* = 0x000087F6
+  GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI* = 0x000087F7
+  GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI* = 0x000087F8
+
+proc glPNTrianglesiATI*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glPNTrianglesiATI".}
+proc glPNTrianglesfATI*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glPNTrianglesfATI".}
+  #***** GL_ATI_texture_mirror_once *****//
+const
+  GL_MIRROR_CLAMP_ATI* = 0x00008742
+  GL_MIRROR_CLAMP_TO_EDGE_ATI* = 0x00008743
+  #***** GL_ATI_vertex_array_object *****//
+
+const
+  GL_STATIC_ATI* = 0x00008760
+  GL_DYNAMIC_ATI* = 0x00008761
+  GL_PRESERVE_ATI* = 0x00008762
+  GL_DISCARD_ATI* = 0x00008763
+  GL_OBJECT_BUFFER_SIZE_ATI* = 0x00008764
+  GL_OBJECT_BUFFER_USAGE_ATI* = 0x00008765
+  GL_ARRAY_OBJECT_BUFFER_ATI* = 0x00008766
+  GL_ARRAY_OBJECT_OFFSET_ATI* = 0x00008767
+
+proc glNewObjectBufferATI*(size: TGLsizei, pointer: PGLvoid, usage: TGLenum): TGLuint{.
+    dynlib: dllname, importc: "glNewObjectBufferATI".}
+proc glIsObjectBufferATI*(buffer: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsObjectBufferATI".}
+proc glUpdateObjectBufferATI*(buffer: TGLuint, offset: TGLuint, size: TGLsizei,
+                              pointer: PGLvoid, preserve: TGLenum){.
+    dynlib: dllname, importc: "glUpdateObjectBufferATI".}
+proc glGetObjectBufferfvATI*(buffer: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetObjectBufferfvATI".}
+proc glGetObjectBufferivATI*(buffer: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetObjectBufferivATI".}
+proc glDeleteObjectBufferATI*(buffer: TGLuint){.dynlib: dllname,
+    importc: "glDeleteObjectBufferATI".}
+proc glArrayObjectATI*(thearray: TGLenum, size: TGLint, thetype: TGLenum,
+                       stride: TGLsizei, buffer: TGLuint, offset: TGLuint){.
+    dynlib: dllname, importc: "glArrayObjectATI".}
+proc glGetArrayObjectfvATI*(thearray: TGLenum, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetArrayObjectfvATI".}
+proc glGetArrayObjectivATI*(thearray: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetArrayObjectivATI".}
+proc glVariantArrayObjectATI*(id: TGLuint, thetype: TGLenum, stride: TGLsizei,
+                              buffer: TGLuint, offset: TGLuint){.
+    dynlib: dllname, importc: "glVariantArrayObjectATI".}
+proc glGetVariantArrayObjectfvATI*(id: TGLuint, pname: TGLenum, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetVariantArrayObjectfvATI".}
+proc glGetVariantArrayObjectivATI*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetVariantArrayObjectivATI".}
+  #***** GL_ATI_vertex_streams *****//
+const
+  GL_MAX_VERTEX_STREAMS_ATI* = 0x0000876B
+  GL_VERTEX_STREAM0_ATI* = 0x0000876C
+  GL_VERTEX_STREAM1_ATI* = 0x0000876D
+  GL_VERTEX_STREAM2_ATI* = 0x0000876E
+  GL_VERTEX_STREAM3_ATI* = 0x0000876F
+  GL_VERTEX_STREAM4_ATI* = 0x00008770
+  GL_VERTEX_STREAM5_ATI* = 0x00008771
+  GL_VERTEX_STREAM6_ATI* = 0x00008772
+  GL_VERTEX_STREAM7_ATI* = 0x00008773
+  GL_VERTEX_SOURCE_ATI* = 0x00008774
+
+proc glVertexStream1s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream1s".}
+proc glVertexStream1i*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream1i".}
+proc glVertexStream1f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream1f".}
+proc glVertexStream1d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream1d".}
+proc glVertexStream1sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream1sv".}
+proc glVertexStream1iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream1iv".}
+proc glVertexStream1fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream1fv".}
+proc glVertexStream1dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream1dv".}
+proc glVertexStream2s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream2s".}
+proc glVertexStream2i*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream2i".}
+proc glVertexStream2f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream2f".}
+proc glVertexStream2d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream2d".}
+proc glVertexStream2sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream2sv".}
+proc glVertexStream2iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream2iv".}
+proc glVertexStream2fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream2fv".}
+proc glVertexStream2dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream2dv".}
+proc glVertexStream3s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream3s".}
+proc glVertexStream3i*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream3i".}
+proc glVertexStream3f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream3f".}
+proc glVertexStream3d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream3d".}
+proc glVertexStream3sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream3sv".}
+proc glVertexStream3iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream3iv".}
+proc glVertexStream3fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream3fv".}
+proc glVertexStream3dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream3dv".}
+proc glVertexStream4s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream4s".}
+proc glVertexStream4i*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream4i".}
+proc glVertexStream4f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream4f".}
+proc glVertexStream4d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream4d".}
+proc glVertexStream4sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glVertexStream4sv".}
+proc glVertexStream4iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glVertexStream4iv".}
+proc glVertexStream4fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glVertexStream4fv".}
+proc glVertexStream4dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glVertexStream4dv".}
+proc glNormalStream3b*(stream: TGLenum, coords: TGLByte){.dynlib: dllname,
+    importc: "glNormalStream3b".}
+proc glNormalStream3s*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glNormalStream3s".}
+proc glNormalStream3i*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glNormalStream3i".}
+proc glNormalStream3f*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glNormalStream3f".}
+proc glNormalStream3d*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glNormalStream3d".}
+proc glNormalStream3bv*(stream: TGLenum, coords: TGLByte){.dynlib: dllname,
+    importc: "glNormalStream3bv".}
+proc glNormalStream3sv*(stream: TGLenum, coords: TGLshort){.dynlib: dllname,
+    importc: "glNormalStream3sv".}
+proc glNormalStream3iv*(stream: TGLenum, coords: TGLint){.dynlib: dllname,
+    importc: "glNormalStream3iv".}
+proc glNormalStream3fv*(stream: TGLenum, coords: TGLfloat){.dynlib: dllname,
+    importc: "glNormalStream3fv".}
+proc glNormalStream3dv*(stream: TGLenum, coords: TGLdouble){.dynlib: dllname,
+    importc: "glNormalStream3dv".}
+proc glClientActiveVertexStream*(stream: TGLenum){.dynlib: dllname,
+    importc: "glClientActiveVertexStream".}
+proc glVertexBlendEnvi*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glVertexBlendEnvi".}
+proc glVertexBlendEnvf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glVertexBlendEnvf".}
+  #***** GL_3DFX_texture_compression_FXT1 *****//
+const
+  GL_COMPRESSED_RGB_FXT1_3DFX* = 0x000086B0
+  GL_COMPRESSED_RGBA_FXT1_3DFX* = 0x000086B1
+  #***** GL_IBM_cull_vertex *****//
+
+const
+  GL_CULL_VERTEX_IBM* = 0x0001928A
+  #***** GL_IBM_multimode_draw_arrays *****//
+
+proc glMultiModeDrawArraysIBM*(mode: PGLenum, first: PGLint, count: PGLsizei,
+                               primcount: TGLsizei, modestride: TGLint){.
+    dynlib: dllname, importc: "glMultiModeDrawArraysIBM".}
+proc glMultiModeDrawElementsIBM*(mode: PGLenum, count: PGLsizei,
+                                 thetype: TGLenum, indices: PGLvoid,
+                                 primcount: TGLsizei, modestride: TGLint){.
+    dynlib: dllname, importc: "glMultiModeDrawElementsIBM".}
+  #***** GL_IBM_raster_pos_clip *****//
+const
+  GL_RASTER_POSITION_UNCLIPPED_IBM* = 0x00019262
+  #***** GL_IBM_texture_mirrored_repeat *****//
+
+const
+  GL_MIRRORED_REPEAT_IBM* = 0x00008370
+  #***** GL_IBM_vertex_array_lists *****//
+
+const
+  GL_VERTEX_ARRAY_LIST_IBM* = 0x0001929E
+  GL_NORMAL_ARRAY_LIST_IBM* = 0x0001929F
+  GL_COLOR_ARRAY_LIST_IBM* = 0x000192A0
+  GL_INDEX_ARRAY_LIST_IBM* = 0x000192A1
+  GL_TEXTURE_COORD_ARRAY_LIST_IBM* = 0x000192A2
+  GL_EDGE_FLAG_ARRAY_LIST_IBM* = 0x000192A3
+  GL_FOG_COORDINATE_ARRAY_LIST_IBM* = 0x000192A4
+  GL_SECONDARY_COLOR_ARRAY_LIST_IBM* = 0x000192A5
+  GL_VERTEX_ARRAY_LIST_STRIDE_IBM* = 0x000192A8
+  GL_NORMAL_ARRAY_LIST_STRIDE_IBM* = 0x000192A9
+  GL_COLOR_ARRAY_LIST_STRIDE_IBM* = 0x000192AA
+  GL_INDEX_ARRAY_LIST_STRIDE_IBM* = 0x000192AB
+  GL_TEXTURE_COORD_ARRAY_LIST_STRIDE_IBM* = 0x000192AC
+  GL_EDGE_FLAG_ARRAY_LIST_STRIDE_IBM* = 0x000192AD
+  GL_FOG_COORDINATE_ARRAY_LIST_STRIDE_IBM* = 0x000192AE
+  GL_SECONDARY_COLOR_ARRAY_LIST_STRIDE_IBM* = 0x000192AF
+
+proc glColorPointerListIBM*(size: TGLint, thetype: TGLenum, stride: TGLint,
+                            pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glColorPointerListIBM".}
+proc glSecondaryColorPointerListIBM*(size: TGLint, thetype: TGLenum,
+                                     stride: TGLint, pointer: PGLvoid,
+                                     ptrstride: TGLint){.dynlib: dllname,
+    importc: "glSecondaryColorPointerListIBM".}
+proc glEdgeFlagPointerListIBM*(stride: TGLint, pointer: PGLboolean,
+                               ptrstride: TGLint){.dynlib: dllname,
+    importc: "glEdgeFlagPointerListIBM".}
+proc glFogCoordPointerListIBM*(thetype: TGLenum, stride: TGLint,
+                               pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glFogCoordPointerListIBM".}
+proc glNormalPointerListIBM*(thetype: TGLenum, stride: TGLint, pointer: PGLvoid,
+                             ptrstride: TGLint){.dynlib: dllname,
+    importc: "glNormalPointerListIBM".}
+proc glTexCoordPointerListIBM*(size: TGLint, thetype: TGLenum, stride: TGLint,
+                               pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glTexCoordPointerListIBM".}
+proc glVertexPointerListIBM*(size: TGLint, thetype: TGLenum, stride: TGLint,
+                             pointer: PGLvoid, ptrstride: TGLint){.
+    dynlib: dllname, importc: "glVertexPointerListIBM".}
+  #***** GL_MESA_resize_buffers *****//
+proc glResizeBuffersMESA*(){.dynlib: dllname, importc: "glResizeBuffersMESA".}
+  #***** GL_MESA_window_pos *****//
+proc glWindowPos2dMESA*(x: TGLdouble, y: TGLdouble){.dynlib: dllname,
+    importc: "glWindowPos2dMESA".}
+proc glWindowPos2fMESA*(x: TGLfloat, y: TGLfloat){.dynlib: dllname,
+    importc: "glWindowPos2fMESA".}
+proc glWindowPos2iMESA*(x: TGLint, y: TGLint){.dynlib: dllname,
+    importc: "glWindowPos2iMESA".}
+proc glWindowPos2sMESA*(x: TGLshort, y: TGLshort){.dynlib: dllname,
+    importc: "glWindowPos2sMESA".}
+proc glWindowPos2ivMESA*(p: PGLint){.dynlib: dllname,
+                                     importc: "glWindowPos2ivMESA".}
+proc glWindowPos2svMESA*(p: PGLshort){.dynlib: dllname,
+                                       importc: "glWindowPos2svMESA".}
+proc glWindowPos2fvMESA*(p: PGLfloat){.dynlib: dllname,
+                                       importc: "glWindowPos2fvMESA".}
+proc glWindowPos2dvMESA*(p: PGLdouble){.dynlib: dllname,
+                                        importc: "glWindowPos2dvMESA".}
+proc glWindowPos3iMESA*(x: TGLint, y: TGLint, z: TGLint){.dynlib: dllname,
+    importc: "glWindowPos3iMESA".}
+proc glWindowPos3sMESA*(x: TGLshort, y: TGLshort, z: TGLshort){.dynlib: dllname,
+    importc: "glWindowPos3sMESA".}
+proc glWindowPos3fMESA*(x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glWindowPos3fMESA".}
+proc glWindowPos3dMESA*(x: TGLdouble, y: TGLdouble, z: TGLdouble){.
+    dynlib: dllname, importc: "glWindowPos3dMESA".}
+proc glWindowPos3ivMESA*(p: PGLint){.dynlib: dllname,
+                                     importc: "glWindowPos3ivMESA".}
+proc glWindowPos3svMESA*(p: PGLshort){.dynlib: dllname,
+                                       importc: "glWindowPos3svMESA".}
+proc glWindowPos3fvMESA*(p: PGLfloat){.dynlib: dllname,
+                                       importc: "glWindowPos3fvMESA".}
+proc glWindowPos3dvMESA*(p: PGLdouble){.dynlib: dllname,
+                                        importc: "glWindowPos3dvMESA".}
+proc glWindowPos4iMESA*(x: TGLint, y: TGLint, z: TGLint, w: TGLint){.
+    dynlib: dllname, importc: "glWindowPos4iMESA".}
+proc glWindowPos4sMESA*(x: TGLshort, y: TGLshort, z: TGLshort, w: TGLshort){.
+    dynlib: dllname, importc: "glWindowPos4sMESA".}
+proc glWindowPos4fMESA*(x: TGLfloat, y: TGLfloat, z: TGLfloat, w: TGLfloat){.
+    dynlib: dllname, importc: "glWindowPos4fMESA".}
+proc glWindowPos4dMESA*(x: TGLdouble, y: TGLdouble, z: TGLdouble, w: TGLdouble){.
+    dynlib: dllname, importc: "glWindowPos4dMESA".}
+proc glWindowPos4ivMESA*(p: PGLint){.dynlib: dllname,
+                                     importc: "glWindowPos4ivMESA".}
+proc glWindowPos4svMESA*(p: PGLshort){.dynlib: dllname,
+                                       importc: "glWindowPos4svMESA".}
+proc glWindowPos4fvMESA*(p: PGLfloat){.dynlib: dllname,
+                                       importc: "glWindowPos4fvMESA".}
+proc glWindowPos4dvMESA*(p: PGLdouble){.dynlib: dllname,
+                                        importc: "glWindowPos4dvMESA".}
+  #***** GL_OML_interlace *****//
+const
+  GL_INTERLACE_OML* = 0x00008980
+  GL_INTERLACE_READ_OML* = 0x00008981
+  #***** GL_OML_resample *****//
+
+const
+  GL_PACK_RESAMPLE_OML* = 0x00008984
+  GL_UNPACK_RESAMPLE_OML* = 0x00008985
+  GL_RESAMPLE_REPLICATE_OML* = 0x00008986
+  GL_RESAMPLE_ZERO_FILL_OML* = 0x00008987
+  GL_RESAMPLE_AVERAGE_OML* = 0x00008988
+  GL_RESAMPLE_DECIMATE_OML* = 0x00008989 # GL_RESAMPLE_AVERAGE_OML  { already defined }
+  #***** GL_OML_subsample *****//
+
+const
+  GL_FORMAT_SUBSAMPLE_24_24_OML* = 0x00008982
+  GL_FORMAT_SUBSAMPLE_244_244_OML* = 0x00008983
+  #***** GL_SGIS_generate_mipmap *****//
+
+const
+  GL_GENERATE_MIPMAP_SGIS* = 0x00008191
+  GL_GENERATE_MIPMAP_HINT_SGIS* = 0x00008192
+  #***** GL_SGIS_multisample *****//
+
+const
+  GLX_SAMPLE_BUFFERS_SGIS* = 0x000186A0
+  GLX_SAMPLES_SGIS* = 0x000186A1
+  GL_MULTISAMPLE_SGIS* = 0x0000809D
+  GL_SAMPLE_ALPHA_TO_MASK_SGIS* = 0x0000809E
+  GL_SAMPLE_ALPHA_TO_ONE_SGIS* = 0x0000809F
+  constGL_SAMPLE_MASK_SGIS* = 0x000080A0
+  GL_MULTISAMPLE_BIT_EXT* = 0x20000000
+  GL_1PASS_SGIS* = 0x000080A1
+  GL_2PASS_0_SGIS* = 0x000080A2
+  GL_2PASS_1_SGIS* = 0x000080A3
+  GL_4PASS_0_SGIS* = 0x000080A4
+  GL_4PASS_1_SGIS* = 0x000080A5
+  GL_4PASS_2_SGIS* = 0x000080A6
+  GL_4PASS_3_SGIS* = 0x000080A7
+  GL_SAMPLE_BUFFERS_SGIS* = 0x000080A8
+  GL_SAMPLES_SGIS* = 0x000080A9
+  GL_SAMPLE_MASK_VALUE_SGIS* = 0x000080AA
+  GL_SAMPLE_MASK_INVERT_SGIS* = 0x000080AB
+  constGL_SAMPLE_PATTERN_SGIS* = 0x000080AC
+
+proc glSampleMaskSGIS*(value: TGLclampf, invert: TGLboolean){.dynlib: dllname,
+    importc: "glSampleMaskSGIS".}
+proc glSamplePatternSGIS*(pattern: TGLenum){.dynlib: dllname,
+    importc: "glSamplePatternSGIS".}
+  #***** GL_SGIS_pixel_texture *****//
+const
+  GL_PIXEL_TEXTURE_SGIS* = 0x00008353
+  GL_PIXEL_FRAGMENT_RGB_SOURCE_SGIS* = 0x00008354
+  GL_PIXEL_FRAGMENT_ALPHA_SOURCE_SGIS* = 0x00008355
+  GL_PIXEL_GROUP_COLOR_SGIS* = 0x00008356
+
+proc glPixelTexGenParameteriSGIS*(pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glPixelTexGenParameteriSGIS".}
+proc glPixelTexGenParameterfSGIS*(pname: TGLenum, param: TGLfloat){.
+    dynlib: dllname, importc: "glPixelTexGenParameterfSGIS".}
+proc glGetPixelTexGenParameterivSGIS*(pname: TGLenum, params: TGLint){.
+    dynlib: dllname, importc: "glGetPixelTexGenParameterivSGIS".}
+proc glGetPixelTexGenParameterfvSGIS*(pname: TGLenum, params: TGLfloat){.
+    dynlib: dllname, importc: "glGetPixelTexGenParameterfvSGIS".}
+  #***** GL_SGIS_texture_border_clamp *****//
+  # GL_CLAMP_TO_BORDER_SGIS  { already defined }
+  #***** GL_SGIS_texture_color_mask *****//
+const
+  GL_TEXTURE_COLOR_WRITEMASK_SGIS* = 0x000081EF
+
+proc glTextureColorMaskSGIS*(r: TGLboolean, g: TGLboolean, b: TGLboolean,
+                             a: TGLboolean){.dynlib: dllname,
+    importc: "glTextureColorMaskSGIS".}
+  #***** GL_SGIS_texture_edge_clamp *****//
+const
+  GL_CLAMP_TO_EDGE_SGIS* = 0x0000812F
+  #***** GL_SGIS_texture_lod *****//
+
+const
+  GL_TEXTURE_MIN_LOD_SGIS* = 0x0000813A
+  GL_TEXTURE_MAX_LOD_SGIS* = 0x0000813B
+  GL_TEXTURE_BASE_LEVEL_SGIS* = 0x0000813C
+  GL_TEXTURE_MAX_LEVEL_SGIS* = 0x0000813D
+  #***** GL_SGIS_depth_texture *****//
+
+const
+  GL_DEPTH_COMPONENT16_SGIX* = 0x000081A5
+  GL_DEPTH_COMPONENT24_SGIX* = 0x000081A6
+  GL_DEPTH_COMPONENT32_SGIX* = 0x000081A7
+  #***** GL_SGIX_fog_offset *****//
+
+const
+  GL_FOG_OFFSET_SGIX* = 0x00008198
+  GL_FOG_OFFSET_VALUE_SGIX* = 0x00008199
+  #***** GL_SGIX_interlace *****//
+
+const
+  GL_INTERLACE_SGIX* = 0x00008094
+  #***** GL_SGIX_shadow_ambient *****//
+
+const
+  GL_SHADOW_AMBIENT_SGIX* = 0x000080BF
+  #***** GL_SGI_color_matrix *****//
+
+const
+  GL_COLOR_MATRIX_SGI* = 0x000080B1
+  GL_COLOR_MATRIX_STACK_DEPTH_SGI* = 0x000080B2
+  GL_MAX_COLOR_MATRIX_STACK_DEPTH_SGI* = 0x000080B3
+  GL_POST_COLOR_MATRIX_RED_SCALE_SGI* = 0x000080B4
+  GL_POST_COLOR_MATRIX_GREEN_SCALE_SGI* = 0x000080B5
+  GL_POST_COLOR_MATRIX_BLUE_SCALE_SGI* = 0x000080B6
+  GL_POST_COLOR_MATRIX_ALPHA_SCALE_SGI* = 0x000080B7
+  GL_POST_COLOR_MATRIX_RED_BIAS_SGI* = 0x000080B8
+  GL_POST_COLOR_MATRIX_GREEN_BIAS_SGI* = 0x000080B9
+  GL_POST_COLOR_MATRIX_BLUE_BIAS_SGI* = 0x000080BA
+  GL_POST_COLOR_MATRIX_ALPHA_BIAS_SGI* = 0x000080BB
+  #***** GL_SGI_color_table *****//
+
+const
+  constGL_COLOR_TABLE_SGI* = 0x000080D0
+  GL_POST_CONVOLUTION_COLOR_TABLE_SGI* = 0x000080D1
+  GL_POST_COLOR_MATRIX_COLOR_TABLE_SGI* = 0x000080D2
+  GL_PROXY_COLOR_TABLE_SGI* = 0x000080D3
+  GL_PROXY_POST_CONVOLUTION_COLOR_TABLE_SGI* = 0x000080D4
+  GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE_SGI* = 0x000080D5
+  GL_COLOR_TABLE_SCALE_SGI* = 0x000080D6
+  GL_COLOR_TABLE_BIAS_SGI* = 0x000080D7
+  GL_COLOR_TABLE_FORMAT_SGI* = 0x000080D8
+  GL_COLOR_TABLE_WIDTH_SGI* = 0x000080D9
+  GL_COLOR_TABLE_RED_SIZE_SGI* = 0x000080DA
+  GL_COLOR_TABLE_GREEN_SIZE_SGI* = 0x000080DB
+  GL_COLOR_TABLE_BLUE_SIZE_SGI* = 0x000080DC
+  GL_COLOR_TABLE_ALPHA_SIZE_SGI* = 0x000080DD
+  GL_COLOR_TABLE_LUMINANCE_SIZE_SGI* = 0x000080DE
+  GL_COLOR_TABLE_INTENSITY_SIZE_SGI* = 0x000080DF
+
+proc glColorTableSGI*(target: TGLenum, internalformat: TGLenum, width: TGLsizei,
+                      format: TGLenum, thetype: TGLenum, table: PGLvoid){.
+    dynlib: dllname, importc: "glColorTableSGI".}
+proc glCopyColorTableSGI*(target: TGLenum, internalformat: TGLenum, x: TGLint,
+                          y: TGLint, width: TGLsizei){.dynlib: dllname,
+    importc: "glCopyColorTableSGI".}
+proc glColorTableParameterivSGI*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glColorTableParameterivSGI".}
+proc glColorTableParameterfvSGI*(target: TGLenum, pname: TGLenum,
+                                 params: PGLfloat){.dynlib: dllname,
+    importc: "glColorTableParameterfvSGI".}
+proc glGetColorTableSGI*(target: TGLenum, format: TGLenum, thetype: TGLenum,
+                         table: PGLvoid){.dynlib: dllname,
+    importc: "glGetColorTableSGI".}
+proc glGetColorTableParameterivSGI*(target: TGLenum, pname: TGLenum,
+                                    params: PGLint){.dynlib: dllname,
+    importc: "glGetColorTableParameterivSGI".}
+proc glGetColorTableParameterfvSGI*(target: TGLenum, pname: TGLenum,
+                                    params: PGLfloat){.dynlib: dllname,
+    importc: "glGetColorTableParameterfvSGI".}
+  #***** GL_SGI_texture_color_table *****//
+const
+  GL_TEXTURE_COLOR_TABLE_SGI* = 0x000080BC
+  GL_PROXY_TEXTURE_COLOR_TABLE_SGI* = 0x000080BD
+  #***** GL_SUN_vertex *****//
+
+proc glColor4ubVertex2fSUN*(r: TGLubyte, g: TGLubyte, b: TGLubyte, a: TGLubyte,
+                            x: TGLfloat, y: TGLfloat){.dynlib: dllname,
+    importc: "glColor4ubVertex2fSUN".}
+proc glColor4ubVertex2fvSUN*(c: PGLubyte, v: PGLfloat){.dynlib: dllname,
+    importc: "glColor4ubVertex2fvSUN".}
+proc glColor4ubVertex3fSUN*(r: TGLubyte, g: TGLubyte, b: TGLubyte, a: TGLubyte,
+                            x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glColor4ubVertex3fSUN".}
+proc glColor4ubVertex3fvSUN*(c: PGLubyte, v: PGLfloat){.dynlib: dllname,
+    importc: "glColor4ubVertex3fvSUN".}
+proc glColor3fVertex3fSUN*(r: TGLfloat, g: TGLfloat, b: TGLfloat, x: TGLfloat,
+                           y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glColor3fVertex3fSUN".}
+proc glColor3fVertex3fvSUN*(c: PGLfloat, v: PGLfloat){.dynlib: dllname,
+    importc: "glColor3fVertex3fvSUN".}
+proc glNormal3fVertex3fSUN*(nx: TGLfloat, ny: TGLfloat, nz: TGLfloat,
+                            x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glNormal3fVertex3fSUN".}
+proc glNormal3fVertex3fvSUN*(n: PGLfloat, v: PGLfloat){.dynlib: dllname,
+    importc: "glNormal3fVertex3fvSUN".}
+proc glColor4fNormal3fVertex3fSUN*(r: TGLfloat, g: TGLfloat, b: TGLfloat,
+                                   a: TGLfloat, nx: TGLfloat, ny: TGLfloat,
+                                   nz: TGLfloat, x: TGLfloat, y: TGLfloat,
+                                   z: TGLfloat){.dynlib: dllname,
+    importc: "glColor4fNormal3fVertex3fSUN".}
+proc glColor4fNormal3fVertex3fvSUN*(c: PGLfloat, n: PGLfloat, v: PGLfloat){.
+    dynlib: dllname, importc: "glColor4fNormal3fVertex3fvSUN".}
+proc glTexCoord2fVertex3fSUN*(s: TGLfloat, t: TGLfloat, x: TGLfloat,
+                              y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glTexCoord2fVertex3fSUN".}
+proc glTexCoord2fVertex3fvSUN*(tc: PGLfloat, v: PGLfloat){.dynlib: dllname,
+    importc: "glTexCoord2fVertex3fvSUN".}
+proc glTexCoord4fVertex4fSUN*(s: TGLfloat, t: TGLfloat, p: TGLfloat,
+                              q: TGLfloat, x: TGLfloat, y: TGLfloat,
+                              z: TGLfloat, w: TGLfloat){.dynlib: dllname,
+    importc: "glTexCoord4fVertex4fSUN".}
+proc glTexCoord4fVertex4fvSUN*(tc: PGLfloat, v: PGLfloat){.dynlib: dllname,
+    importc: "glTexCoord4fVertex4fvSUN".}
+proc glTexCoord2fColor4ubVertex3fSUN*(s: TGLfloat, t: TGLfloat, r: TGLubyte,
+                                      g: TGLubyte, b: TGLubyte, a: TGLubyte,
+                                      x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor4ubVertex3fSUN".}
+proc glTexCoord2fColor4ubVertex3fvSUN*(tc: PGLfloat, c: PGLubyte, v: PGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor4ubVertex3fvSUN".}
+proc glTexCoord2fColor3fVertex3fSUN*(s: TGLfloat, t: TGLfloat, r: TGLfloat,
+                                     g: TGLfloat, b: TGLfloat, x: TGLfloat,
+                                     y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glTexCoord2fColor3fVertex3fSUN".}
+proc glTexCoord2fColor3fVertex3fvSUN*(tc: PGLfloat, c: PGLfloat, v: PGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor3fVertex3fvSUN".}
+proc glTexCoord2fNormal3fVertex3fSUN*(s: TGLfloat, t: TGLfloat, nx: TGLfloat,
+                                      ny: TGLfloat, nz: TGLfloat, x: TGLfloat,
+                                      y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fNormal3fVertex3fSUN".}
+proc glTexCoord2fNormal3fVertex3fvSUN*(tc: PGLfloat, n: PGLfloat, v: PGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fNormal3fVertex3fvSUN".}
+proc glTexCoord2fColor4fNormal3fVertex3fSUN*(s: TGLfloat, t: TGLfloat,
+    r: TGLfloat, g: TGLfloat, b: TGLfloat, a: TGLfloat, nx: TGLfloat,
+    ny: TGLfloat, nz: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glTexCoord2fColor4fNormal3fVertex3fSUN".}
+proc glTexCoord2fColor4fNormal3fVertex3fvSUN*(tc: PGLfloat, c: PGLfloat,
+    n: PGLfloat, v: PGLfloat){.dynlib: dllname, importc: "glTexCoord2fColor4fNormal3fVertex3fvSUN".}
+proc glTexCoord4fColor4fNormal3fVertex4fSUN*(s: TGLfloat, t: TGLfloat,
+    p: TGLfloat, q: TGLfloat, r: TGLfloat, g: TGLfloat, b: TGLfloat,
+    a: TGLfloat, nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, x: TGLfloat,
+    y: TGLfloat, z: TGLfloat, w: TGLfloat){.dynlib: dllname,
+    importc: "glTexCoord4fColor4fNormal3fVertex4fSUN".}
+proc glTexCoord4fColor4fNormal3fVertex4fvSUN*(tc: PGLfloat, c: PGLfloat,
+    n: PGLfloat, v: PGLfloat){.dynlib: dllname, importc: "glTexCoord4fColor4fNormal3fVertex4fvSUN".}
+proc glReplacementCodeuiVertex3fSUN*(rc: TGLuint, x: TGLfloat, y: TGLfloat,
+                                     z: TGLfloat){.dynlib: dllname,
+    importc: "glReplacementCodeuiVertex3fSUN".}
+proc glReplacementCodeuiVertex3fvSUN*(rc: PGLuint, v: PGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiVertex3fvSUN".}
+proc glReplacementCodeuiColor4ubVertex3fSUN*(rc: TGLuint, r: TGLubyte,
+    g: TGLubyte, b: TGLubyte, a: TGLubyte, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiColor4ubVertex3fSUN".}
+proc glReplacementCodeuiColor4ubVertex3fvSUN*(rc: PGLuint, c: PGLubyte,
+    v: PGLfloat){.dynlib: dllname,
+                  importc: "glReplacementCodeuiColor4ubVertex3fvSUN".}
+proc glReplacementCodeuiColor3fVertex3fSUN*(rc: TGLuint, r: TGLfloat,
+    g: TGLfloat, b: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiColor3fVertex3fSUN".}
+proc glReplacementCodeuiColor3fVertex3fvSUN*(rc: PGLuint, c: PGLfloat,
+    v: PGLfloat){.dynlib: dllname,
+                  importc: "glReplacementCodeuiColor3fVertex3fvSUN".}
+proc glReplacementCodeuiNormal3fVertex3fSUN*(rc: TGLuint, nx: TGLfloat,
+    ny: TGLfloat, nz: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.
+    dynlib: dllname, importc: "glReplacementCodeuiNormal3fVertex3fSUN".}
+proc glReplacementCodeuiNormal3fVertex3fvSUN*(rc: PGLuint, n: PGLfloat,
+    v: PGLfloat){.dynlib: dllname,
+                  importc: "glReplacementCodeuiNormal3fVertex3fvSUN".}
+proc glReplacementCodeuiColor4fNormal3fVertex3fSUN*(rc: TGLuint, r: TGLfloat,
+    g: TGLfloat, b: TGLfloat, a: TGLfloat, nx: TGLfloat, ny: TGLfloat,
+    nz: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glReplacementCodeuiColor4fNormal3fVertex3fSUN".}
+proc glReplacementCodeuiColor4fNormal3fVertex3fvSUN*(rc: PGLuint, c: PGLfloat,
+    n: PGLfloat, v: PGLfloat){.dynlib: dllname, importc: "glReplacementCodeuiColor4fNormal3fVertex3fvSUN".}
+proc glReplacementCodeuiTexCoord2fVertex3fSUN*(rc: TGLuint, s: TGLfloat,
+    t: TGLfloat, x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glReplacementCodeuiTexCoord2fVertex3fSUN".}
+proc glReplacementCodeuiTexCoord2fVertex3fvSUN*(rc: PGLuint, tc: PGLfloat,
+    v: PGLfloat){.dynlib: dllname,
+                  importc: "glReplacementCodeuiTexCoord2fVertex3fvSUN".}
+proc glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN*(rc: TGLuint, s: TGLfloat,
+    t: TGLfloat, nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, x: TGLfloat,
+    y: TGLfloat, z: TGLfloat){.dynlib: dllname, importc: "glReplacementCodeuiTexCoord2fNormal3fVertex3fSUN".}
+proc glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN*(rc: PGLuint,
+    tc: PGLfloat, n: PGLfloat, v: PGLfloat){.dynlib: dllname,
+    importc: "glReplacementCodeuiTexCoord2fNormal3fVertex3fvSUN".}
+proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN*(rc: TGLuint,
+    s: TGLfloat, t: TGLfloat, r: TGLfloat, g: TGLfloat, b: TGLfloat,
+    a: TGLfloat, nx: TGLfloat, ny: TGLfloat, nz: TGLfloat, x: TGLfloat,
+    y: TGLfloat, z: TGLfloat){.dynlib: dllname, importc: "glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fSUN".}
+proc glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN*(rc: PGLuint,
+    tc: PGLfloat, c: PGLfloat, n: PGLfloat, v: PGLfloat){.dynlib: dllname,
+    importc: "glReplacementCodeuiTexCoord2fColor4fNormal3fVertex3fvSUN".}
+  #***** GL_ARB_fragment_program *****//
+const
+  GL_FRAGMENT_PROGRAM_ARB* = 0x00008804 # GL_PROGRAM_FORMAT_ASCII_ARB  { already defined }
+                                        # GL_PROGRAM_LENGTH_ARB  { already defined }
+                                        # GL_PROGRAM_FORMAT_ARB  { already defined }
+                                        # GL_PROGRAM_BINDING_ARB  { already defined }
+                                        # GL_PROGRAM_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB  { already defined }
+                                        # GL_PROGRAM_TEMPORARIES_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_TEMPORARIES_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_TEMPORARIES_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB  { already defined }
+                                        # GL_PROGRAM_PARAMETERS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_PARAMETERS_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_PARAMETERS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB  { already defined }
+                                        # GL_PROGRAM_ATTRIBS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_ATTRIBS_ARB  { already defined }
+                                        # GL_PROGRAM_NATIVE_ATTRIBS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB  { already defined }
+                                        # GL_MAX_PROGRAM_ENV_PARAMETERS_ARB  { already defined }
+                                        # GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB  { already defined }
+  GL_PROGRAM_ALU_INSTRUCTIONS_ARB* = 0x00008805
+  GL_PROGRAM_TEX_INSTRUCTIONS_ARB* = 0x00008806
+  GL_PROGRAM_TEX_INDIRECTIONS_ARB* = 0x00008807
+  GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB* = 0x00008808
+  GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB* = 0x00008809
+  GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB* = 0x0000880A
+  GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB* = 0x0000880B
+  GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB* = 0x0000880C
+  GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB* = 0x0000880D
+  GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB* = 0x0000880E
+  GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB* = 0x0000880F
+  GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB* = 0x00008810 # GL_PROGRAM_STRING_ARB  { already defined }
+                                                           #
+                                                           #
+                                                           # GL_PROGRAM_ERROR_POSITION_ARB  { already defined }
+                                                           # GL_CURRENT_MATRIX_ARB  { already defined }
+                                                           #
+                                                           #
+                                                           # GL_TRANSPOSE_CURRENT_MATRIX_ARB  { already defined }
+                                                           #
+                                                           #
+                                                           # GL_CURRENT_MATRIX_STACK_DEPTH_ARB  { already defined }
+                                                           #
+                                                           #
+                                                           # GL_MAX_PROGRAM_MATRICES_ARB  { already defined }
+                                                           #
+                                                           #
+                                                           # GL_MAX_PROGRAM_MATRIX_STACK_DEPTH_ARB  { already defined }
+  GL_MAX_TEXTURE_COORDS_ARB* = 0x00008871
+  GL_MAX_TEXTURE_IMAGE_UNITS_ARB* = 0x00008872 # GL_PROGRAM_ERROR_STRING_ARB  { already defined }
+                                               # GL_MATRIX0_ARB  { already defined }
+                                               # GL_MATRIX1_ARB  { already defined }
+                                               # GL_MATRIX2_ARB  { already defined }
+                                               # GL_MATRIX3_ARB  { already defined }
+                                               # GL_MATRIX4_ARB  { already defined }
+                                               # GL_MATRIX5_ARB  { already defined }
+                                               # GL_MATRIX6_ARB  { already defined }
+                                               # GL_MATRIX7_ARB  { already defined }
+                                               # GL_MATRIX8_ARB  { already defined }
+                                               # GL_MATRIX9_ARB  { already defined }
+                                               # GL_MATRIX10_ARB  { already defined }
+                                               # GL_MATRIX11_ARB  { already defined }
+                                               # GL_MATRIX12_ARB  { already defined }
+                                               # GL_MATRIX13_ARB  { already defined }
+                                               # GL_MATRIX14_ARB  { already defined }
+                                               # GL_MATRIX15_ARB  { already defined }
+                                               # GL_MATRIX16_ARB  { already defined }
+                                               # GL_MATRIX17_ARB  { already defined }
+                                               # GL_MATRIX18_ARB  { already defined }
+                                               # GL_MATRIX19_ARB  { already defined }
+                                               # GL_MATRIX20_ARB  { already defined }
+                                               # GL_MATRIX21_ARB  { already defined }
+                                               # GL_MATRIX22_ARB  { already defined }
+                                               # GL_MATRIX23_ARB  { already defined }
+                                               # GL_MATRIX24_ARB  { already defined }
+                                               # GL_MATRIX25_ARB  { already defined }
+                                               # GL_MATRIX26_ARB  { already defined }
+                                               # GL_MATRIX27_ARB  { already defined }
+                                               # GL_MATRIX28_ARB  { already defined }
+                                               # GL_MATRIX29_ARB  { already defined }
+                                               # GL_MATRIX30_ARB  { already defined }
+                                               # GL_MATRIX31_ARB  { already defined }
+                                               # glProgramStringARB  { already defined }
+                                               # glBindProgramARB  { already defined }
+                                               # glDeleteProgramsARB  { already defined }
+                                               # glGenProgramsARB  { already defined }
+                                               # glProgramEnvParameter4dARB  { already defined }
+                                               # glProgramEnvParameter4dvARB  { already defined }
+                                               # glProgramEnvParameter4fARB  { already defined }
+                                               # glProgramEnvParameter4fvARB  { already defined }
+                                               # glProgramLocalParameter4dARB  { already defined }
+                                               # glProgramLocalParameter4dvARB  { already defined }
+                                               # glProgramLocalParameter4fARB  { already defined }
+                                               # glProgramLocalParameter4fvARB  { already defined }
+                                               # glGetProgramEnvParameterdvARB  { already defined }
+                                               # glGetProgramEnvParameterfvARB  { already defined }
+                                               # glGetProgramLocalParameterdvARB  { already defined }
+                                               # glGetProgramLocalParameterfvARB  { already defined }
+                                               # glGetProgramivARB  { already defined }
+                                               # glGetProgramStringARB  { already defined }
+                                               # glIsProgramARB  { already defined }
+  #***** GL_ATI_text_fragment_shader *****
+
+const
+  GL_TEXT_FRAGMENT_SHADER_ATI* = 0x00008200 #***** GL_ARB_vertex_buffer_object *****
+
+const
+  GL_BUFFER_SIZE_ARB* = 0x00008764
+  GL_BUFFER_USAGE_ARB* = 0x00008765
+  GL_ARRAY_BUFFER_ARB* = 0x00008892
+  GL_ELEMENT_ARRAY_BUFFER_ARB* = 0x00008893
+  GL_ARRAY_BUFFER_BINDING_ARB* = 0x00008894
+  GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB* = 0x00008895
+  GL_VERTEX_ARRAY_BUFFER_BINDING_ARB* = 0x00008896
+  GL_NORMAL_ARRAY_BUFFER_BINDING_ARB* = 0x00008897
+  GL_COLOR_ARRAY_BUFFER_BINDING_ARB* = 0x00008898
+  GL_INDEX_ARRAY_BUFFER_BINDING_ARB* = 0x00008899
+  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING_ARB* = 0x0000889A
+  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING_ARB* = 0x0000889B
+  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING_ARB* = 0x0000889C
+  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING_ARB* = 0x0000889D
+  GL_WEIGHT_ARRAY_BUFFER_BINDING_ARB* = 0x0000889E
+  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB* = 0x0000889F
+  GL_READ_ONLY_ARB* = 0x000088B8
+  GL_WRITE_ONLY_ARB* = 0x000088B9
+  GL_READ_WRITE_ARB* = 0x000088BA
+  GL_BUFFER_ACCESS_ARB* = 0x000088BB
+  GL_BUFFER_MAPPED_ARB* = 0x000088BC
+  GL_BUFFER_MAP_POINTER_ARB* = 0x000088BD
+  GL_STREAM_DRAW_ARB* = 0x000088E0
+  GL_STREAM_READ_ARB* = 0x000088E1
+  GL_STREAM_COPY_ARB* = 0x000088E2
+  GL_STATIC_DRAW_ARB* = 0x000088E4
+  GL_STATIC_READ_ARB* = 0x000088E5
+  GL_STATIC_COPY_ARB* = 0x000088E6
+  GL_DYNAMIC_DRAW_ARB* = 0x000088E8
+  GL_DYNAMIC_READ_ARB* = 0x000088E9
+  GL_DYNAMIC_COPY_ARB* = 0x000088EA
+
+proc glBindBufferARB*(target: TGLenum, buffer: TGLuint){.dynlib: dllname,
+    importc: "glBindBufferARB".}
+proc glDeleteBuffersARB*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname,
+    importc: "glDeleteBuffersARB".}
+proc glGenBuffersARB*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname,
+    importc: "glGenBuffersARB".}
+proc glIsBufferARB*(buffer: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsBufferARB".}
+proc glBufferDataARB*(target: TGLenum, size: TGLsizei, data: PGLvoid,
+                      usage: TGLenum){.dynlib: dllname,
+                                       importc: "glBufferDataARB".}
+proc glBufferSubDataARB*(target: TGLenum, offset: TGLint, size: TGLsizei,
+                         data: PGLvoid){.dynlib: dllname,
+    importc: "glBufferSubDataARB".}
+proc glGetBufferSubDataARB*(target: TGLenum, offset: TGLint, size: TGLsizei,
+                            data: PGLvoid){.dynlib: dllname,
+    importc: "glGetBufferSubDataARB".}
+proc glMapBufferARB*(target: TGLenum, access: TGLenum): PGLvoid{.
+    dynlib: dllname, importc: "glMapBufferARB".}
+proc glUnmapBufferARB*(target: TGLenum): TGLboolean{.dynlib: dllname,
+    importc: "glUnmapBufferARB".}
+proc glGetBufferParameterivARB*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetBufferParameterivARB".}
+proc glGetBufferPointervARB*(target: TGLenum, pname: TGLenum, params: PPGLvoid){.
+    dynlib: dllname, importc: "glGetBufferPointervARB".}
+  #***** GL_APPLE_client_storage *****//
+const
+  GL_UNPACK_CLIENT_STORAGE_APPLE* = 0x000085B2
+  #***** GL_APPLE_element_array *****//
+
+const
+  GL_ELEMENT_ARRAY_APPLE* = 0x00008768
+  GL_ELEMENT_ARRAY_TYPE_APPLE* = 0x00008769
+  GL_ELEMENT_ARRAY_POINTER_APPLE* = 0x0000876A
+
+proc glElementPointerAPPLE*(thetype: TGLenum, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glElementPointerAPPLE".}
+proc glDrawElementArrayAPPLE*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawElementArrayAPPLE".}
+proc glDrawRangeElementArrayAPPLE*(mode: TGLenum, start: TGLuint,
+                                   theend: TGLuint, first: TGLint,
+                                   count: TGLsizei){.dynlib: dllname,
+    importc: "glDrawRangeElementArrayAPPLE".}
+proc glMultiDrawElementArrayAPPLE*(mode: TGLenum, first: PGLint,
+                                   count: PGLsizei, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawElementArrayAPPLE".}
+proc glMultiDrawRangeElementArrayAPPLE*(mode: TGLenum, start: TGLuint,
+                                        theend: TGLuint, first: PGLint,
+                                        count: PGLsizei, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawRangeElementArrayAPPLE".}
+  #***** GL_APPLE_fence *****//
+const
+  GL_DRAW_PIXELS_APPLE* = 0x00008A0A
+  GL_FENCE_APPLE* = 0x00008A0B
+
+proc glGenFencesAPPLE*(n: TGLsizei, fences: PGLuint){.dynlib: dllname,
+    importc: "glGenFencesAPPLE".}
+proc glDeleteFencesAPPLE*(n: TGLsizei, fences: PGLuint){.dynlib: dllname,
+    importc: "glDeleteFencesAPPLE".}
+proc glSetFenceAPPLE*(fence: TGLuint){.dynlib: dllname,
+                                       importc: "glSetFenceAPPLE".}
+proc glIsFenceAPPLE*(fence: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsFenceAPPLE".}
+proc glTestFenceAPPLE*(fence: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glTestFenceAPPLE".}
+proc glFinishFenceAPPLE*(fence: TGLuint){.dynlib: dllname,
+    importc: "glFinishFenceAPPLE".}
+proc glTestObjectAPPLE*(theobject: TGLenum, name: TGLuint): TGLboolean{.
+    dynlib: dllname, importc: "glTestObjectAPPLE".}
+proc glFinishObjectAPPLE*(theobject: TGLenum, name: TGLint){.dynlib: dllname,
+    importc: "glFinishObjectAPPLE".}
+  #***** GL_APPLE_vertex_array_object *****//
+const
+  GL_VERTEX_ARRAY_BINDING_APPLE* = 0x000085B5
+
+proc glBindVertexArrayAPPLE*(thearray: TGLuint){.dynlib: dllname,
+    importc: "glBindVertexArrayAPPLE".}
+proc glDeleteVertexArraysAPPLE*(n: TGLsizei, arrays: PGLuint){.dynlib: dllname,
+    importc: "glDeleteVertexArraysAPPLE".}
+proc glGenVertexArraysAPPLE*(n: TGLsizei, arrays: PGLuint){.dynlib: dllname,
+    importc: "glGenVertexArraysAPPLE".}
+proc glIsVertexArrayAPPLE*(thearray: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsVertexArrayAPPLE".}
+  #***** GL_APPLE_vertex_array_range *****//
+const
+  constGL_VERTEX_ARRAY_RANGE_APPLE* = 0x0000851D
+  GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE* = 0x0000851E
+  GL_MAX_VERTEX_ARRAY_RANGE_ELEMENT_APPLE* = 0x00008520
+  GL_VERTEX_ARRAY_RANGE_POINTER_APPLE* = 0x00008521
+  GL_VERTEX_ARRAY_STORAGE_HINT_APPLE* = 0x0000851F
+  GL_STORAGE_CACHED_APPLE* = 0x000085BE
+  GL_STORAGE_SHARED_APPLE* = 0x000085BF
+
+proc glVertexArrayRangeAPPLE*(len: TGLsizei, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glVertexArrayRangeAPPLE".}
+proc glFlushVertexArrayRangeAPPLE*(len: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glFlushVertexArrayRangeAPPLE".}
+proc glVertexArrayParameteriAPPLE*(pname: TGLenum, param: TGLint){.
+    dynlib: dllname, importc: "glVertexArrayParameteriAPPLE".}
+  #***** GL_ARB_matrix_palette *****//
+const
+  GL_MATRIX_PALETTE_ARB* = 0x00008840
+  GL_MAX_MATRIX_PALETTE_STACK_DEPTH_ARB* = 0x00008841
+  GL_MAX_PALETTE_MATRICES_ARB* = 0x00008842
+  constGL_CURRENT_PALETTE_MATRIX_ARB* = 0x00008843
+  GL_MATRIX_INDEX_ARRAY_ARB* = 0x00008844
+  GL_CURRENT_MATRIX_INDEX_ARB* = 0x00008845
+  GL_MATRIX_INDEX_ARRAY_SIZE_ARB* = 0x00008846
+  GL_MATRIX_INDEX_ARRAY_TYPE_ARB* = 0x00008847
+  GL_MATRIX_INDEX_ARRAY_STRIDE_ARB* = 0x00008848
+  GL_MATRIX_INDEX_ARRAY_POINTER_ARB* = 0x00008849
+
+proc glCurrentPaletteMatrixARB*(index: TGLint){.dynlib: dllname,
+    importc: "glCurrentPaletteMatrixARB".}
+proc glMatrixIndexubvARB*(size: TGLint, indices: PGLubyte){.dynlib: dllname,
+    importc: "glMatrixIndexubvARB".}
+proc glMatrixIndexusvARB*(size: TGLint, indices: PGLushort){.dynlib: dllname,
+    importc: "glMatrixIndexusvARB".}
+proc glMatrixIndexuivARB*(size: TGLint, indices: PGLuint){.dynlib: dllname,
+    importc: "glMatrixIndexuivARB".}
+proc glMatrixIndexPointerARB*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                              pointer: PGLvoid){.dynlib: dllname,
+    importc: "glMatrixIndexPointerARB".}
+  #***** GL_NV_element_array *****//
+const
+  GL_ELEMENT_ARRAY_TYPE_NV* = 0x00008769
+  GL_ELEMENT_ARRAY_POINTER_NV* = 0x0000876A
+
+proc glElementPointerNV*(thetype: TGLenum, pointer: PGLvoid){.dynlib: dllname,
+    importc: "glElementPointerNV".}
+proc glDrawElementArrayNV*(mode: TGLenum, first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawElementArrayNV".}
+proc glDrawRangeElementArrayNV*(mode: TGLenum, start: TGLuint, theend: TGLuint,
+                                first: TGLint, count: TGLsizei){.
+    dynlib: dllname, importc: "glDrawRangeElementArrayNV".}
+proc glMultiDrawElementArrayNV*(mode: TGLenum, first: PGLint, count: PGLsizei,
+                                primcount: TGLsizei){.dynlib: dllname,
+    importc: "glMultiDrawElementArrayNV".}
+proc glMultiDrawRangeElementArrayNV*(mode: TGLenum, start: TGLuint,
+                                     theend: TGLuint, first: PGLint,
+                                     count: PGLsizei, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawRangeElementArrayNV".}
+  #***** GL_NV_float_buffer *****//
+const
+  GL_FLOAT_R_NV* = 0x00008880
+  GL_FLOAT_RG_NV* = 0x00008881
+  GL_FLOAT_RGB_NV* = 0x00008882
+  GL_FLOAT_RGBA_NV* = 0x00008883
+  GL_FLOAT_R16_NV* = 0x00008884
+  GL_FLOAT_R32_NV* = 0x00008885
+  GL_FLOAT_RG16_NV* = 0x00008886
+  GL_FLOAT_RG32_NV* = 0x00008887
+  GL_FLOAT_RGB16_NV* = 0x00008888
+  GL_FLOAT_RGB32_NV* = 0x00008889
+  GL_FLOAT_RGBA16_NV* = 0x0000888A
+  GL_FLOAT_RGBA32_NV* = 0x0000888B
+  GL_TEXTURE_FLOAT_COMPONENTS_NV* = 0x0000888C
+  GL_FLOAT_CLEAR_COLOR_VALUE_NV* = 0x0000888D
+  GL_FLOAT_RGBA_MODE_NV* = 0x0000888E
+  #***** GL_NV_fragment_program *****//
+
+const
+  GL_FRAGMENT_PROGRAM_NV* = 0x00008870
+  GL_MAX_TEXTURE_COORDS_NV* = 0x00008871
+  GL_MAX_TEXTURE_IMAGE_UNITS_NV* = 0x00008872
+  GL_FRAGMENT_PROGRAM_BINDING_NV* = 0x00008873
+  GL_MAX_FRAGMENT_PROGRAM_LOCAL_PARAMETERS_NV* = 0x00008868
+  GL_PROGRAM_ERROR_STRING_NV* = 0x00008874
+
+proc glProgramNamedParameter4fNV*(id: TGLuint, length: TGLsizei, name: PGLubyte,
+                                  x: TGLfloat, y: TGLfloat, z: TGLfloat,
+                                  w: TGLfloat){.dynlib: dllname,
+    importc: "glProgramNamedParameter4fNV".}
+proc glProgramNamedParameter4dNV*(id: TGLuint, length: TGLsizei, name: PGLubyte,
+                                  x: TGLdouble, y: TGLdouble, z: TGLdouble,
+                                  w: TGLdouble){.dynlib: dllname,
+    importc: "glProgramNamedParameter4dNV".}
+proc glGetProgramNamedParameterfvNV*(id: TGLuint, length: TGLsizei,
+                                     name: PGLubyte, params: PGLfloat){.
+    dynlib: dllname, importc: "glGetProgramNamedParameterfvNV".}
+proc glGetProgramNamedParameterdvNV*(id: TGLuint, length: TGLsizei,
+                                     name: PGLubyte, params: PGLdouble){.
+    dynlib: dllname, importc: "glGetProgramNamedParameterdvNV".}
+  # glProgramLocalParameter4dARB  { already defined }
+  # glProgramLocalParameter4dvARB  { already defined }
+  # glProgramLocalParameter4fARB  { already defined }
+  # glProgramLocalParameter4fvARB  { already defined }
+  # glGetProgramLocalParameterdvARB  { already defined }
+  # glGetProgramLocalParameterfvARB  { already defined }
+  #***** GL_NV_primitive_restart *****//
+const
+  constGL_PRIMITIVE_RESTART_NV* = 0x00008558
+  constGL_PRIMITIVE_RESTART_INDEX_NV* = 0x00008559
+
+proc glPrimitiveRestartNV*(){.dynlib: dllname, importc: "glPrimitiveRestartNV".}
+proc glPrimitiveRestartIndexNV*(index: TGLuint){.dynlib: dllname,
+    importc: "glPrimitiveRestartIndexNV".}
+  #***** GL_NV_vertex_program2 *****//
+  #***** GL_NV_pixel_data_range *****//
+const
+  GL_WRITE_PIXEL_DATA_RANGE_NV* = 0x00008878
+  GL_READ_PIXEL_DATA_RANGE_NV* = 0x00008879
+  GL_WRITE_PIXEL_DATA_RANGE_LENGTH_NV* = 0x0000887A
+  GL_READ_PIXEL_DATA_RANGE_LENGTH_NV* = 0x0000887B
+  GL_WRITE_PIXEL_DATA_RANGE_POINTER_NV* = 0x0000887C
+  GL_READ_PIXEL_DATA_RANGE_POINTER_NV* = 0x0000887D
+
+proc glPixelDataRangeNV*(target: TGLenum, len: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glPixelDataRangeNV".}
+proc glFlushPixelDataRangeNV*(target: TGLenum){.dynlib: dllname,
+    importc: "glFlushPixelDataRangeNV".}
+  # wglAllocateMemoryNV  { already defined }
+  # wglFreeMemoryNV  { already defined }
+  #***** GL_EXT_texture_rectangle *****//
+const
+  GL_TEXTURE_RECTANGLE_EXT* = 0x000084F5
+  GL_TEXTURE_BINDING_RECTANGLE_EXT* = 0x000084F6
+  GL_PROXY_TEXTURE_RECTANGLE_EXT* = 0x000084F7
+  GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT* = 0x000084F8
+  #***** GL_S3_s3tc *****//
+
+const
+  GL_RGB_S3TC* = 0x000083A0
+  GL_RGB4_S3TC* = 0x000083A1
+  GL_RGBA_S3TC* = 0x000083A2
+  GL_RGBA4_S3TC* = 0x000083A3
+  #***** GL_ATI_draw_buffers *****//
+
+const
+  GL_MAX_DRAW_BUFFERS_ATI* = 0x00008824
+  GL_DRAW_BUFFER0_ATI* = 0x00008825
+  GL_DRAW_BUFFER1_ATI* = 0x00008826
+  GL_DRAW_BUFFER2_ATI* = 0x00008827
+  GL_DRAW_BUFFER3_ATI* = 0x00008828
+  GL_DRAW_BUFFER4_ATI* = 0x00008829
+  GL_DRAW_BUFFER5_ATI* = 0x0000882A
+  GL_DRAW_BUFFER6_ATI* = 0x0000882B
+  GL_DRAW_BUFFER7_ATI* = 0x0000882C
+  GL_DRAW_BUFFER8_ATI* = 0x0000882D
+  GL_DRAW_BUFFER9_ATI* = 0x0000882E
+  GL_DRAW_BUFFER10_ATI* = 0x0000882F
+  GL_DRAW_BUFFER11_ATI* = 0x00008830
+  GL_DRAW_BUFFER12_ATI* = 0x00008831
+  GL_DRAW_BUFFER13_ATI* = 0x00008832
+  GL_DRAW_BUFFER14_ATI* = 0x00008833
+  GL_DRAW_BUFFER15_ATI* = 0x00008834
+
+proc glDrawBuffersATI*(n: TGLsizei, bufs: PGLenum){.dynlib: dllname,
+    importc: "glDrawBuffersATI".}
+  #***** GL_ATI_texture_env_combine3 *****//
+const
+  GL_MODULATE_ADD_ATI* = 0x00008744
+  GL_MODULATE_SIGNED_ADD_ATI* = 0x00008745
+  GL_MODULATE_SUBTRACT_ATI* = 0x00008746
+  #***** GL_ATI_texture_float *****//
+
+const
+  GL_RGBA_FLOAT32_ATI* = 0x00008814
+  GL_RGB_FLOAT32_ATI* = 0x00008815
+  GL_ALPHA_FLOAT32_ATI* = 0x00008816
+  GL_INTENSITY_FLOAT32_ATI* = 0x00008817
+  GL_LUMINANCE_FLOAT32_ATI* = 0x00008818
+  GL_LUMINANCE_ALPHA_FLOAT32_ATI* = 0x00008819
+  GL_RGBA_FLOAT16_ATI* = 0x0000881A
+  GL_RGB_FLOAT16_ATI* = 0x0000881B
+  GL_ALPHA_FLOAT16_ATI* = 0x0000881C
+  GL_INTENSITY_FLOAT16_ATI* = 0x0000881D
+  GL_LUMINANCE_FLOAT16_ATI* = 0x0000881E
+  GL_LUMINANCE_ALPHA_FLOAT16_ATI* = 0x0000881F
+  #***** GL_NV_texture_expand_normal *****//
+
+const
+  GL_TEXTURE_UNSIGNED_REMAP_MODE_NV* = 0x0000888F
+  #***** GL_NV_half_float *****//
+
+const
+  GL_HALF_FLOAT_NV* = 0x0000140B
+
+proc glVertex2hNV*(x: TGLushort, y: TGLushort){.dynlib: dllname,
+    importc: "glVertex2hNV".}
+proc glVertex2hvNV*(v: PGLushort){.dynlib: dllname, importc: "glVertex2hvNV".}
+proc glVertex3hNV*(x: TGLushort, y: TGLushort, z: TGLushort){.dynlib: dllname,
+    importc: "glVertex3hNV".}
+proc glVertex3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glVertex3hvNV".}
+proc glVertex4hNV*(x: TGLushort, y: TGLushort, z: TGLushort, w: TGLushort){.
+    dynlib: dllname, importc: "glVertex4hNV".}
+proc glVertex4hvNV*(v: PGLushort){.dynlib: dllname, importc: "glVertex4hvNV".}
+proc glNormal3hNV*(nx: TGLushort, ny: TGLushort, nz: TGLushort){.
+    dynlib: dllname, importc: "glNormal3hNV".}
+proc glNormal3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glNormal3hvNV".}
+proc glColor3hNV*(red: TGLushort, green: TGLushort, blue: TGLushort){.
+    dynlib: dllname, importc: "glColor3hNV".}
+proc glColor3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glColor3hvNV".}
+proc glColor4hNV*(red: TGLushort, green: TGLushort, blue: TGLushort,
+                  alpha: TGLushort){.dynlib: dllname, importc: "glColor4hNV".}
+proc glColor4hvNV*(v: PGLushort){.dynlib: dllname, importc: "glColor4hvNV".}
+proc glTexCoord1hNV*(s: TGLushort){.dynlib: dllname, importc: "glTexCoord1hNV".}
+proc glTexCoord1hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord1hvNV".}
+proc glTexCoord2hNV*(s: TGLushort, t: TGLushort){.dynlib: dllname,
+    importc: "glTexCoord2hNV".}
+proc glTexCoord2hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord2hvNV".}
+proc glTexCoord3hNV*(s: TGLushort, t: TGLushort, r: TGLushort){.dynlib: dllname,
+    importc: "glTexCoord3hNV".}
+proc glTexCoord3hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord3hvNV".}
+proc glTexCoord4hNV*(s: TGLushort, t: TGLushort, r: TGLushort, q: TGLushort){.
+    dynlib: dllname, importc: "glTexCoord4hNV".}
+proc glTexCoord4hvNV*(v: PGLushort){.dynlib: dllname, importc: "glTexCoord4hvNV".}
+proc glMultiTexCoord1hNV*(target: TGLenum, s: TGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord1hNV".}
+proc glMultiTexCoord1hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord1hvNV".}
+proc glMultiTexCoord2hNV*(target: TGLenum, s: TGLushort, t: TGLushort){.
+    dynlib: dllname, importc: "glMultiTexCoord2hNV".}
+proc glMultiTexCoord2hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord2hvNV".}
+proc glMultiTexCoord3hNV*(target: TGLenum, s: TGLushort, t: TGLushort,
+                          r: TGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord3hNV".}
+proc glMultiTexCoord3hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord3hvNV".}
+proc glMultiTexCoord4hNV*(target: TGLenum, s: TGLushort, t: TGLushort,
+                          r: TGLushort, q: TGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord4hNV".}
+proc glMultiTexCoord4hvNV*(target: TGLenum, v: PGLushort){.dynlib: dllname,
+    importc: "glMultiTexCoord4hvNV".}
+proc glFogCoordhNV*(fog: TGLushort){.dynlib: dllname, importc: "glFogCoordhNV".}
+proc glFogCoordhvNV*(fog: PGLushort){.dynlib: dllname, importc: "glFogCoordhvNV".}
+proc glSecondaryColor3hNV*(red: TGLushort, green: TGLushort, blue: TGLushort){.
+    dynlib: dllname, importc: "glSecondaryColor3hNV".}
+proc glSecondaryColor3hvNV*(v: PGLushort){.dynlib: dllname,
+    importc: "glSecondaryColor3hvNV".}
+proc glVertexWeighthNV*(weight: TGLushort){.dynlib: dllname,
+    importc: "glVertexWeighthNV".}
+proc glVertexWeighthvNV*(weight: PGLushort){.dynlib: dllname,
+    importc: "glVertexWeighthvNV".}
+proc glVertexAttrib1hNV*(index: TGLuint, x: TGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib1hNV".}
+proc glVertexAttrib1hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib1hvNV".}
+proc glVertexAttrib2hNV*(index: TGLuint, x: TGLushort, y: TGLushort){.
+    dynlib: dllname, importc: "glVertexAttrib2hNV".}
+proc glVertexAttrib2hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib2hvNV".}
+proc glVertexAttrib3hNV*(index: TGLuint, x: TGLushort, y: TGLushort,
+                         z: TGLushort){.dynlib: dllname,
+                                        importc: "glVertexAttrib3hNV".}
+proc glVertexAttrib3hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib3hvNV".}
+proc glVertexAttrib4hNV*(index: TGLuint, x: TGLushort, y: TGLushort,
+                         z: TGLushort, w: TGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib4hNV".}
+proc glVertexAttrib4hvNV*(index: TGLuint, v: PGLushort){.dynlib: dllname,
+    importc: "glVertexAttrib4hvNV".}
+proc glVertexAttribs1hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs1hvNV".}
+proc glVertexAttribs2hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs2hvNV".}
+proc glVertexAttribs3hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs3hvNV".}
+proc glVertexAttribs4hvNV*(index: TGLuint, n: TGLsizei, v: PGLushort){.
+    dynlib: dllname, importc: "glVertexAttribs4hvNV".}
+  #***** GL_ATI_map_object_buffer *****//
+proc glMapObjectBufferATI*(buffer: TGLuint): PGLvoid{.dynlib: dllname,
+    importc: "glMapObjectBufferATI".}
+proc glUnmapObjectBufferATI*(buffer: TGLuint){.dynlib: dllname,
+    importc: "glUnmapObjectBufferATI".}
+  #***** GL_ATI_separate_stencil *****//
+const
+  GL_KEEP* = 0x00001E00
+  GL_ZERO* = 0x00000000
+  GL_REPLACE* = 0x00001E01
+  GL_INCR* = 0x00001E02
+  GL_DECR* = 0x00001E03
+  GL_INVERT* = 0x0000150A
+  GL_NEVER* = 0x00000200
+  GL_LESS* = 0x00000201
+  GL_LEQUAL* = 0x00000203
+  GL_GREATER* = 0x00000204
+  GL_GEQUAL* = 0x00000206
+  GL_EQUAL* = 0x00000202
+  GL_NOTEQUAL* = 0x00000205
+  GL_ALWAYS* = 0x00000207
+  GL_FRONT* = 0x00000404
+  GL_BACK* = 0x00000405
+  GL_FRONT_AND_BACK* = 0x00000408
+  GL_STENCIL_BACK_FUNC_ATI* = 0x00008800
+  GL_STENCIL_BACK_FAIL_ATI* = 0x00008801
+  GL_STENCIL_BACK_PASS_DEPTH_FAIL_ATI* = 0x00008802
+  GL_STENCIL_BACK_PASS_DEPTH_PASS_ATI* = 0x00008803
+
+proc glStencilOpSeparateATI*(face: TGLenum, sfail: TGLenum, dpfail: TGLenum,
+                             dppass: TGLenum){.dynlib: dllname,
+    importc: "glStencilOpSeparateATI".}
+proc glStencilFuncSeparateATI*(frontfunc: TGLenum, backfunc: TGLenum,
+                               theRef: TGLint, mask: TGLuint){.dynlib: dllname,
+    importc: "glStencilFuncSeparateATI".}
+  #***** GL_ATI_vertex_attrib_array_object *****//
+proc glVertexAttribArrayObjectATI*(index: TGLuint, size: TGLint,
+                                   thetype: TGLenum, normalized: TGLboolean,
+                                   stride: TGLsizei, buffer: TGLuint,
+                                   offset: TGLuint){.dynlib: dllname,
+    importc: "glVertexAttribArrayObjectATI".}
+proc glGetVertexAttribArrayObjectfvATI*(index: TGLuint, pname: TGLenum,
+                                        params: PGLfloat){.dynlib: dllname,
+    importc: "glGetVertexAttribArrayObjectfvATI".}
+proc glGetVertexAttribArrayObjectivATI*(index: TGLuint, pname: TGLenum,
+                                        params: PGLint){.dynlib: dllname,
+    importc: "glGetVertexAttribArrayObjectivATI".}
+  #***** GL_ARB_occlusion_query *****//
+const
+  GL_SAMPLES_PASSED_ARB* = 0x00008914
+  GL_QUERY_COUNTER_BITS_ARB* = 0x00008864
+  GL_CURRENT_QUERY_ARB* = 0x00008865
+  GL_QUERY_RESULT_ARB* = 0x00008866
+  GL_QUERY_RESULT_AVAILABLE_ARB* = 0x00008867
+
+proc glGenQueriesARB*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glGenQueriesARB".}
+proc glDeleteQueriesARB*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glDeleteQueriesARB".}
+proc glIsQueryARB*(id: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsQueryARB".}
+proc glBeginQueryARB*(target: TGLenum, id: TGLuint){.dynlib: dllname,
+    importc: "glBeginQueryARB".}
+proc glEndQueryARB*(target: TGLenum){.dynlib: dllname, importc: "glEndQueryARB".}
+proc glGetQueryivARB*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryivARB".}
+proc glGetQueryObjectivARB*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryObjectivARB".}
+proc glGetQueryObjectuivARB*(id: TGLuint, pname: TGLenum, params: PGLuint){.
+    dynlib: dllname, importc: "glGetQueryObjectuivARB".}
+  #***** GL_ARB_shader_objects *****//
+const
+  GL_PROGRAM_OBJECT_ARB* = 0x00008B40
+  GL_OBJECT_TYPE_ARB* = 0x00008B4E
+  GL_OBJECT_SUBTYPE_ARB* = 0x00008B4F
+  GL_OBJECT_DELETE_STATUS_ARB* = 0x00008B80
+  GL_OBJECT_COMPILE_STATUS_ARB* = 0x00008B81
+  GL_OBJECT_LINK_STATUS_ARB* = 0x00008B82
+  GL_OBJECT_VALIDATE_STATUS_ARB* = 0x00008B83
+  GL_OBJECT_INFO_LOG_LENGTH_ARB* = 0x00008B84
+  GL_OBJECT_ATTACHED_OBJECTS_ARB* = 0x00008B85
+  GL_OBJECT_ACTIVE_UNIFORMS_ARB* = 0x00008B86
+  GL_OBJECT_ACTIVE_UNIFORM_MAX_LENGTH_ARB* = 0x00008B87
+  GL_OBJECT_SHADER_SOURCE_LENGTH_ARB* = 0x00008B88
+  GL_SHADER_OBJECT_ARB* = 0x00008B48
+  GL_FLOAT* = 0x00001406
+  GL_FLOAT_VEC2_ARB* = 0x00008B50
+  GL_FLOAT_VEC3_ARB* = 0x00008B51
+  GL_FLOAT_VEC4_ARB* = 0x00008B52
+  GL_INT* = 0x00001404
+  GL_INT_VEC2_ARB* = 0x00008B53
+  GL_INT_VEC3_ARB* = 0x00008B54
+  GL_INT_VEC4_ARB* = 0x00008B55
+  GL_BOOL_ARB* = 0x00008B56
+  GL_BOOL_VEC2_ARB* = 0x00008B57
+  GL_BOOL_VEC3_ARB* = 0x00008B58
+  GL_BOOL_VEC4_ARB* = 0x00008B59
+  GL_FLOAT_MAT2_ARB* = 0x00008B5A
+  GL_FLOAT_MAT3_ARB* = 0x00008B5B
+  GL_FLOAT_MAT4_ARB* = 0x00008B5C
+
+proc glDeleteObjectARB*(obj: GLhandleARB){.dynlib: dllname,
+    importc: "glDeleteObjectARB".}
+proc glGetHandleARB*(pname: TGLenum): GLhandleARB{.dynlib: dllname,
+    importc: "glGetHandleARB".}
+proc glDetachObjectARB*(containerObj: GLhandleARB, attachedObj: GLhandleARB){.
+    dynlib: dllname, importc: "glDetachObjectARB".}
+proc glCreateShaderObjectARB*(shaderType: TGLenum): GLhandleARB{.
+    dynlib: dllname, importc: "glCreateShaderObjectARB".}
+proc glShaderSourceARB*(shaderObj: GLhandleARB, count: TGLsizei, str: PGLvoid,
+                        len: PGLint){.dynlib: dllname,
+                                      importc: "glShaderSourceARB".}
+proc glCompileShaderARB*(shaderObj: GLhandleARB){.dynlib: dllname,
+    importc: "glCompileShaderARB".}
+proc glCreateProgramObjectARB*(): GLhandleARB{.dynlib: dllname,
+    importc: "glCreateProgramObjectARB".}
+proc glAttachObjectARB*(containerObj: GLhandleARB, obj: GLhandleARB){.
+    dynlib: dllname, importc: "glAttachObjectARB".}
+proc glLinkProgramARB*(programObj: GLhandleARB){.dynlib: dllname,
+    importc: "glLinkProgramARB".}
+proc glUseProgramObjectARB*(programObj: GLhandleARB){.dynlib: dllname,
+    importc: "glUseProgramObjectARB".}
+proc glValidateProgramARB*(programObj: GLhandleARB){.dynlib: dllname,
+    importc: "glValidateProgramARB".}
+proc glUniform1fARB*(location: TGLint, v0: TGLfloat){.dynlib: dllname,
+    importc: "glUniform1fARB".}
+proc glUniform2fARB*(location: TGLint, v0: TGLfloat, v1: TGLfloat){.
+    dynlib: dllname, importc: "glUniform2fARB".}
+proc glUniform3fARB*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat){.
+    dynlib: dllname, importc: "glUniform3fARB".}
+proc glUniform4fARB*(location: TGLint, v0: TGLfloat, v1: TGLfloat, v2: TGLfloat,
+                     v3: TGLfloat){.dynlib: dllname, importc: "glUniform4fARB".}
+proc glUniform1iARB*(location: TGLint, v0: TGLint){.dynlib: dllname,
+    importc: "glUniform1iARB".}
+proc glUniform2iARB*(location: TGLint, v0: TGLint, v1: TGLint){.dynlib: dllname,
+    importc: "glUniform2iARB".}
+proc glUniform3iARB*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint){.
+    dynlib: dllname, importc: "glUniform3iARB".}
+proc glUniform4iARB*(location: TGLint, v0: TGLint, v1: TGLint, v2: TGLint,
+                     v3: TGLint){.dynlib: dllname, importc: "glUniform4iARB".}
+proc glUniform1fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform1fvARB".}
+proc glUniform2fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform2fvARB".}
+proc glUniform3fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform3fvARB".}
+proc glUniform4fvARB*(location: TGLint, count: TGLsizei, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniform4fvARB".}
+proc glUniform1ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform1ivARB".}
+proc glUniform2ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform2ivARB".}
+proc glUniform3ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform3ivARB".}
+proc glUniform4ivARB*(location: TGLint, count: TGLsizei, value: PGLint){.
+    dynlib: dllname, importc: "glUniform4ivARB".}
+proc glUniformMatrix2fvARB*(location: TGLint, count: TGLsizei,
+                            transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix2fvARB".}
+proc glUniformMatrix3fvARB*(location: TGLint, count: TGLsizei,
+                            transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix3fvARB".}
+proc glUniformMatrix4fvARB*(location: TGLint, count: TGLsizei,
+                            transpose: TGLboolean, value: PGLfloat){.
+    dynlib: dllname, importc: "glUniformMatrix4fvARB".}
+proc glGetObjectParameterfvARB*(obj: GLhandleARB, pname: TGLenum,
+                                params: PGLfloat){.dynlib: dllname,
+    importc: "glGetObjectParameterfvARB".}
+proc glGetObjectParameterivARB*(obj: GLhandleARB, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetObjectParameterivARB".}
+proc glGetInfoLogARB*(obj: GLhandleARB, maxLength: TGLsizei, len: PGLsizei,
+                      infoLog: PGLcharARB){.dynlib: dllname,
+    importc: "glGetInfoLogARB".}
+proc glGetAttachedObjectsARB*(containerObj: GLhandleARB, maxCount: TGLsizei,
+                              count: PGLsizei, obj: PGLhandleARB){.
+    dynlib: dllname, importc: "glGetAttachedObjectsARB".}
+proc glGetUniformLocationARB*(programObj: GLhandleARB, name: PGLcharARB): TGLint{.
+    dynlib: dllname, importc: "glGetUniformLocationARB".}
+proc glGetActiveUniformARB*(programObj: GLhandleARB, index: TGLuint,
+                            maxLength: TGLsizei, len: PGLsizei, size: PGLint,
+                            thetype: PGLenum, name: PGLcharARB){.
+    dynlib: dllname, importc: "glGetActiveUniformARB".}
+proc glGetUniformfvARB*(programObj: GLhandleARB, location: TGLint,
+                        params: PGLfloat){.dynlib: dllname,
+    importc: "glGetUniformfvARB".}
+proc glGetUniformivARB*(programObj: GLhandleARB, location: TGLint,
+                        params: PGLint){.dynlib: dllname,
+    importc: "glGetUniformivARB".}
+proc glGetShaderSourceARB*(obj: GLhandleARB, maxLength: TGLsizei, len: PGLsizei,
+                           source: PGLcharARB){.dynlib: dllname,
+    importc: "glGetShaderSourceARB".}
+const
+  GL_VERTEX_SHADER_ARB* = 0x00008B31
+  GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB* = 0x00008B4A
+  GL_MAX_VARYING_FLOATS_ARB* = 0x00008B4B # GL_MAX_VERTEX_ATTRIBS_ARB  { already defined }
+                                          # GL_MAX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
+  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB* = 0x00008B4C
+  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB* = 0x00008B4D #
+                                                        #
+                                                        # GL_MAX_TEXTURE_COORDS_ARB  { already defined }
+                                                        #
+                                                        #
+                                                        # GL_VERTEX_PROGRAM_POINT_SIZE_ARB  { already defined }
+                                                        #
+                                                        #
+                                                        # GL_VERTEX_PROGRAM_TWO_SIDE_ARB  { already defined }
+                                                        # GL_OBJECT_TYPE_ARB  { already defined }
+                                                        # GL_OBJECT_SUBTYPE_ARB  { already defined }
+  GL_OBJECT_ACTIVE_ATTRIBUTES_ARB* = 0x00008B89
+  GL_OBJECT_ACTIVE_ATTRIBUTE_MAX_LENGTH_ARB* = 0x00008B8A # GL_SHADER_OBJECT_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_CURRENT_VERTEX_ATTRIB_ARB  { already defined }
+                                                          #
+                                                          #
+                                                          # GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB  { already defined }
+                                                          # GL_FLOAT  { already defined }
+                                                          # GL_FLOAT_VEC2_ARB  { already defined }
+                                                          # GL_FLOAT_VEC3_ARB  { already defined }
+                                                          # GL_FLOAT_VEC4_ARB  { already defined }
+                                                          # GL_FLOAT_MAT2_ARB  { already defined }
+                                                          # GL_FLOAT_MAT3_ARB  { already defined }
+                                                          # GL_FLOAT_MAT4_ARB  { already defined }
+                                                          # glVertexAttrib1fARB  { already defined }
+                                                          # glVertexAttrib1sARB  { already defined }
+                                                          # glVertexAttrib1dARB  { already defined }
+                                                          # glVertexAttrib2fARB  { already defined }
+                                                          # glVertexAttrib2sARB  { already defined }
+                                                          # glVertexAttrib2dARB  { already defined }
+                                                          # glVertexAttrib3fARB  { already defined }
+                                                          # glVertexAttrib3sARB  { already defined }
+                                                          # glVertexAttrib3dARB  { already defined }
+                                                          # glVertexAttrib4fARB  { already defined }
+                                                          # glVertexAttrib4sARB  { already defined }
+                                                          # glVertexAttrib4dARB  { already defined }
+                                                          # glVertexAttrib4NubARB  { already defined }
+                                                          # glVertexAttrib1fvARB  { already defined }
+                                                          # glVertexAttrib1svARB  { already defined }
+                                                          # glVertexAttrib1dvARB  { already defined }
+                                                          # glVertexAttrib2fvARB  { already defined }
+                                                          # glVertexAttrib2svARB  { already defined }
+                                                          # glVertexAttrib2dvARB  { already defined }
+                                                          # glVertexAttrib3fvARB  { already defined }
+                                                          # glVertexAttrib3svARB  { already defined }
+                                                          # glVertexAttrib3dvARB  { already defined }
+                                                          # glVertexAttrib4fvARB  { already defined }
+                                                          # glVertexAttrib4svARB  { already defined }
+                                                          # glVertexAttrib4dvARB  { already defined }
+                                                          # glVertexAttrib4ivARB  { already defined }
+                                                          # glVertexAttrib4bvARB  { already defined }
+                                                          # glVertexAttrib4ubvARB  { already defined }
+                                                          # glVertexAttrib4usvARB  { already defined }
+                                                          # glVertexAttrib4uivARB  { already defined }
+                                                          # glVertexAttrib4NbvARB  { already defined }
+                                                          # glVertexAttrib4NsvARB  { already defined }
+                                                          # glVertexAttrib4NivARB  { already defined }
+                                                          # glVertexAttrib4NubvARB  { already defined }
+                                                          # glVertexAttrib4NusvARB  { already defined }
+                                                          # glVertexAttrib4NuivARB  { already defined }
+                                                          #
+                                                          #
+                                                          # glVertexAttribPointerARB  { already defined }
+                                                          #
+                                                          #
+                                                          # glEnableVertexAttribArrayARB  { already defined }
+                                                          #
+                                                          #
+                                                          # glDisableVertexAttribArrayARB  { already defined }
+
+proc glBindAttribLocationARB*(programObj: GLhandleARB, index: TGLuint,
+                              name: PGLcharARB){.dynlib: dllname,
+    importc: "glBindAttribLocationARB".}
+proc glGetActiveAttribARB*(programObj: GLhandleARB, index: TGLuint,
+                           maxLength: TGLsizei, len: PGLsizei, size: PGLint,
+                           thetype: PGLenum, name: PGLcharARB){.dynlib: dllname,
+    importc: "glGetActiveAttribARB".}
+proc glGetAttribLocationARB*(programObj: GLhandleARB, name: PGLcharARB): TGLint{.
+    dynlib: dllname, importc: "glGetAttribLocationARB".}
+  # glGetVertexAttribdvARB  { already defined }
+  # glGetVertexAttribfvARB  { already defined }
+  # glGetVertexAttribivARB  { already defined }
+  # glGetVertexAttribPointervARB  { already defined }
+  #***** GL_ARB_fragment_shader *****//
+const
+  GL_FRAGMENT_SHADER_ARB* = 0x00008B30
+  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB* = 0x00008B49 # GL_MAX_TEXTURE_COORDS_ARB  { already defined }
+                                                       #
+                                                       #
+                                                       # GL_MAX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
+                                                       # GL_OBJECT_TYPE_ARB  { already defined }
+                                                       # GL_OBJECT_SUBTYPE_ARB  { already defined }
+                                                       # GL_SHADER_OBJECT_ARB  { already defined }
+  #***** GL_ARB_shading_language_100 *****//
+  #***** GL_ARB_texture_non_power_of_two *****//
+  #***** GL_ARB_point_sprite *****//
+
+const
+  GL_POINT_SPRITE_ARB* = 0x00008861
+  GL_COORD_REPLACE_ARB* = 0x00008862
+  #***** GL_EXT_depth_bounds_test *****//
+
+const
+  constGL_DEPTH_BOUNDS_TEST_EXT* = 0x00008890
+  constGL_DEPTH_BOUNDS_EXT* = 0x00008891
+
+proc glDepthBoundsEXT*(zmin: TGLclampd, zmax: TGLclampd){.dynlib: dllname,
+    importc: "glDepthBoundsEXT".}
+  #***** GL_EXT_texture_mirror_clamp *****//
+const
+  GL_MIRROR_CLAMP_EXT* = 0x00008742
+  GL_MIRROR_CLAMP_TO_EDGE_EXT* = 0x00008743
+  GL_MIRROR_CLAMP_TO_BORDER_EXT* = 0x00008912
+  #***** GL_EXT_blend_equation_separate *****//
+
+const
+  GL_BLEND_EQUATION_RGB_EXT* = 0x00008009
+  GL_BLEND_EQUATION_ALPHA_EXT* = 0x0000883D
+
+proc glBlendEquationSeparateEXT*(modeRGB: TGLenum, modeAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendEquationSeparateEXT".}
+  #***** GL_MESA_pack_invert *****//
+const
+  GL_PACK_INVERT_MESA* = 0x00008758
+  #***** GL_MESA_ycbcr_texture *****//
+
+const
+  GL_YCBCR_MESA* = 0x00008757
+  GL_UNSIGNED_SHORT_8_8_MESA* = 0x000085BA
+  GL_UNSIGNED_SHORT_8_8_REV_MESA* = 0x000085BB
+  #***** GL_ARB_fragment_program_shadow *****//
+  #***** GL_NV_fragment_program_option *****//
+  #***** GL_EXT_pixel_buffer_object *****//
+
+const
+  GL_PIXEL_PACK_BUFFER_EXT* = 0x000088EB
+  GL_PIXEL_UNPACK_BUFFER_EXT* = 0x000088EC
+  GL_PIXEL_PACK_BUFFER_BINDING_EXT* = 0x000088ED
+  GL_PIXEL_UNPACK_BUFFER_BINDING_EXT* = 0x000088EF
+  #***** GL_NV_fragment_program2 *****//
+
+const
+  GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV* = 0x000088F4
+  GL_MAX_PROGRAM_CALL_DEPTH_NV* = 0x000088F5
+  GL_MAX_PROGRAM_IF_DEPTH_NV* = 0x000088F6
+  GL_MAX_PROGRAM_LOOP_DEPTH_NV* = 0x000088F7
+  GL_MAX_PROGRAM_LOOP_COUNT_NV* = 0x000088F8
+  #***** GL_NV_vertex_program2_option *****//
+  # GL_MAX_PROGRAM_EXEC_INSTRUCTIONS_NV  { already defined }
+  # GL_MAX_PROGRAM_CALL_DEPTH_NV  { already defined }
+  #***** GL_NV_vertex_program3 *****//
+  # GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB  { already defined }
+  #***** GL_ARB_draw_buffers *****//
+
+const
+  GL_MAX_DRAW_BUFFERS_ARB* = 0x00008824
+  GL_DRAW_BUFFER0_ARB* = 0x00008825
+  GL_DRAW_BUFFER1_ARB* = 0x00008826
+  GL_DRAW_BUFFER2_ARB* = 0x00008827
+  GL_DRAW_BUFFER3_ARB* = 0x00008828
+  GL_DRAW_BUFFER4_ARB* = 0x00008829
+  GL_DRAW_BUFFER5_ARB* = 0x0000882A
+  GL_DRAW_BUFFER6_ARB* = 0x0000882B
+  GL_DRAW_BUFFER7_ARB* = 0x0000882C
+  GL_DRAW_BUFFER8_ARB* = 0x0000882D
+  GL_DRAW_BUFFER9_ARB* = 0x0000882E
+  GL_DRAW_BUFFER10_ARB* = 0x0000882F
+  GL_DRAW_BUFFER11_ARB* = 0x00008830
+  GL_DRAW_BUFFER12_ARB* = 0x00008831
+  GL_DRAW_BUFFER13_ARB* = 0x00008832
+  GL_DRAW_BUFFER14_ARB* = 0x00008833
+  GL_DRAW_BUFFER15_ARB* = 0x00008834
+
+proc glDrawBuffersARB*(n: TGLsizei, bufs: PGLenum){.dynlib: dllname,
+    importc: "glDrawBuffersARB".}
+  #***** GL_ARB_texture_rectangle *****//
+const
+  GL_TEXTURE_RECTANGLE_ARB* = 0x000084F5
+  GL_TEXTURE_BINDING_RECTANGLE_ARB* = 0x000084F6
+  GL_PROXY_TEXTURE_RECTANGLE_ARB* = 0x000084F7
+  GL_MAX_RECTANGLE_TEXTURE_SIZE_ARB* = 0x000084F8
+  #***** GL_ARB_color_buffer_float *****//
+
+const
+  GL_RGBA_FLOAT_MODE_ARB* = 0x00008820
+  GL_CLAMP_VERTEX_COLOR_ARB* = 0x0000891A
+  GL_CLAMP_FRAGMENT_COLOR_ARB* = 0x0000891B
+  GL_CLAMP_READ_COLOR_ARB* = 0x0000891C
+  GL_FIXED_ONLY_ARB* = 0x0000891D
+  WGL_TYPE_RGBA_FLOAT_ARB* = 0x000021A0
+
+proc glClampColorARB*(target: TGLenum, clamp: TGLenum){.dynlib: dllname,
+    importc: "glClampColorARB".}
+  #***** GL_ARB_half_float_pixel *****//
+const
+  GL_HALF_FLOAT_ARB* = 0x0000140B
+  #***** GL_ARB_texture_float *****//
+
+const
+  GL_TEXTURE_RED_TYPE_ARB* = 0x00008C10
+  GL_TEXTURE_GREEN_TYPE_ARB* = 0x00008C11
+  GL_TEXTURE_BLUE_TYPE_ARB* = 0x00008C12
+  GL_TEXTURE_ALPHA_TYPE_ARB* = 0x00008C13
+  GL_TEXTURE_LUMINANCE_TYPE_ARB* = 0x00008C14
+  GL_TEXTURE_INTENSITY_TYPE_ARB* = 0x00008C15
+  GL_TEXTURE_DEPTH_TYPE_ARB* = 0x00008C16
+  GL_UNSIGNED_NORMALIZED_ARB* = 0x00008C17
+  GL_RGBA32F_ARB* = 0x00008814
+  GL_RGB32F_ARB* = 0x00008815
+  GL_ALPHA32F_ARB* = 0x00008816
+  GL_INTENSITY32F_ARB* = 0x00008817
+  GL_LUMINANCE32F_ARB* = 0x00008818
+  GL_LUMINANCE_ALPHA32F_ARB* = 0x00008819
+  GL_RGBA16F_ARB* = 0x0000881A
+  GL_RGB16F_ARB* = 0x0000881B
+  GL_ALPHA16F_ARB* = 0x0000881C
+  GL_INTENSITY16F_ARB* = 0x0000881D
+  GL_LUMINANCE16F_ARB* = 0x0000881E
+  GL_LUMINANCE_ALPHA16F_ARB* = 0x0000881F
+  #***** GL_EXT_texture_compression_dxt1 *****//
+  # GL_COMPRESSED_RGB_S3TC_DXT1_EXT  { already defined }
+  # GL_COMPRESSED_RGBA_S3TC_DXT1_EXT  { already defined }
+  #***** GL_ARB_pixel_buffer_object *****//
+
+const
+  GL_PIXEL_PACK_BUFFER_ARB* = 0x000088EB
+  GL_PIXEL_UNPACK_BUFFER_ARB* = 0x000088EC
+  GL_PIXEL_PACK_BUFFER_BINDING_ARB* = 0x000088ED
+  GL_PIXEL_UNPACK_BUFFER_BINDING_ARB* = 0x000088EF
+  #***** GL_EXT_framebuffer_object *****//
+
+const
+  GL_FRAMEBUFFER_EXT* = 0x00008D40
+  GL_RENDERBUFFER_EXT* = 0x00008D41
+  GL_STENCIL_INDEX_EXT* = 0x00008D45
+  GL_STENCIL_INDEX1_EXT* = 0x00008D46
+  GL_STENCIL_INDEX4_EXT* = 0x00008D47
+  GL_STENCIL_INDEX8_EXT* = 0x00008D48
+  GL_STENCIL_INDEX16_EXT* = 0x00008D49
+  GL_RENDERBUFFER_WIDTH_EXT* = 0x00008D42
+  GL_RENDERBUFFER_HEIGHT_EXT* = 0x00008D43
+  GL_RENDERBUFFER_INTERNAL_FORMAT_EXT* = 0x00008D44
+  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT* = 0x00008CD0
+  GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT* = 0x00008CD1
+  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT* = 0x00008CD2
+  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT* = 0x00008CD3
+  GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT* = 0x00008CD4
+  GL_COLOR_ATTACHMENT0_EXT* = 0x00008CE0
+  GL_COLOR_ATTACHMENT1_EXT* = 0x00008CE1
+  GL_COLOR_ATTACHMENT2_EXT* = 0x00008CE2
+  GL_COLOR_ATTACHMENT3_EXT* = 0x00008CE3
+  GL_COLOR_ATTACHMENT4_EXT* = 0x00008CE4
+  GL_COLOR_ATTACHMENT5_EXT* = 0x00008CE5
+  GL_COLOR_ATTACHMENT6_EXT* = 0x00008CE6
+  GL_COLOR_ATTACHMENT7_EXT* = 0x00008CE7
+  GL_COLOR_ATTACHMENT8_EXT* = 0x00008CE8
+  GL_COLOR_ATTACHMENT9_EXT* = 0x00008CE9
+  GL_COLOR_ATTACHMENT10_EXT* = 0x00008CEA
+  GL_COLOR_ATTACHMENT11_EXT* = 0x00008CEB
+  GL_COLOR_ATTACHMENT12_EXT* = 0x00008CEC
+  GL_COLOR_ATTACHMENT13_EXT* = 0x00008CED
+  GL_COLOR_ATTACHMENT14_EXT* = 0x00008CEE
+  GL_COLOR_ATTACHMENT15_EXT* = 0x00008CEF
+  GL_DEPTH_ATTACHMENT_EXT* = 0x00008D00
+  GL_STENCIL_ATTACHMENT_EXT* = 0x00008D20
+  GL_FRAMEBUFFER_COMPLETE_EXT* = 0x00008CD5
+  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT* = 0x00008CD6
+  GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT* = 0x00008CD7
+  GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT* = 0x00008CD8
+  GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT* = 0x00008CD9
+  GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT* = 0x00008CDA
+  GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT* = 0x00008CDB
+  GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT* = 0x00008CDC
+  GL_FRAMEBUFFER_UNSUPPORTED_EXT* = 0x00008CDD
+  GL_FRAMEBUFFER_STATUS_ERROR_EXT* = 0x00008CDE
+  GL_FRAMEBUFFER_BINDING_EXT* = 0x00008CA6
+  GL_RENDERBUFFER_BINDING_EXT* = 0x00008CA7
+  GL_MAX_COLOR_ATTACHMENTS_EXT* = 0x00008CDF
+  GL_MAX_RENDERBUFFER_SIZE_EXT* = 0x000084E8
+  GL_INVALID_FRAMEBUFFER_OPERATION_EXT* = 0x00000506
+
+proc glIsRenderbufferEXT*(renderbuffer: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsRenderbufferEXT".}
+proc glBindRenderbufferEXT*(target: TGLenum, renderbuffer: TGLuint){.
+    dynlib: dllname, importc: "glBindRenderbufferEXT".}
+proc glDeleteRenderbuffersEXT*(n: TGLsizei, renderbuffers: PGLuint){.
+    dynlib: dllname, importc: "glDeleteRenderbuffersEXT".}
+proc glGenRenderbuffersEXT*(n: TGLsizei, renderbuffers: PGLuint){.
+    dynlib: dllname, importc: "glGenRenderbuffersEXT".}
+proc glRenderbufferStorageEXT*(target: TGLenum, internalformat: TGLenum,
+                               width: TGLsizei, height: TGLsizei){.
+    dynlib: dllname, importc: "glRenderbufferStorageEXT".}
+proc glGetRenderbufferParameterivEXT*(target: TGLenum, pname: TGLenum,
+                                      params: PGLint){.dynlib: dllname,
+    importc: "glGetRenderbufferParameterivEXT".}
+proc glIsFramebufferEXT*(framebuffer: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsFramebufferEXT".}
+proc glBindFramebufferEXT*(target: TGLenum, framebuffer: TGLuint){.
+    dynlib: dllname, importc: "glBindFramebufferEXT".}
+proc glDeleteFramebuffersEXT*(n: TGLsizei, framebuffers: PGLuint){.
+    dynlib: dllname, importc: "glDeleteFramebuffersEXT".}
+proc glGenFramebuffersEXT*(n: TGLsizei, framebuffers: PGLuint){.dynlib: dllname,
+    importc: "glGenFramebuffersEXT".}
+proc glCheckFramebufferStatusEXT*(target: TGLenum): TGLenum{.dynlib: dllname,
+    importc: "glCheckFramebufferStatusEXT".}
+proc glFramebufferTexture1DEXT*(target: TGLenum, attachment: TGLenum,
+                                textarget: TGLenum, texture: TGLuint,
+                                level: TGLint){.dynlib: dllname,
+    importc: "glFramebufferTexture1DEXT".}
+proc glFramebufferTexture2DEXT*(target: TGLenum, attachment: TGLenum,
+                                textarget: TGLenum, texture: TGLuint,
+                                level: TGLint){.dynlib: dllname,
+    importc: "glFramebufferTexture2DEXT".}
+proc glFramebufferTexture3DEXT*(target: TGLenum, attachment: TGLenum,
+                                textarget: TGLenum, texture: TGLuint,
+                                level: TGLint, zoffset: TGLint){.
+    dynlib: dllname, importc: "glFramebufferTexture3DEXT".}
+proc glFramebufferRenderbufferEXT*(target: TGLenum, attachment: TGLenum,
+                                   renderbuffertarget: TGLenum,
+                                   renderbuffer: TGLuint){.dynlib: dllname,
+    importc: "glFramebufferRenderbufferEXT".}
+proc glGetFramebufferAttachmentParameterivEXT*(target: TGLenum,
+    attachment: TGLenum, pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glGetFramebufferAttachmentParameterivEXT".}
+proc glGenerateMipmapEXT*(target: TGLenum){.dynlib: dllname,
+    importc: "glGenerateMipmapEXT".}
+  #***** GL_version_1_4 *****//
+const
+  GL_BLEND_DST_RGB* = 0x000080C8
+  GL_BLEND_SRC_RGB* = 0x000080C9
+  GL_BLEND_DST_ALPHA* = 0x000080CA
+  GL_BLEND_SRC_ALPHA* = 0x000080CB
+  GL_POINT_SIZE_MIN* = 0x00008126
+  GL_POINT_SIZE_MAX* = 0x00008127
+  GL_POINT_FADE_THRESHOLD_SIZE* = 0x00008128
+  GL_POINT_DISTANCE_ATTENUATION* = 0x00008129
+  GL_GENERATE_MIPMAP* = 0x00008191
+  GL_GENERATE_MIPMAP_HINT* = 0x00008192
+  GL_DEPTH_COMPONENT16* = 0x000081A5
+  GL_DEPTH_COMPONENT24* = 0x000081A6
+  GL_DEPTH_COMPONENT32* = 0x000081A7
+  GL_MIRRORED_REPEAT* = 0x00008370
+  GL_FOG_COORDINATE_SOURCE* = 0x00008450
+  GL_FOG_COORDINATE* = 0x00008451
+  GL_FRAGMENT_DEPTH* = 0x00008452
+  GL_CURRENT_FOG_COORDINATE* = 0x00008453
+  GL_FOG_COORDINATE_ARRAY_TYPE* = 0x00008454
+  GL_FOG_COORDINATE_ARRAY_STRIDE* = 0x00008455
+  GL_FOG_COORDINATE_ARRAY_POINTER* = 0x00008456
+  GL_FOG_COORDINATE_ARRAY* = 0x00008457
+  GL_COLOR_SUM* = 0x00008458
+  GL_CURRENT_SECONDARY_COLOR* = 0x00008459
+  GL_SECONDARY_COLOR_ARRAY_SIZE* = 0x0000845A
+  GL_SECONDARY_COLOR_ARRAY_TYPE* = 0x0000845B
+  GL_SECONDARY_COLOR_ARRAY_STRIDE* = 0x0000845C
+  GL_SECONDARY_COLOR_ARRAY_POINTER* = 0x0000845D
+  GL_SECONDARY_COLOR_ARRAY* = 0x0000845E
+  GL_MAX_TEXTURE_LOD_BIAS* = 0x000084FD
+  GL_TEXTURE_FILTER_CONTROL* = 0x00008500
+  GL_TEXTURE_LOD_BIAS* = 0x00008501
+  GL_INCR_WRAP* = 0x00008507
+  GL_DECR_WRAP* = 0x00008508
+  GL_TEXTURE_DEPTH_SIZE* = 0x0000884A
+  GL_DEPTH_TEXTURE_MODE* = 0x0000884B
+  GL_TEXTURE_COMPARE_MODE* = 0x0000884C
+  GL_TEXTURE_COMPARE_FUNC* = 0x0000884D
+  GL_COMPARE_R_TO_TEXTURE* = 0x0000884E
+
+proc glBlendFuncSeparate*(sfactorRGB: TGLenum, dfactorRGB: TGLenum,
+                          sfactorAlpha: TGLenum, dfactorAlpha: TGLenum){.
+    dynlib: dllname, importc: "glBlendFuncSeparate".}
+proc glFogCoordf*(coord: TGLfloat){.dynlib: dllname, importc: "glFogCoordf".}
+proc glFogCoordfv*(coord: PGLfloat){.dynlib: dllname, importc: "glFogCoordfv".}
+proc glFogCoordd*(coord: TGLdouble){.dynlib: dllname, importc: "glFogCoordd".}
+proc glFogCoorddv*(coord: PGLdouble){.dynlib: dllname, importc: "glFogCoorddv".}
+proc glFogCoordPointer*(thetype: TGLenum, stride: TGLsizei, pointer: PGLvoid){.
+    dynlib: dllname, importc: "glFogCoordPointer".}
+proc glMultiDrawArrays*(mode: TGLenum, first: PGLint, count: PGLsizei,
+                        primcount: TGLsizei){.dynlib: dllname,
+    importc: "glMultiDrawArrays".}
+proc glMultiDrawElements*(mode: TGLenum, count: PGLsizei, thetype: TGLenum,
+                          indices: PGLvoid, primcount: TGLsizei){.
+    dynlib: dllname, importc: "glMultiDrawElements".}
+proc glPointParameterf*(pname: TGLenum, param: TGLfloat){.dynlib: dllname,
+    importc: "glPointParameterf".}
+proc glPointParameterfv*(pname: TGLenum, params: PGLfloat){.dynlib: dllname,
+    importc: "glPointParameterfv".}
+proc glPointParameteri*(pname: TGLenum, param: TGLint){.dynlib: dllname,
+    importc: "glPointParameteri".}
+proc glPointParameteriv*(pname: TGLenum, params: PGLint){.dynlib: dllname,
+    importc: "glPointParameteriv".}
+proc glSecondaryColor3b*(red: TGLByte, green: TGLByte, blue: TGLByte){.
+    dynlib: dllname, importc: "glSecondaryColor3b".}
+proc glSecondaryColor3bv*(v: PGLbyte){.dynlib: dllname,
+                                       importc: "glSecondaryColor3bv".}
+proc glSecondaryColor3d*(red: TGLdouble, green: TGLdouble, blue: TGLdouble){.
+    dynlib: dllname, importc: "glSecondaryColor3d".}
+proc glSecondaryColor3dv*(v: PGLdouble){.dynlib: dllname,
+    importc: "glSecondaryColor3dv".}
+proc glSecondaryColor3f*(red: TGLfloat, green: TGLfloat, blue: TGLfloat){.
+    dynlib: dllname, importc: "glSecondaryColor3f".}
+proc glSecondaryColor3fv*(v: PGLfloat){.dynlib: dllname,
+                                        importc: "glSecondaryColor3fv".}
+proc glSecondaryColor3i*(red: TGLint, green: TGLint, blue: TGLint){.
+    dynlib: dllname, importc: "glSecondaryColor3i".}
+proc glSecondaryColor3iv*(v: PGLint){.dynlib: dllname,
+                                      importc: "glSecondaryColor3iv".}
+proc glSecondaryColor3s*(red: TGLshort, green: TGLshort, blue: TGLshort){.
+    dynlib: dllname, importc: "glSecondaryColor3s".}
+proc glSecondaryColor3sv*(v: PGLshort){.dynlib: dllname,
+                                        importc: "glSecondaryColor3sv".}
+proc glSecondaryColor3ub*(red: TGLubyte, green: TGLubyte, blue: TGLubyte){.
+    dynlib: dllname, importc: "glSecondaryColor3ub".}
+proc glSecondaryColor3ubv*(v: PGLubyte){.dynlib: dllname,
+    importc: "glSecondaryColor3ubv".}
+proc glSecondaryColor3ui*(red: TGLuint, green: TGLuint, blue: TGLuint){.
+    dynlib: dllname, importc: "glSecondaryColor3ui".}
+proc glSecondaryColor3uiv*(v: PGLuint){.dynlib: dllname,
+                                        importc: "glSecondaryColor3uiv".}
+proc glSecondaryColor3us*(red: TGLushort, green: TGLushort, blue: TGLushort){.
+    dynlib: dllname, importc: "glSecondaryColor3us".}
+proc glSecondaryColor3usv*(v: PGLushort){.dynlib: dllname,
+    importc: "glSecondaryColor3usv".}
+proc glSecondaryColorPointer*(size: TGLint, thetype: TGLenum, stride: TGLsizei,
+                              pointer: PGLvoid){.dynlib: dllname,
+    importc: "glSecondaryColorPointer".}
+proc glWindowPos2d*(x: TGLdouble, y: TGLdouble){.dynlib: dllname,
+    importc: "glWindowPos2d".}
+proc glWindowPos2dv*(v: PGLdouble){.dynlib: dllname, importc: "glWindowPos2dv".}
+proc glWindowPos2f*(x: TGLfloat, y: TGLfloat){.dynlib: dllname,
+    importc: "glWindowPos2f".}
+proc glWindowPos2fv*(v: PGLfloat){.dynlib: dllname, importc: "glWindowPos2fv".}
+proc glWindowPos2i*(x: TGLint, y: TGLint){.dynlib: dllname,
+    importc: "glWindowPos2i".}
+proc glWindowPos2iv*(v: PGLint){.dynlib: dllname, importc: "glWindowPos2iv".}
+proc glWindowPos2s*(x: TGLshort, y: TGLshort){.dynlib: dllname,
+    importc: "glWindowPos2s".}
+proc glWindowPos2sv*(v: PGLshort){.dynlib: dllname, importc: "glWindowPos2sv".}
+proc glWindowPos3d*(x: TGLdouble, y: TGLdouble, z: TGLdouble){.dynlib: dllname,
+    importc: "glWindowPos3d".}
+proc glWindowPos3dv*(v: PGLdouble){.dynlib: dllname, importc: "glWindowPos3dv".}
+proc glWindowPos3f*(x: TGLfloat, y: TGLfloat, z: TGLfloat){.dynlib: dllname,
+    importc: "glWindowPos3f".}
+proc glWindowPos3fv*(v: PGLfloat){.dynlib: dllname, importc: "glWindowPos3fv".}
+proc glWindowPos3i*(x: TGLint, y: TGLint, z: TGLint){.dynlib: dllname,
+    importc: "glWindowPos3i".}
+proc glWindowPos3iv*(v: PGLint){.dynlib: dllname, importc: "glWindowPos3iv".}
+proc glWindowPos3s*(x: TGLshort, y: TGLshort, z: TGLshort){.dynlib: dllname,
+    importc: "glWindowPos3s".}
+proc glWindowPos3sv*(v: PGLshort){.dynlib: dllname, importc: "glWindowPos3sv".}
+  #***** GL_version_1_5 *****//
+const
+  GL_BUFFER_SIZE* = 0x00008764
+  GL_BUFFER_USAGE* = 0x00008765
+  GL_QUERY_COUNTER_BITS* = 0x00008864
+  GL_CURRENT_QUERY* = 0x00008865
+  GL_QUERY_RESULT* = 0x00008866
+  GL_QUERY_RESULT_AVAILABLE* = 0x00008867
+  GL_ARRAY_BUFFER* = 0x00008892
+  GL_ELEMENT_ARRAY_BUFFER* = 0x00008893
+  GL_ARRAY_BUFFER_BINDING* = 0x00008894
+  GL_ELEMENT_ARRAY_BUFFER_BINDING* = 0x00008895
+  GL_VERTEX_ARRAY_BUFFER_BINDING* = 0x00008896
+  GL_NORMAL_ARRAY_BUFFER_BINDING* = 0x00008897
+  GL_COLOR_ARRAY_BUFFER_BINDING* = 0x00008898
+  GL_INDEX_ARRAY_BUFFER_BINDING* = 0x00008899
+  GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING* = 0x0000889A
+  GL_EDGE_FLAG_ARRAY_BUFFER_BINDING* = 0x0000889B
+  GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING* = 0x0000889C
+  GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING* = 0x0000889D
+  GL_WEIGHT_ARRAY_BUFFER_BINDING* = 0x0000889E
+  GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING* = 0x0000889F
+  GL_READ_ONLY* = 0x000088B8
+  GL_WRITE_ONLY* = 0x000088B9
+  GL_READ_WRITE* = 0x000088BA
+  GL_BUFFER_ACCESS* = 0x000088BB
+  GL_BUFFER_MAPPED* = 0x000088BC
+  GL_BUFFER_MAP_POINTER* = 0x000088BD
+  GL_STREAM_DRAW* = 0x000088E0
+  GL_STREAM_READ* = 0x000088E1
+  GL_STREAM_COPY* = 0x000088E2
+  GL_STATIC_DRAW* = 0x000088E4
+  GL_STATIC_READ* = 0x000088E5
+  GL_STATIC_COPY* = 0x000088E6
+  GL_DYNAMIC_DRAW* = 0x000088E8
+  GL_DYNAMIC_READ* = 0x000088E9
+  GL_DYNAMIC_COPY* = 0x000088EA
+  GL_SAMPLES_PASSED* = 0x00008914
+  GL_FOG_COORD_SRC* = 0x00008450
+  GL_FOG_COORD* = 0x00008451
+  GL_CURRENT_FOG_COORD* = 0x00008453
+  GL_FOG_COORD_ARRAY_TYPE* = 0x00008454
+  GL_FOG_COORD_ARRAY_STRIDE* = 0x00008455
+  GL_FOG_COORD_ARRAY_POINTER* = 0x00008456
+  GL_FOG_COORD_ARRAY* = 0x00008457
+  GL_FOG_COORD_ARRAY_BUFFER_BINDING* = 0x0000889D
+  GL_SRC0_RGB* = 0x00008580
+  GL_SRC1_RGB* = 0x00008581
+  GL_SRC2_RGB* = 0x00008582
+  GL_SRC0_ALPHA* = 0x00008588
+  GL_SRC1_ALPHA* = 0x00008589
+  GL_SRC2_ALPHA* = 0x0000858A
+
+proc glGenQueries*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glGenQueries".}
+proc glDeleteQueries*(n: TGLsizei, ids: PGLuint){.dynlib: dllname,
+    importc: "glDeleteQueries".}
+proc glIsQuery*(id: TGLuint): TGLboolean{.dynlib: dllname, importc: "glIsQuery".}
+proc glBeginQuery*(target: TGLenum, id: TGLuint){.dynlib: dllname,
+    importc: "glBeginQuery".}
+proc glEndQuery*(target: TGLenum){.dynlib: dllname, importc: "glEndQuery".}
+proc glGetQueryiv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryiv".}
+proc glGetQueryObjectiv*(id: TGLuint, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetQueryObjectiv".}
+proc glGetQueryObjectuiv*(id: TGLuint, pname: TGLenum, params: PGLuint){.
+    dynlib: dllname, importc: "glGetQueryObjectuiv".}
+proc glBindBuffer*(target: TGLenum, buffer: TGLuint){.dynlib: dllname,
+    importc: "glBindBuffer".}
+proc glDeleteBuffers*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname,
+    importc: "glDeleteBuffers".}
+proc glGenBuffers*(n: TGLsizei, buffers: PGLuint){.dynlib: dllname,
+    importc: "glGenBuffers".}
+proc glIsBuffer*(buffer: TGLuint): TGLboolean{.dynlib: dllname,
+    importc: "glIsBuffer".}
+proc glBufferData*(target: TGLenum, size: GLsizeiptr, data: PGLvoid,
+                   usage: TGLenum){.dynlib: dllname, importc: "glBufferData".}
+proc glBufferSubData*(target: TGLenum, offset: GLintptr, size: GLsizeiptr,
+                      data: PGLvoid){.dynlib: dllname,
+                                      importc: "glBufferSubData".}
+proc glGetBufferSubData*(target: TGLenum, offset: GLintptr, size: GLsizeiptr,
+                         data: PGLvoid){.dynlib: dllname,
+    importc: "glGetBufferSubData".}
+proc glMapBuffer*(target: TGLenum, access: TGLenum): PGLvoid{.dynlib: dllname,
+    importc: "glMapBuffer".}
+proc glUnmapBuffer*(target: TGLenum): TGLboolean{.dynlib: dllname,
+    importc: "glUnmapBuffer".}
+proc glGetBufferParameteriv*(target: TGLenum, pname: TGLenum, params: PGLint){.
+    dynlib: dllname, importc: "glGetBufferParameteriv".}
+proc glGetBufferPointerv*(target: TGLenum, pname: TGLenum, params: PGLvoid){.
+    dynlib: dllname, importc: "glGetBufferPointerv".}
+  #***** GL_version_2_0 *****//
+const
+  GL_BLEND_EQUATION_RGB* = 0x00008009
+  GL_VERTEX_ATTRIB_ARRAY_ENABLED* = 0x00008622
+  GL_VERTEX_ATTRIB_ARRAY_SIZE* = 0x00008623
+  GL_VERTEX_ATTRIB_ARRAY_STRIDE* = 0x00008624
+  GL_VERTEX_ATTRIB_ARRAY_TYPE* = 0x00008625
+  GL_CURRENT_VERTEX_ATTRIB* = 0x00008626
+  GL_VERTEX_PROGRAM_POINT_SIZE* = 0x00008642
+  GL_VERTEX_PROGRAM_TWO_SIDE* = 0x00008643
+  GL_VERTEX_ATTRIB_ARRAY_POINTER* = 0x00008645
+  GL_STENCIL_BACK_FUNC* = 0x00008800
+  GL_STENCIL_BACK_FAIL* = 0x00008801
+  GL_STENCIL_BACK_PASS_DEPTH_FAIL* = 0x00008802
+  GL_STENCIL_BACK_PASS_DEPTH_PASS* = 0x00008803
+  GL_MAX_DRAW_BUFFERS* = 0x00008824
+  GL_DRAW_BUFFER0* = 0x00008825
+  GL_DRAW_BUFFER1* = 0x00008826
+  GL_DRAW_BUFFER2* = 0x00008827
+  GL_DRAW_BUFFER3* = 0x00008828
+  GL_DRAW_BUFFER4* = 0x00008829
+  GL_DRAW_BUFFER5* = 0x0000882A
+  GL_DRAW_BUFFER6* = 0x0000882B
+  GL_DRAW_BUFFER7* = 0x0000882C
+  GL_DRAW_BUFFER8* = 0x0000882D
+  GL_DRAW_BUFFER9* = 0x0000882E
+  GL_DRAW_BUFFER10* = 0x0000882F
+  GL_DRAW_BUFFER11* = 0x00008830
+  GL_DRAW_BUFFER12* = 0x00008831
+  GL_DRAW_BUFFER13* = 0x00008832
+  GL_DRAW_BUFFER14* = 0x00008833
+  GL_DRAW_BUFFER15* = 0x00008834
+  GL_BLEND_EQUATION_ALPHA* = 0x0000883D
+  GL_POINT_SPRITE* = 0x00008861
+  GL_COORD_REPLACE* = 0x00008862
+  GL_MAX_VERTEX_ATTRIBS* = 0x00008869
+  GL_VERTEX_ATTRIB_ARRAY_NORMALIZED* = 0x0000886A
+  GL_MAX_TEXTURE_COORDS* = 0x00008871
+  GL_MAX_TEXTURE_IMAGE_UNITS* = 0x00008872
+  GL_FRAGMENT_SHADER* = 0x00008B30
+  GL_VERTEX_SHADER* = 0x00008B31
+  GL_MAX_FRAGMENT_UNIFORM_COMPONENTS* = 0x00008B49
+  GL_MAX_VERTEX_UNIFORM_COMPONENTS* = 0x00008B4A
+  GL_MAX_VARYING_FLOATS* = 0x00008B4B
+  GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS* = 0x00008B4C
+  GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS* = 0x00008B4D
+  GL_SHADER_TYPE* = 0x00008B4F
+  GL_FLOAT_VEC2* = 0x00008B50
+  GL_FLOAT_VEC3* = 0x00008B51
+  GL_FLOAT_VEC4* = 0x00008B52
+  GL_INT_VEC2* = 0x00008B53
+  GL_INT_VEC3* = 0x00008B54
+  GL_INT_VEC4* = 0x00008B55
+  GL_BOOL* = 0x00008B56
+  GL_BOOL_VEC2* = 0x00008B57
+  GL_BOOL_VEC3* = 0x00008B58
+  GL_BOOL_VEC4* = 0x00008B59
+  GL_FLOAT_MAT2* = 0x00008B5A
+  GL_FLOAT_MAT3* = 0x00008B5B
+  GL_FLOAT_MAT4* = 0x00008B5C
+  GL_SAMPLER_1D* = 0x00008B5D
+  GL_SAMPLER_2D* = 0x00008B5E
+  GL_SAMPLER_3D* = 0x00008B5F
+  GL_SAMPLER_CUBE* = 0x00008B60
+  GL_SAMPLER_1D_SHADOW* = 0x00008B61
+  GL_SAMPLER_2D_SHADOW* = 0x00008B62
+  GL_DELETE_STATUS* = 0x00008B80
+  GL_COMPILE_STATUS* = 0x00008B81
+  GL_LINK_STATUS* = 0x00008B82
+  GL_VALIDATE_STATUS* = 0x00008B83
+  GL_INFO_LOG_LENGTH* = 0x00008B84
+  GL_ATTACHED_SHADERS* = 0x00008B85
+  GL_ACTIVE_UNIFORMS* = 0x00008B86
+  GL_ACTIVE_UNIFORM_MAX_LENGTH* = 0x00008B87
+  GL_SHADER_SOURCE_LENGTH* = 0x00008B88
+  GL_ACTIVE_ATTRIBUTES* = 0x00008B89
+  GL_ACTIVE_ATTRIBUTE_MAX_LENGTH* = 0x00008B8A
+  GL_FRAGMENT_SHADER_DERIVATIVE_HINT* = 0x00008B8B
+  GL_SHADING_LANGUAGE_VERSION* = 0x00008B8C
+  GL_CURRENT_PROGRAM* = 0x00008B8D
+  GL_POINT_SPRITE_COORD_ORIGIN* = 0x00008CA0
+  GL_LOWER_LEFT* = 0x00008CA1
+  GL_UPPER_LEFT* = 0x00008CA2
+  GL_STENCIL_BACK_REF* = 0x00008CA3
+  GL_STENCIL_BACK_VALUE_MASK* = 0x00008CA4
+  GL_STENCIL_BACK_WRITEMASK* = 0x00008CA5
+
+{.pop.}
diff --git a/tests/manyloc/keineschweine/lib/glu.nim b/tests/manyloc/keineschweine/lib/glu.nim
new file mode 100644
index 000000000..867d0e47f
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glu.nim
@@ -0,0 +1,335 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#******************************************************************************
+# Converted to Delphi by Tom Nuydens (tom@delphi3d.net)
+# For the latest updates, visit Delphi3D: http://www.delphi3d.net
+#******************************************************************************
+
+import
+  GL
+
+when defined(windows):
+  {.push, callconv: stdcall.}
+else:
+  {.push, callconv: cdecl.}
+
+when defined(windows):
+  const
+    dllname = "glu32.dll"
+elif defined(macosx):
+  const
+    dllname = "/System/Library/Frameworks/OpenGL.framework/Libraries/libGLU.dylib"
+else:
+  const
+    dllname = "libGLU.so.1"
+type
+  TViewPortArray* = array[0..3, TGLint]
+  T16dArray* = array[0..15, TGLdouble]
+  TCallBack* = proc ()
+  T3dArray* = array[0..2, TGLdouble]
+  T4pArray* = array[0..3, Pointer]
+  T4fArray* = array[0..3, TGLfloat]
+  PPointer* = ptr Pointer
+
+type
+  GLUnurbs*{.final.} = object
+  PGLUnurbs* = ptr GLUnurbs
+  GLUquadric*{.final.} = object
+  PGLUquadric* = ptr GLUquadric
+  GLUtesselator*{.final.} = object
+  PGLUtesselator* = ptr GLUtesselator # backwards compatibility:
+  GLUnurbsObj* = GLUnurbs
+  PGLUnurbsObj* = PGLUnurbs
+  GLUquadricObj* = GLUquadric
+  PGLUquadricObj* = PGLUquadric
+  GLUtesselatorObj* = GLUtesselator
+  PGLUtesselatorObj* = PGLUtesselator
+  GLUtriangulatorObj* = GLUtesselator
+  PGLUtriangulatorObj* = PGLUtesselator
+  TGLUnurbs* = GLUnurbs
+  TGLUquadric* = GLUquadric
+  TGLUtesselator* = GLUtesselator
+  TGLUnurbsObj* = GLUnurbsObj
+  TGLUquadricObj* = GLUquadricObj
+  TGLUtesselatorObj* = GLUtesselatorObj
+  TGLUtriangulatorObj* = GLUtriangulatorObj
+
+proc gluErrorString*(errCode: TGLenum): cstring{.dynlib: dllname,
+    importc: "gluErrorString".}
+proc gluErrorUnicodeStringEXT*(errCode: TGLenum): ptr int16{.dynlib: dllname,
+    importc: "gluErrorUnicodeStringEXT".}
+proc gluGetString*(name: TGLenum): cstring{.dynlib: dllname,
+    importc: "gluGetString".}
+proc gluOrtho2D*(left, right, bottom, top: TGLdouble){.dynlib: dllname,
+    importc: "gluOrtho2D".}
+proc gluPerspective*(fovy, aspect, zNear, zFar: TGLdouble){.dynlib: dllname,
+    importc: "gluPerspective".}
+proc gluPickMatrix*(x, y, width, height: TGLdouble, viewport: var TViewPortArray){.
+    dynlib: dllname, importc: "gluPickMatrix".}
+proc gluLookAt*(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz: TGLdouble){.
+    dynlib: dllname, importc: "gluLookAt".}
+proc gluProject*(objx, objy, objz: TGLdouble,
+                 modelMatrix, projMatrix: var T16dArray,
+                 viewport: var TViewPortArray, winx, winy, winz: PGLdouble): int{.
+    dynlib: dllname, importc: "gluProject".}
+proc gluUnProject*(winx, winy, winz: TGLdouble,
+                   modelMatrix, projMatrix: var T16dArray,
+                   viewport: var TViewPortArray, objx, objy, objz: PGLdouble): int{.
+    dynlib: dllname, importc: "gluUnProject".}
+proc gluScaleImage*(format: TGLenum, widthin, heightin: TGLint, typein: TGLenum,
+                    datain: Pointer, widthout, heightout: TGLint,
+                    typeout: TGLenum, dataout: Pointer): int{.dynlib: dllname,
+    importc: "gluScaleImage".}
+proc gluBuild1DMipmaps*(target: TGLenum, components, width: TGLint,
+                        format, atype: TGLenum, data: Pointer): int{.
+    dynlib: dllname, importc: "gluBuild1DMipmaps".}
+proc gluBuild2DMipmaps*(target: TGLenum, components, width, height: TGLint,
+                        format, atype: TGLenum, data: Pointer): int{.
+    dynlib: dllname, importc: "gluBuild2DMipmaps".}
+proc gluNewQuadric*(): PGLUquadric{.dynlib: dllname, importc: "gluNewQuadric".}
+proc gluDeleteQuadric*(state: PGLUquadric){.dynlib: dllname,
+    importc: "gluDeleteQuadric".}
+proc gluQuadricNormals*(quadObject: PGLUquadric, normals: TGLenum){.
+    dynlib: dllname, importc: "gluQuadricNormals".}
+proc gluQuadricTexture*(quadObject: PGLUquadric, textureCoords: TGLboolean){.
+    dynlib: dllname, importc: "gluQuadricTexture".}
+proc gluQuadricOrientation*(quadObject: PGLUquadric, orientation: TGLenum){.
+    dynlib: dllname, importc: "gluQuadricOrientation".}
+proc gluQuadricDrawStyle*(quadObject: PGLUquadric, drawStyle: TGLenum){.
+    dynlib: dllname, importc: "gluQuadricDrawStyle".}
+proc gluCylinder*(qobj: PGLUquadric, baseRadius, topRadius, height: TGLdouble,
+                  slices, stacks: TGLint){.dynlib: dllname,
+    importc: "gluCylinder".}
+proc gluDisk*(qobj: PGLUquadric, innerRadius, outerRadius: TGLdouble,
+              slices, loops: TGLint){.dynlib: dllname, importc: "gluDisk".}
+proc gluPartialDisk*(qobj: PGLUquadric, innerRadius, outerRadius: TGLdouble,
+                     slices, loops: TGLint, startAngle, sweepAngle: TGLdouble){.
+    dynlib: dllname, importc: "gluPartialDisk".}
+proc gluSphere*(qobj: PGLuquadric, radius: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "gluSphere".}
+proc gluQuadricCallback*(qobj: PGLUquadric, which: TGLenum, fn: TCallBack){.
+    dynlib: dllname, importc: "gluQuadricCallback".}
+proc gluNewTess*(): PGLUtesselator{.dynlib: dllname, importc: "gluNewTess".}
+proc gluDeleteTess*(tess: PGLUtesselator){.dynlib: dllname,
+    importc: "gluDeleteTess".}
+proc gluTessBeginPolygon*(tess: PGLUtesselator, polygon_data: Pointer){.
+    dynlib: dllname, importc: "gluTessBeginPolygon".}
+proc gluTessBeginContour*(tess: PGLUtesselator){.dynlib: dllname,
+    importc: "gluTessBeginContour".}
+proc gluTessVertex*(tess: PGLUtesselator, coords: var T3dArray, data: Pointer){.
+    dynlib: dllname, importc: "gluTessVertex".}
+proc gluTessEndContour*(tess: PGLUtesselator){.dynlib: dllname,
+    importc: "gluTessEndContour".}
+proc gluTessEndPolygon*(tess: PGLUtesselator){.dynlib: dllname,
+    importc: "gluTessEndPolygon".}
+proc gluTessProperty*(tess: PGLUtesselator, which: TGLenum, value: TGLdouble){.
+    dynlib: dllname, importc: "gluTessProperty".}
+proc gluTessNormal*(tess: PGLUtesselator, x, y, z: TGLdouble){.dynlib: dllname,
+    importc: "gluTessNormal".}
+proc gluTessCallback*(tess: PGLUtesselator, which: TGLenum, fn: TCallBack){.
+    dynlib: dllname, importc: "gluTessCallback".}
+proc gluGetTessProperty*(tess: PGLUtesselator, which: TGLenum, value: PGLdouble){.
+    dynlib: dllname, importc: "gluGetTessProperty".}
+proc gluNewNurbsRenderer*(): PGLUnurbs{.dynlib: dllname,
+                                        importc: "gluNewNurbsRenderer".}
+proc gluDeleteNurbsRenderer*(nobj: PGLUnurbs){.dynlib: dllname,
+    importc: "gluDeleteNurbsRenderer".}
+proc gluBeginSurface*(nobj: PGLUnurbs){.dynlib: dllname,
+                                        importc: "gluBeginSurface".}
+proc gluBeginCurve*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluBeginCurve".}
+proc gluEndCurve*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluEndCurve".}
+proc gluEndSurface*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluEndSurface".}
+proc gluBeginTrim*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluBeginTrim".}
+proc gluEndTrim*(nobj: PGLUnurbs){.dynlib: dllname, importc: "gluEndTrim".}
+proc gluPwlCurve*(nobj: PGLUnurbs, count: TGLint, aarray: PGLfloat,
+                  stride: TGLint, atype: TGLenum){.dynlib: dllname,
+    importc: "gluPwlCurve".}
+proc gluNurbsCurve*(nobj: PGLUnurbs, nknots: TGLint, knot: PGLfloat,
+                    stride: TGLint, ctlarray: PGLfloat, order: TGLint,
+                    atype: TGLenum){.dynlib: dllname, importc: "gluNurbsCurve".}
+proc gluNurbsSurface*(nobj: PGLUnurbs, sknot_count: TGLint, sknot: PGLfloat,
+                      tknot_count: TGLint, tknot: PGLfloat,
+                      s_stride, t_stride: TGLint, ctlarray: PGLfloat,
+                      sorder, torder: TGLint, atype: TGLenum){.dynlib: dllname,
+    importc: "gluNurbsSurface".}
+proc gluLoadSamplingMatrices*(nobj: PGLUnurbs,
+                              modelMatrix, projMatrix: var T16dArray,
+                              viewport: var TViewPortArray){.dynlib: dllname,
+    importc: "gluLoadSamplingMatrices".}
+proc gluNurbsProperty*(nobj: PGLUnurbs, aproperty: TGLenum, value: TGLfloat){.
+    dynlib: dllname, importc: "gluNurbsProperty".}
+proc gluGetNurbsProperty*(nobj: PGLUnurbs, aproperty: TGLenum, value: PGLfloat){.
+    dynlib: dllname, importc: "gluGetNurbsProperty".}
+proc gluNurbsCallback*(nobj: PGLUnurbs, which: TGLenum, fn: TCallBack){.
+    dynlib: dllname, importc: "gluNurbsCallback".}
+  #*** Callback function prototypes ***
+type                          # gluQuadricCallback
+  GLUquadricErrorProc* = proc (p: TGLenum) # gluTessCallback
+  GLUtessBeginProc* = proc (p: TGLenum)
+  GLUtessEdgeFlagProc* = proc (p: TGLboolean)
+  GLUtessVertexProc* = proc (p: Pointer)
+  GLUtessEndProc* = proc ()
+  GLUtessErrorProc* = proc (p: TGLenum)
+  GLUtessCombineProc* = proc (p1: var T3dArray, p2: T4pArray, p3: T4fArray,
+                              p4: PPointer)
+  GLUtessBeginDataProc* = proc (p1: TGLenum, p2: Pointer)
+  GLUtessEdgeFlagDataProc* = proc (p1: TGLboolean, p2: Pointer)
+  GLUtessVertexDataProc* = proc (p1, p2: Pointer)
+  GLUtessEndDataProc* = proc (p: Pointer)
+  GLUtessErrorDataProc* = proc (p1: TGLenum, p2: Pointer)
+  GLUtessCombineDataProc* = proc (p1: var T3dArray, p2: var T4pArray,
+                                  p3: var T4fArray, p4: PPointer, p5: Pointer) #
+                                                                               #
+                                                                               # gluNurbsCallback
+  GLUnurbsErrorProc* = proc (p: TGLenum) #***           Generic constants               ****/
+
+const                         # Version
+  GLU_VERSION_1_1* = 1
+  GLU_VERSION_1_2* = 1        # Errors: (return value 0 = no error)
+  GLU_INVALID_ENUM* = 100900
+  GLU_INVALID_VALUE* = 100901
+  GLU_OUT_OF_MEMORY* = 100902
+  GLU_INCOMPATIBLE_GL_VERSION* = 100903 # StringName
+  GLU_VERSION* = 100800
+  GLU_EXTENSIONS* = 100801    # Boolean
+  GLU_TRUE* = GL_TRUE
+  GLU_FALSE* = GL_FALSE #***           Quadric constants               ****/
+                        # QuadricNormal
+  GLU_SMOOTH* = 100000
+  GLU_FLAT* = 100001
+  GLU_NONE* = 100002          # QuadricDrawStyle
+  GLU_POINT* = 100010
+  GLU_LINE* = 100011
+  GLU_FILL* = 100012
+  GLU_SILHOUETTE* = 100013    # QuadricOrientation
+  GLU_OUTSIDE* = 100020
+  GLU_INSIDE* = 100021        # Callback types:
+                              #      GLU_ERROR       = 100103;
+                              #***           Tesselation constants           ****/
+  GLU_TESS_MAX_COORD* = 1.00000e+150 # TessProperty
+  GLU_TESS_WINDING_RULE* = 100140
+  GLU_TESS_BOUNDARY_ONLY* = 100141
+  GLU_TESS_TOLERANCE* = 100142 # TessWinding
+  GLU_TESS_WINDING_ODD* = 100130
+  GLU_TESS_WINDING_NONZERO* = 100131
+  GLU_TESS_WINDING_POSITIVE* = 100132
+  GLU_TESS_WINDING_NEGATIVE* = 100133
+  GLU_TESS_WINDING_ABS_GEQ_TWO* = 100134 # TessCallback
+  GLU_TESS_BEGIN* = 100100    # void (CALLBACK*)(TGLenum    type)
+  constGLU_TESS_VERTEX* = 100101 # void (CALLBACK*)(void      *data)
+  GLU_TESS_END* = 100102      # void (CALLBACK*)(void)
+  GLU_TESS_ERROR* = 100103    # void (CALLBACK*)(TGLenum    errno)
+  GLU_TESS_EDGE_FLAG* = 100104 # void (CALLBACK*)(TGLboolean boundaryEdge)
+  GLU_TESS_COMBINE* = 100105 # void (CALLBACK*)(TGLdouble  coords[3],
+                             #                                                            void      *data[4],
+                             #                                                            TGLfloat   weight[4],
+                             #                                                            void      **dataOut)
+  GLU_TESS_BEGIN_DATA* = 100106 # void (CALLBACK*)(TGLenum    type,
+                                #                                                            void      *polygon_data)
+  GLU_TESS_VERTEX_DATA* = 100107 # void (CALLBACK*)(void      *data,
+                                 #                                                            void      *polygon_data)
+  GLU_TESS_END_DATA* = 100108 # void (CALLBACK*)(void      *polygon_data)
+  GLU_TESS_ERROR_DATA* = 100109 # void (CALLBACK*)(TGLenum    errno,
+                                #                                                            void      *polygon_data)
+  GLU_TESS_EDGE_FLAG_DATA* = 100110 # void (CALLBACK*)(TGLboolean boundaryEdge,
+                                    #                                                            void      *polygon_data)
+  GLU_TESS_COMBINE_DATA* = 100111 # void (CALLBACK*)(TGLdouble  coords[3],
+                                  #                                                            void      *data[4],
+                                  #                                                            TGLfloat   weight[4],
+                                  #                                                            void      **dataOut,
+                                  #                                                            void      *polygon_data)
+                                  # TessError
+  GLU_TESS_ERROR1* = 100151
+  GLU_TESS_ERROR2* = 100152
+  GLU_TESS_ERROR3* = 100153
+  GLU_TESS_ERROR4* = 100154
+  GLU_TESS_ERROR5* = 100155
+  GLU_TESS_ERROR6* = 100156
+  GLU_TESS_ERROR7* = 100157
+  GLU_TESS_ERROR8* = 100158
+  GLU_TESS_MISSING_BEGIN_POLYGON* = GLU_TESS_ERROR1
+  GLU_TESS_MISSING_BEGIN_CONTOUR* = GLU_TESS_ERROR2
+  GLU_TESS_MISSING_END_POLYGON* = GLU_TESS_ERROR3
+  GLU_TESS_MISSING_END_CONTOUR* = GLU_TESS_ERROR4
+  GLU_TESS_COORD_TOO_LARGE* = GLU_TESS_ERROR5
+  GLU_TESS_NEED_COMBINE_CALLBACK* = GLU_TESS_ERROR6 #***           NURBS constants                 ****/
+                                                    # NurbsProperty
+  GLU_AUTO_LOAD_MATRIX* = 100200
+  GLU_CULLING* = 100201
+  GLU_SAMPLING_TOLERANCE* = 100203
+  GLU_DISPLAY_MODE* = 100204
+  GLU_PARAMETRIC_TOLERANCE* = 100202
+  GLU_SAMPLING_METHOD* = 100205
+  GLU_U_STEP* = 100206
+  GLU_V_STEP* = 100207        # NurbsSampling
+  GLU_PATH_LENGTH* = 100215
+  GLU_PARAMETRIC_ERROR* = 100216
+  GLU_DOMAIN_DISTANCE* = 100217 # NurbsTrim
+  GLU_MAP1_TRIM_2* = 100210
+  GLU_MAP1_TRIM_3* = 100211   # NurbsDisplay
+                              #      GLU_FILL                = 100012;
+  GLU_OUTLINE_POLYGON* = 100240
+  GLU_OUTLINE_PATCH* = 100241 # NurbsCallback
+                              #      GLU_ERROR               = 100103;
+                              # NurbsErrors
+  GLU_NURBS_ERROR1* = 100251
+  GLU_NURBS_ERROR2* = 100252
+  GLU_NURBS_ERROR3* = 100253
+  GLU_NURBS_ERROR4* = 100254
+  GLU_NURBS_ERROR5* = 100255
+  GLU_NURBS_ERROR6* = 100256
+  GLU_NURBS_ERROR7* = 100257
+  GLU_NURBS_ERROR8* = 100258
+  GLU_NURBS_ERROR9* = 100259
+  GLU_NURBS_ERROR10* = 100260
+  GLU_NURBS_ERROR11* = 100261
+  GLU_NURBS_ERROR12* = 100262
+  GLU_NURBS_ERROR13* = 100263
+  GLU_NURBS_ERROR14* = 100264
+  GLU_NURBS_ERROR15* = 100265
+  GLU_NURBS_ERROR16* = 100266
+  GLU_NURBS_ERROR17* = 100267
+  GLU_NURBS_ERROR18* = 100268
+  GLU_NURBS_ERROR19* = 100269
+  GLU_NURBS_ERROR20* = 100270
+  GLU_NURBS_ERROR21* = 100271
+  GLU_NURBS_ERROR22* = 100272
+  GLU_NURBS_ERROR23* = 100273
+  GLU_NURBS_ERROR24* = 100274
+  GLU_NURBS_ERROR25* = 100275
+  GLU_NURBS_ERROR26* = 100276
+  GLU_NURBS_ERROR27* = 100277
+  GLU_NURBS_ERROR28* = 100278
+  GLU_NURBS_ERROR29* = 100279
+  GLU_NURBS_ERROR30* = 100280
+  GLU_NURBS_ERROR31* = 100281
+  GLU_NURBS_ERROR32* = 100282
+  GLU_NURBS_ERROR33* = 100283
+  GLU_NURBS_ERROR34* = 100284
+  GLU_NURBS_ERROR35* = 100285
+  GLU_NURBS_ERROR36* = 100286
+  GLU_NURBS_ERROR37* = 100287 #***           Backwards compatibility for old tesselator           ****/
+
+proc gluBeginPolygon*(tess: PGLUtesselator){.dynlib: dllname,
+    importc: "gluBeginPolygon".}
+proc gluNextContour*(tess: PGLUtesselator, atype: TGLenum){.dynlib: dllname,
+    importc: "gluNextContour".}
+proc gluEndPolygon*(tess: PGLUtesselator){.dynlib: dllname,
+    importc: "gluEndPolygon".}
+const                         # Contours types -- obsolete!
+  GLU_CW* = 100120
+  GLU_CCW* = 100121
+  GLU_INTERIOR* = 100122
+  GLU_EXTERIOR* = 100123
+  GLU_UNKNOWN* = 100124       # Names without "TESS_" prefix
+  GLU_BEGIN* = GLU_TESS_BEGIN
+  GLU_VERTEX* = constGLU_TESS_VERTEX
+  GLU_END* = GLU_TESS_END
+  GLU_ERROR* = GLU_TESS_ERROR
+  GLU_EDGE_FLAG* = GLU_TESS_EDGE_FLAG
+
+{.pop.}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/glut.nim b/tests/manyloc/keineschweine/lib/glut.nim
new file mode 100644
index 000000000..de9a97456
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glut.nim
@@ -0,0 +1,438 @@
+#
+#
+#  Adaption of the delphi3d.net OpenGL units to FreePascal
+#  Sebastian Guenther (sg@freepascal.org) in 2002
+#  These units are free to use
+#
+
+# Copyright (c) Mark J. Kilgard, 1994, 1995, 1996.
+# This program is freely distributable without licensing fees  and is
+#   provided without guarantee or warrantee expressed or  implied. This
+#   program is -not- in the public domain.
+#******************************************************************************
+# Converted to Delphi by Tom Nuydens (tom@delphi3d.net)
+#   Contributions by Igor Karpov (glygrik@hotbox.ru)
+#   For the latest updates, visit Delphi3D: http://www.delphi3d.net
+#******************************************************************************
+
+import
+  GL
+
+when defined(windows):
+  const
+    dllname = "glut32.dll"
+elif defined(macosx):
+  const
+    dllname = "/System/Library/Frameworks/GLUT.framework/GLUT"
+else:
+  const
+    dllname = "libglut.so.3"
+type
+  TGlutVoidCallback* = proc (){.cdecl.}
+  TGlut1IntCallback* = proc (value: cint){.cdecl.}
+  TGlut2IntCallback* = proc (v1, v2: cint){.cdecl.}
+  TGlut3IntCallback* = proc (v1, v2, v3: cint){.cdecl.}
+  TGlut4IntCallback* = proc (v1, v2, v3, v4: cint){.cdecl.}
+  TGlut1Char2IntCallback* = proc (c: int8, v1, v2: cint){.cdecl.}
+  TGlut1UInt3IntCallback* = proc (u, v1, v2, v3: cint){.cdecl.}
+
+const
+  GLUT_API_VERSION* = 3
+  GLUT_XLIB_IMPLEMENTATION* = 12 # Display mode bit masks.
+  GLUT_RGB* = 0
+  GLUT_RGBA* = GLUT_RGB
+  GLUT_INDEX* = 1
+  GLUT_SINGLE* = 0
+  GLUT_DOUBLE* = 2
+  GLUT_ACCUM* = 4
+  GLUT_ALPHA* = 8
+  GLUT_DEPTH* = 16
+  GLUT_STENCIL* = 32
+  GLUT_MULTISAMPLE* = 128
+  GLUT_STEREO* = 256
+  GLUT_LUMINANCE* = 512       # Mouse buttons.
+  GLUT_LEFT_BUTTON* = 0
+  GLUT_MIDDLE_BUTTON* = 1
+  GLUT_RIGHT_BUTTON* = 2      # Mouse button state.
+  GLUT_DOWN* = 0
+  GLUT_UP* = 1                # function keys
+  GLUT_KEY_F1* = 1
+  GLUT_KEY_F2* = 2
+  GLUT_KEY_F3* = 3
+  GLUT_KEY_F4* = 4
+  GLUT_KEY_F5* = 5
+  GLUT_KEY_F6* = 6
+  GLUT_KEY_F7* = 7
+  GLUT_KEY_F8* = 8
+  GLUT_KEY_F9* = 9
+  GLUT_KEY_F10* = 10
+  GLUT_KEY_F11* = 11
+  GLUT_KEY_F12* = 12          # directional keys
+  GLUT_KEY_LEFT* = 100
+  GLUT_KEY_UP* = 101
+  GLUT_KEY_RIGHT* = 102
+  GLUT_KEY_DOWN* = 103
+  GLUT_KEY_PAGE_UP* = 104
+  GLUT_KEY_PAGE_DOWN* = 105
+  GLUT_KEY_HOME* = 106
+  GLUT_KEY_END* = 107
+  GLUT_KEY_INSERT* = 108      # Entry/exit  state.
+  GLUT_LEFT* = 0
+  GLUT_ENTERED* = 1           # Menu usage state.
+  GLUT_MENU_NOT_IN_USE* = 0
+  GLUT_MENU_IN_USE* = 1       # Visibility  state.
+  GLUT_NOT_VISIBLE* = 0
+  GLUT_VISIBLE* = 1           # Window status  state.
+  GLUT_HIDDEN* = 0
+  GLUT_FULLY_RETAINED* = 1
+  GLUT_PARTIALLY_RETAINED* = 2
+  GLUT_FULLY_COVERED* = 3     # Color index component selection values.
+  GLUT_RED* = 0
+  GLUT_GREEN* = 1
+  GLUT_BLUE* = 2              # Layers for use.
+  GLUT_NORMAL* = 0
+  GLUT_OVERLAY* = 1
+
+when defined(windows):
+  const                       # Stroke font constants (use these in GLUT program).
+    GLUT_STROKE_ROMAN* = cast[Pointer](0)
+    GLUT_STROKE_MONO_ROMAN* = cast[Pointer](1) # Bitmap font constants (use these in GLUT program).
+    GLUT_BITMAP_9_BY_15* = cast[Pointer](2)
+    GLUT_BITMAP_8_BY_13* = cast[Pointer](3)
+    GLUT_BITMAP_TIMES_ROMAN_10* = cast[Pointer](4)
+    GLUT_BITMAP_TIMES_ROMAN_24* = cast[Pointer](5)
+    GLUT_BITMAP_HELVETICA_10* = cast[Pointer](6)
+    GLUT_BITMAP_HELVETICA_12* = cast[Pointer](7)
+    GLUT_BITMAP_HELVETICA_18* = cast[Pointer](8)
+else:
+  var                         # Stroke font constants (use these in GLUT program).
+    GLUT_STROKE_ROMAN*: Pointer
+    GLUT_STROKE_MONO_ROMAN*: Pointer # Bitmap font constants (use these in GLUT program).
+    GLUT_BITMAP_9_BY_15*: Pointer
+    GLUT_BITMAP_8_BY_13*: Pointer
+    GLUT_BITMAP_TIMES_ROMAN_10*: Pointer
+    GLUT_BITMAP_TIMES_ROMAN_24*: Pointer
+    GLUT_BITMAP_HELVETICA_10*: Pointer
+    GLUT_BITMAP_HELVETICA_12*: Pointer
+    GLUT_BITMAP_HELVETICA_18*: Pointer
+const                         # glutGet parameters.
+  GLUT_WINDOW_X* = 100
+  GLUT_WINDOW_Y* = 101
+  GLUT_WINDOW_WIDTH* = 102
+  GLUT_WINDOW_HEIGHT* = 103
+  GLUT_WINDOW_BUFFER_SIZE* = 104
+  GLUT_WINDOW_STENCIL_SIZE* = 105
+  GLUT_WINDOW_DEPTH_SIZE* = 106
+  GLUT_WINDOW_RED_SIZE* = 107
+  GLUT_WINDOW_GREEN_SIZE* = 108
+  GLUT_WINDOW_BLUE_SIZE* = 109
+  GLUT_WINDOW_ALPHA_SIZE* = 110
+  GLUT_WINDOW_ACCUM_RED_SIZE* = 111
+  GLUT_WINDOW_ACCUM_GREEN_SIZE* = 112
+  GLUT_WINDOW_ACCUM_BLUE_SIZE* = 113
+  GLUT_WINDOW_ACCUM_ALPHA_SIZE* = 114
+  GLUT_WINDOW_DOUBLEBUFFER* = 115
+  GLUT_WINDOW_RGBA* = 116
+  GLUT_WINDOW_PARENT* = 117
+  GLUT_WINDOW_NUM_CHILDREN* = 118
+  GLUT_WINDOW_COLORMAP_SIZE* = 119
+  GLUT_WINDOW_NUM_SAMPLES* = 120
+  GLUT_WINDOW_STEREO* = 121
+  GLUT_WINDOW_CURSOR* = 122
+  GLUT_SCREEN_WIDTH* = 200
+  GLUT_SCREEN_HEIGHT* = 201
+  GLUT_SCREEN_WIDTH_MM* = 202
+  GLUT_SCREEN_HEIGHT_MM* = 203
+  GLUT_MENU_NUM_ITEMS* = 300
+  GLUT_DISPLAY_MODE_POSSIBLE* = 400
+  GLUT_INIT_WINDOW_X* = 500
+  GLUT_INIT_WINDOW_Y* = 501
+  GLUT_INIT_WINDOW_WIDTH* = 502
+  GLUT_INIT_WINDOW_HEIGHT* = 503
+  constGLUT_INIT_DISPLAY_MODE* = 504
+  GLUT_ELAPSED_TIME* = 700
+  GLUT_WINDOW_FORMAT_ID* = 123 # glutDeviceGet parameters.
+  GLUT_HAS_KEYBOARD* = 600
+  GLUT_HAS_MOUSE* = 601
+  GLUT_HAS_SPACEBALL* = 602
+  GLUT_HAS_DIAL_AND_BUTTON_BOX* = 603
+  GLUT_HAS_TABLET* = 604
+  GLUT_NUM_MOUSE_BUTTONS* = 605
+  GLUT_NUM_SPACEBALL_BUTTONS* = 606
+  GLUT_NUM_BUTTON_BOX_BUTTONS* = 607
+  GLUT_NUM_DIALS* = 608
+  GLUT_NUM_TABLET_BUTTONS* = 609
+  GLUT_DEVICE_IGNORE_KEY_REPEAT* = 610
+  GLUT_DEVICE_KEY_REPEAT* = 611
+  GLUT_HAS_JOYSTICK* = 612
+  GLUT_OWNS_JOYSTICK* = 613
+  GLUT_JOYSTICK_BUTTONS* = 614
+  GLUT_JOYSTICK_AXES* = 615
+  GLUT_JOYSTICK_POLL_RATE* = 616 # glutLayerGet parameters.
+  GLUT_OVERLAY_POSSIBLE* = 800
+  GLUT_LAYER_IN_USE* = 801
+  GLUT_HAS_OVERLAY* = 802
+  GLUT_TRANSPARENT_INDEX* = 803
+  GLUT_NORMAL_DAMAGED* = 804
+  GLUT_OVERLAY_DAMAGED* = 805 # glutVideoResizeGet parameters.
+  GLUT_VIDEO_RESIZE_POSSIBLE* = 900
+  GLUT_VIDEO_RESIZE_IN_USE* = 901
+  GLUT_VIDEO_RESIZE_X_DELTA* = 902
+  GLUT_VIDEO_RESIZE_Y_DELTA* = 903
+  GLUT_VIDEO_RESIZE_WIDTH_DELTA* = 904
+  GLUT_VIDEO_RESIZE_HEIGHT_DELTA* = 905
+  GLUT_VIDEO_RESIZE_X* = 906
+  GLUT_VIDEO_RESIZE_Y* = 907
+  GLUT_VIDEO_RESIZE_WIDTH* = 908
+  GLUT_VIDEO_RESIZE_HEIGHT* = 909 # glutGetModifiers return mask.
+  GLUT_ACTIVE_SHIFT* = 1
+  GLUT_ACTIVE_CTRL* = 2
+  GLUT_ACTIVE_ALT* = 4        # glutSetCursor parameters.
+                              # Basic arrows.
+  GLUT_CURSOR_RIGHT_ARROW* = 0
+  GLUT_CURSOR_LEFT_ARROW* = 1 # Symbolic cursor shapes.
+  GLUT_CURSOR_INFO* = 2
+  GLUT_CURSOR_DESTROY* = 3
+  GLUT_CURSOR_HELP* = 4
+  GLUT_CURSOR_CYCLE* = 5
+  GLUT_CURSOR_SPRAY* = 6
+  GLUT_CURSOR_WAIT* = 7
+  GLUT_CURSOR_TEXT* = 8
+  GLUT_CURSOR_CROSSHAIR* = 9  # Directional cursors.
+  GLUT_CURSOR_UP_DOWN* = 10
+  GLUT_CURSOR_LEFT_RIGHT* = 11 # Sizing cursors.
+  GLUT_CURSOR_TOP_SIDE* = 12
+  GLUT_CURSOR_BOTTOM_SIDE* = 13
+  GLUT_CURSOR_LEFT_SIDE* = 14
+  GLUT_CURSOR_RIGHT_SIDE* = 15
+  GLUT_CURSOR_TOP_LEFT_CORNER* = 16
+  GLUT_CURSOR_TOP_RIGHT_CORNER* = 17
+  GLUT_CURSOR_BOTTOM_RIGHT_CORNER* = 18
+  GLUT_CURSOR_BOTTOM_LEFT_CORNER* = 19 # Inherit from parent window.
+  GLUT_CURSOR_INHERIT* = 100  # Blank cursor.
+  GLUT_CURSOR_NONE* = 101     # Fullscreen crosshair (if available).
+  GLUT_CURSOR_FULL_CROSSHAIR* = 102 # GLUT device control sub-API.
+                                    # glutSetKeyRepeat modes.
+  GLUT_KEY_REPEAT_OFF* = 0
+  GLUT_KEY_REPEAT_ON* = 1
+  GLUT_KEY_REPEAT_DEFAULT* = 2 # Joystick button masks.
+  GLUT_JOYSTICK_BUTTON_A* = 1
+  GLUT_JOYSTICK_BUTTON_B* = 2
+  GLUT_JOYSTICK_BUTTON_C* = 4
+  GLUT_JOYSTICK_BUTTON_D* = 8 # GLUT game mode sub-API.
+                              # glutGameModeGet.
+  GLUT_GAME_MODE_ACTIVE* = 0
+  GLUT_GAME_MODE_POSSIBLE* = 1
+  GLUT_GAME_MODE_WIDTH* = 2
+  GLUT_GAME_MODE_HEIGHT* = 3
+  GLUT_GAME_MODE_PIXEL_DEPTH* = 4
+  GLUT_GAME_MODE_REFRESH_RATE* = 5
+  GLUT_GAME_MODE_DISPLAY_CHANGED* = 6 # GLUT initialization sub-API.
+
+proc glutInit*(argcp: ptr cint, argv: pointer){.dynlib: dllname,
+    importc: "glutInit".}
+
+proc glutInit*() =
+  ## version that passes `argc` and `argc` implicitely.
+  var
+    cmdLine {.importc: "cmdLine".}: array[0..255, cstring]
+    cmdCount {.importc: "cmdCount".}: cint
+  glutInit(addr(cmdCount), addr(cmdLine))
+
+proc glutInitDisplayMode*(mode: int16){.dynlib: dllname,
+                                        importc: "glutInitDisplayMode".}
+proc glutInitDisplayString*(str: cstring){.dynlib: dllname,
+    importc: "glutInitDisplayString".}
+proc glutInitWindowPosition*(x, y: int){.dynlib: dllname,
+    importc: "glutInitWindowPosition".}
+proc glutInitWindowSize*(width, height: int){.dynlib: dllname,
+    importc: "glutInitWindowSize".}
+proc glutMainLoop*(){.dynlib: dllname, importc: "glutMainLoop".}
+  # GLUT window sub-API.
+proc glutCreateWindow*(title: cstring): int{.dynlib: dllname,
+    importc: "glutCreateWindow".}
+proc glutCreateSubWindow*(win, x, y, width, height: int): int{.dynlib: dllname,
+    importc: "glutCreateSubWindow".}
+proc glutDestroyWindow*(win: int){.dynlib: dllname, importc: "glutDestroyWindow".}
+proc glutPostRedisplay*(){.dynlib: dllname, importc: "glutPostRedisplay".}
+proc glutPostWindowRedisplay*(win: int){.dynlib: dllname,
+    importc: "glutPostWindowRedisplay".}
+proc glutSwapBuffers*(){.dynlib: dllname, importc: "glutSwapBuffers".}
+proc glutGetWindow*(): int{.dynlib: dllname, importc: "glutGetWindow".}
+proc glutSetWindow*(win: int){.dynlib: dllname, importc: "glutSetWindow".}
+proc glutSetWindowTitle*(title: cstring){.dynlib: dllname,
+    importc: "glutSetWindowTitle".}
+proc glutSetIconTitle*(title: cstring){.dynlib: dllname,
+                                        importc: "glutSetIconTitle".}
+proc glutPositionWindow*(x, y: int){.dynlib: dllname,
+                                     importc: "glutPositionWindow".}
+proc glutReshapeWindow*(width, height: int){.dynlib: dllname,
+    importc: "glutReshapeWindow".}
+proc glutPopWindow*(){.dynlib: dllname, importc: "glutPopWindow".}
+proc glutPushWindow*(){.dynlib: dllname, importc: "glutPushWindow".}
+proc glutIconifyWindow*(){.dynlib: dllname, importc: "glutIconifyWindow".}
+proc glutShowWindow*(){.dynlib: dllname, importc: "glutShowWindow".}
+proc glutHideWindow*(){.dynlib: dllname, importc: "glutHideWindow".}
+proc glutFullScreen*(){.dynlib: dllname, importc: "glutFullScreen".}
+proc glutSetCursor*(cursor: int){.dynlib: dllname, importc: "glutSetCursor".}
+proc glutWarpPointer*(x, y: int){.dynlib: dllname, importc: "glutWarpPointer".}
+  # GLUT overlay sub-API.
+proc glutEstablishOverlay*(){.dynlib: dllname, importc: "glutEstablishOverlay".}
+proc glutRemoveOverlay*(){.dynlib: dllname, importc: "glutRemoveOverlay".}
+proc glutUseLayer*(layer: TGLenum){.dynlib: dllname, importc: "glutUseLayer".}
+proc glutPostOverlayRedisplay*(){.dynlib: dllname,
+                                  importc: "glutPostOverlayRedisplay".}
+proc glutPostWindowOverlayRedisplay*(win: int){.dynlib: dllname,
+    importc: "glutPostWindowOverlayRedisplay".}
+proc glutShowOverlay*(){.dynlib: dllname, importc: "glutShowOverlay".}
+proc glutHideOverlay*(){.dynlib: dllname, importc: "glutHideOverlay".}
+  # GLUT menu sub-API.
+proc glutCreateMenu*(callback: TGlut1IntCallback): int{.dynlib: dllname,
+    importc: "glutCreateMenu".}
+proc glutDestroyMenu*(menu: int){.dynlib: dllname, importc: "glutDestroyMenu".}
+proc glutGetMenu*(): int{.dynlib: dllname, importc: "glutGetMenu".}
+proc glutSetMenu*(menu: int){.dynlib: dllname, importc: "glutSetMenu".}
+proc glutAddMenuEntry*(caption: cstring, value: int){.dynlib: dllname,
+    importc: "glutAddMenuEntry".}
+proc glutAddSubMenu*(caption: cstring, submenu: int){.dynlib: dllname,
+    importc: "glutAddSubMenu".}
+proc glutChangeToMenuEntry*(item: int, caption: cstring, value: int){.
+    dynlib: dllname, importc: "glutChangeToMenuEntry".}
+proc glutChangeToSubMenu*(item: int, caption: cstring, submenu: int){.
+    dynlib: dllname, importc: "glutChangeToSubMenu".}
+proc glutRemoveMenuItem*(item: int){.dynlib: dllname,
+                                     importc: "glutRemoveMenuItem".}
+proc glutAttachMenu*(button: int){.dynlib: dllname, importc: "glutAttachMenu".}
+proc glutDetachMenu*(button: int){.dynlib: dllname, importc: "glutDetachMenu".}
+  # GLUT window callback sub-API.
+proc glutDisplayFunc*(f: TGlutVoidCallback){.dynlib: dllname,
+    importc: "glutDisplayFunc".}
+proc glutReshapeFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutReshapeFunc".}
+proc glutKeyboardFunc*(f: TGlut1Char2IntCallback){.dynlib: dllname,
+    importc: "glutKeyboardFunc".}
+proc glutMouseFunc*(f: TGlut4IntCallback){.dynlib: dllname,
+    importc: "glutMouseFunc".}
+proc glutMotionFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutMotionFunc".}
+proc glutPassiveMotionFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutPassiveMotionFunc".}
+proc glutEntryFunc*(f: TGlut1IntCallback){.dynlib: dllname,
+    importc: "glutEntryFunc".}
+proc glutVisibilityFunc*(f: TGlut1IntCallback){.dynlib: dllname,
+    importc: "glutVisibilityFunc".}
+proc glutIdleFunc*(f: TGlutVoidCallback){.dynlib: dllname,
+    importc: "glutIdleFunc".}
+proc glutTimerFunc*(millis: int16, f: TGlut1IntCallback, value: int){.
+    dynlib: dllname, importc: "glutTimerFunc".}
+proc glutMenuStateFunc*(f: TGlut1IntCallback){.dynlib: dllname,
+    importc: "glutMenuStateFunc".}
+proc glutSpecialFunc*(f: TGlut3IntCallback){.dynlib: dllname,
+    importc: "glutSpecialFunc".}
+proc glutSpaceballMotionFunc*(f: TGlut3IntCallback){.dynlib: dllname,
+    importc: "glutSpaceballMotionFunc".}
+proc glutSpaceballRotateFunc*(f: TGlut3IntCallback){.dynlib: dllname,
+    importc: "glutSpaceballRotateFunc".}
+proc glutSpaceballButtonFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutSpaceballButtonFunc".}
+proc glutButtonBoxFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutButtonBoxFunc".}
+proc glutDialsFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutDialsFunc".}
+proc glutTabletMotionFunc*(f: TGlut2IntCallback){.dynlib: dllname,
+    importc: "glutTabletMotionFunc".}
+proc glutTabletButtonFunc*(f: TGlut4IntCallback){.dynlib: dllname,
+    importc: "glutTabletButtonFunc".}
+proc glutMenuStatusFunc*(f: TGlut3IntCallback){.dynlib: dllname,
+    importc: "glutMenuStatusFunc".}
+proc glutOverlayDisplayFunc*(f: TGlutVoidCallback){.dynlib: dllname,
+    importc: "glutOverlayDisplayFunc".}
+proc glutWindowStatusFunc*(f: TGlut1IntCallback){.dynlib: dllname,
+    importc: "glutWindowStatusFunc".}
+proc glutKeyboardUpFunc*(f: TGlut1Char2IntCallback){.dynlib: dllname,
+    importc: "glutKeyboardUpFunc".}
+proc glutSpecialUpFunc*(f: TGlut3IntCallback){.dynlib: dllname,
+    importc: "glutSpecialUpFunc".}
+proc glutJoystickFunc*(f: TGlut1UInt3IntCallback, pollInterval: int){.
+    dynlib: dllname, importc: "glutJoystickFunc".}
+  # GLUT color index sub-API.
+proc glutSetColor*(cell: int, red, green, blue: TGLfloat){.dynlib: dllname,
+    importc: "glutSetColor".}
+proc glutGetColor*(ndx, component: int): TGLfloat{.dynlib: dllname,
+    importc: "glutGetColor".}
+proc glutCopyColormap*(win: int){.dynlib: dllname, importc: "glutCopyColormap".}
+  # GLUT state retrieval sub-API.
+proc glutGet*(t: TGLenum): int{.dynlib: dllname, importc: "glutGet".}
+proc glutDeviceGet*(t: TGLenum): int{.dynlib: dllname, importc: "glutDeviceGet".}
+  # GLUT extension support sub-API
+proc glutExtensionSupported*(name: cstring): int{.dynlib: dllname,
+    importc: "glutExtensionSupported".}
+proc glutGetModifiers*(): int{.dynlib: dllname, importc: "glutGetModifiers".}
+proc glutLayerGet*(t: TGLenum): int{.dynlib: dllname, importc: "glutLayerGet".}
+  # GLUT font sub-API
+proc glutBitmapCharacter*(font: pointer, character: int){.dynlib: dllname,
+    importc: "glutBitmapCharacter".}
+proc glutBitmapWidth*(font: pointer, character: int): int{.dynlib: dllname,
+    importc: "glutBitmapWidth".}
+proc glutStrokeCharacter*(font: pointer, character: int){.dynlib: dllname,
+    importc: "glutStrokeCharacter".}
+proc glutStrokeWidth*(font: pointer, character: int): int{.dynlib: dllname,
+    importc: "glutStrokeWidth".}
+proc glutBitmapLength*(font: pointer, str: cstring): int{.dynlib: dllname,
+    importc: "glutBitmapLength".}
+proc glutStrokeLength*(font: pointer, str: cstring): int{.dynlib: dllname,
+    importc: "glutStrokeLength".}
+  # GLUT pre-built models sub-API
+proc glutWireSphere*(radius: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutWireSphere".}
+proc glutSolidSphere*(radius: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutSolidSphere".}
+proc glutWireCone*(base, height: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutWireCone".}
+proc glutSolidCone*(base, height: TGLdouble, slices, stacks: TGLint){.
+    dynlib: dllname, importc: "glutSolidCone".}
+proc glutWireCube*(size: TGLdouble){.dynlib: dllname, importc: "glutWireCube".}
+proc glutSolidCube*(size: TGLdouble){.dynlib: dllname, importc: "glutSolidCube".}
+proc glutWireTorus*(innerRadius, outerRadius: TGLdouble, sides, rings: TGLint){.
+    dynlib: dllname, importc: "glutWireTorus".}
+proc glutSolidTorus*(innerRadius, outerRadius: TGLdouble, sides, rings: TGLint){.
+    dynlib: dllname, importc: "glutSolidTorus".}
+proc glutWireDodecahedron*(){.dynlib: dllname, importc: "glutWireDodecahedron".}
+proc glutSolidDodecahedron*(){.dynlib: dllname, importc: "glutSolidDodecahedron".}
+proc glutWireTeapot*(size: TGLdouble){.dynlib: dllname,
+                                       importc: "glutWireTeapot".}
+proc glutSolidTeapot*(size: TGLdouble){.dynlib: dllname,
+                                        importc: "glutSolidTeapot".}
+proc glutWireOctahedron*(){.dynlib: dllname, importc: "glutWireOctahedron".}
+proc glutSolidOctahedron*(){.dynlib: dllname, importc: "glutSolidOctahedron".}
+proc glutWireTetrahedron*(){.dynlib: dllname, importc: "glutWireTetrahedron".}
+proc glutSolidTetrahedron*(){.dynlib: dllname, importc: "glutSolidTetrahedron".}
+proc glutWireIcosahedron*(){.dynlib: dllname, importc: "glutWireIcosahedron".}
+proc glutSolidIcosahedron*(){.dynlib: dllname, importc: "glutSolidIcosahedron".}
+  # GLUT video resize sub-API.
+proc glutVideoResizeGet*(param: TGLenum): int{.dynlib: dllname,
+    importc: "glutVideoResizeGet".}
+proc glutSetupVideoResizing*(){.dynlib: dllname,
+                                importc: "glutSetupVideoResizing".}
+proc glutStopVideoResizing*(){.dynlib: dllname, importc: "glutStopVideoResizing".}
+proc glutVideoResize*(x, y, width, height: int){.dynlib: dllname,
+    importc: "glutVideoResize".}
+proc glutVideoPan*(x, y, width, height: int){.dynlib: dllname,
+    importc: "glutVideoPan".}
+  # GLUT debugging sub-API.
+proc glutReportErrors*(){.dynlib: dllname, importc: "glutReportErrors".}
+  # GLUT device control sub-API.
+proc glutIgnoreKeyRepeat*(ignore: int){.dynlib: dllname,
+                                        importc: "glutIgnoreKeyRepeat".}
+proc glutSetKeyRepeat*(repeatMode: int){.dynlib: dllname,
+    importc: "glutSetKeyRepeat".}
+proc glutForceJoystickFunc*(){.dynlib: dllname, importc: "glutForceJoystickFunc".}
+  # GLUT game mode sub-API.
+  #example glutGameModeString('1280x1024:32@75');
+proc glutGameModeString*(AString: cstring){.dynlib: dllname,
+    importc: "glutGameModeString".}
+proc glutEnterGameMode*(): int{.dynlib: dllname, importc: "glutEnterGameMode".}
+proc glutLeaveGameMode*(){.dynlib: dllname, importc: "glutLeaveGameMode".}
+proc glutGameModeGet*(mode: TGLenum): int{.dynlib: dllname,
+    importc: "glutGameModeGet".}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/glx.nim b/tests/manyloc/keineschweine/lib/glx.nim
new file mode 100644
index 000000000..ce02835bd
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/glx.nim
@@ -0,0 +1,153 @@
+#
+#
+#  Translation of the Mesa GLX headers for FreePascal
+#  Copyright (C) 1999 Sebastian Guenther
+#
+#
+#  Mesa 3-D graphics library
+#  Version:  3.0
+#  Copyright (C) 1995-1998  Brian Paul
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Library General Public
+#  License as published by the Free Software Foundation; either
+#  version 2 of the License, or (at your option) any later version.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Library General Public License for more details.
+#
+#  You should have received a copy of the GNU Library General Public
+#  License along with this library; if not, write to the Free
+#  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import
+  X, XLib, XUtil, gl
+
+when defined(windows):
+  const
+    dllname = "GL.dll"
+elif defined(macosx):
+  const
+    dllname = "/usr/X11R6/lib/libGL.dylib"
+else:
+  const
+    dllname = "libGL.so"
+const
+  GLX_USE_GL* = 1
+  GLX_BUFFER_SIZE* = 2
+  GLX_LEVEL* = 3
+  GLX_RGBA* = 4
+  GLX_DOUBLEBUFFER* = 5
+  GLX_STEREO* = 6
+  GLX_AUX_BUFFERS* = 7
+  GLX_RED_SIZE* = 8
+  GLX_GREEN_SIZE* = 9
+  GLX_BLUE_SIZE* = 10
+  GLX_ALPHA_SIZE* = 11
+  GLX_DEPTH_SIZE* = 12
+  GLX_STENCIL_SIZE* = 13
+  GLX_ACCUM_RED_SIZE* = 14
+  GLX_ACCUM_GREEN_SIZE* = 15
+  GLX_ACCUM_BLUE_SIZE* = 16
+  GLX_ACCUM_ALPHA_SIZE* = 17  # GLX_EXT_visual_info extension
+  GLX_X_VISUAL_TYPE_EXT* = 0x00000022
+  GLX_TRANSPARENT_TYPE_EXT* = 0x00000023
+  GLX_TRANSPARENT_INDEX_VALUE_EXT* = 0x00000024
+  GLX_TRANSPARENT_RED_VALUE_EXT* = 0x00000025
+  GLX_TRANSPARENT_GREEN_VALUE_EXT* = 0x00000026
+  GLX_TRANSPARENT_BLUE_VALUE_EXT* = 0x00000027
+  GLX_TRANSPARENT_ALPHA_VALUE_EXT* = 0x00000028 # Error codes returned by glXGetConfig:
+  GLX_BAD_SCREEN* = 1
+  GLX_BAD_ATTRIBUTE* = 2
+  GLX_NO_EXTENSION* = 3
+  GLX_BAD_VISUAL* = 4
+  GLX_BAD_CONTEXT* = 5
+  GLX_BAD_VALUE* = 6
+  GLX_BAD_ENUM* = 7           # GLX 1.1 and later:
+  GLX_VENDOR* = 1
+  GLX_VERSION* = 2
+  GLX_EXTENSIONS* = 3         # GLX_visual_info extension
+  GLX_TRUE_COLOR_EXT* = 0x00008002
+  GLX_DIRECT_COLOR_EXT* = 0x00008003
+  GLX_PSEUDO_COLOR_EXT* = 0x00008004
+  GLX_STATIC_COLOR_EXT* = 0x00008005
+  GLX_GRAY_SCALE_EXT* = 0x00008006
+  GLX_STATIC_GRAY_EXT* = 0x00008007
+  GLX_NONE_EXT* = 0x00008000
+  GLX_TRANSPARENT_RGB_EXT* = 0x00008008
+  GLX_TRANSPARENT_INDEX_EXT* = 0x00008009
+
+type                          # From XLib:
+  XPixmap* = TXID
+  XFont* = TXID
+  XColormap* = TXID
+  GLXContext* = Pointer
+  GLXPixmap* = TXID
+  GLXDrawable* = TXID
+  GLXContextID* = TXID
+  TXPixmap* = XPixmap
+  TXFont* = XFont
+  TXColormap* = XColormap
+  TGLXContext* = GLXContext
+  TGLXPixmap* = GLXPixmap
+  TGLXDrawable* = GLXDrawable
+  TGLXContextID* = GLXContextID
+
+proc glXChooseVisual*(dpy: PDisplay, screen: int, attribList: ptr int32): PXVisualInfo{.
+    cdecl, dynlib: dllname, importc: "glXChooseVisual".}
+proc glXCreateContext*(dpy: PDisplay, vis: PXVisualInfo, shareList: GLXContext,
+                       direct: bool): GLXContext{.cdecl, dynlib: dllname,
+    importc: "glXCreateContext".}
+proc glXDestroyContext*(dpy: PDisplay, ctx: GLXContext){.cdecl, dynlib: dllname,
+    importc: "glXDestroyContext".}
+proc glXMakeCurrent*(dpy: PDisplay, drawable: GLXDrawable, ctx: GLXContext): bool{.
+    cdecl, dynlib: dllname, importc: "glXMakeCurrent".}
+proc glXCopyContext*(dpy: PDisplay, src, dst: GLXContext, mask: int32){.cdecl,
+    dynlib: dllname, importc: "glXCopyContext".}
+proc glXSwapBuffers*(dpy: PDisplay, drawable: GLXDrawable){.cdecl,
+    dynlib: dllname, importc: "glXSwapBuffers".}
+proc glXCreateGLXPixmap*(dpy: PDisplay, visual: PXVisualInfo, pixmap: XPixmap): GLXPixmap{.
+    cdecl, dynlib: dllname, importc: "glXCreateGLXPixmap".}
+proc glXDestroyGLXPixmap*(dpy: PDisplay, pixmap: GLXPixmap){.cdecl,
+    dynlib: dllname, importc: "glXDestroyGLXPixmap".}
+proc glXQueryExtension*(dpy: PDisplay, errorb, event: var int): bool{.cdecl,
+    dynlib: dllname, importc: "glXQueryExtension".}
+proc glXQueryVersion*(dpy: PDisplay, maj, min: var int): bool{.cdecl,
+    dynlib: dllname, importc: "glXQueryVersion".}
+proc glXIsDirect*(dpy: PDisplay, ctx: GLXContext): bool{.cdecl, dynlib: dllname,
+    importc: "glXIsDirect".}
+proc glXGetConfig*(dpy: PDisplay, visual: PXVisualInfo, attrib: int,
+                   value: var int): int{.cdecl, dynlib: dllname,
+    importc: "glXGetConfig".}
+proc glXGetCurrentContext*(): GLXContext{.cdecl, dynlib: dllname,
+    importc: "glXGetCurrentContext".}
+proc glXGetCurrentDrawable*(): GLXDrawable{.cdecl, dynlib: dllname,
+    importc: "glXGetCurrentDrawable".}
+proc glXWaitGL*(){.cdecl, dynlib: dllname, importc: "glXWaitGL".}
+proc glXWaitX*(){.cdecl, dynlib: dllname, importc: "glXWaitX".}
+proc glXUseXFont*(font: XFont, first, count, list: int){.cdecl, dynlib: dllname,
+    importc: "glXUseXFont".}
+  # GLX 1.1 and later
+proc glXQueryExtensionsString*(dpy: PDisplay, screen: int): cstring{.cdecl,
+    dynlib: dllname, importc: "glXQueryExtensionsString".}
+proc glXQueryServerString*(dpy: PDisplay, screen, name: int): cstring{.cdecl,
+    dynlib: dllname, importc: "glXQueryServerString".}
+proc glXGetClientString*(dpy: PDisplay, name: int): cstring{.cdecl,
+    dynlib: dllname, importc: "glXGetClientString".}
+  # Mesa GLX Extensions
+proc glXCreateGLXPixmapMESA*(dpy: PDisplay, visual: PXVisualInfo,
+                             pixmap: XPixmap, cmap: XColormap): GLXPixmap{.
+    cdecl, dynlib: dllname, importc: "glXCreateGLXPixmapMESA".}
+proc glXReleaseBufferMESA*(dpy: PDisplay, d: GLXDrawable): bool{.cdecl,
+    dynlib: dllname, importc: "glXReleaseBufferMESA".}
+proc glXCopySubBufferMESA*(dpy: PDisplay, drawbale: GLXDrawable,
+                           x, y, width, height: int){.cdecl, dynlib: dllname,
+    importc: "glXCopySubBufferMESA".}
+proc glXGetVideoSyncSGI*(counter: var int32): int{.cdecl, dynlib: dllname,
+    importc: "glXGetVideoSyncSGI".}
+proc glXWaitVideoSyncSGI*(divisor, remainder: int, count: var int32): int{.
+    cdecl, dynlib: dllname, importc: "glXWaitVideoSyncSGI".}
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/idgen.nim b/tests/manyloc/keineschweine/lib/idgen.nim
new file mode 100644
index 000000000..1ed196d88
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/idgen.nim
@@ -0,0 +1,23 @@
+type
+  PIDGen*[T: Ordinal] = ref TIDGen[T]
+  TIDGen*[T: Ordinal] = object
+    max: T
+    freeIDs: seq[T]
+  EOutOfIDs* = object of EInvalidKey
+
+#proc free[T](idg: PIDgen[T]) =
+#  result.freeIDs = nil
+proc newIDGen*[T: Ordinal](): PIDGen[T] =
+  new(result)#, free)
+  result.max = 0.T
+  result.freeIDs = @[]
+proc next*[T](idg: PIDGen[T]): T =
+  if idg.freeIDs.len > 0:
+    result = idg.freeIDs.pop
+  elif idg.max < high(T)-T(1):
+    inc idg.max
+    result = idg.max
+  else:
+    raise newException(EOutOfIDs, "ID generator hit max value")
+proc del*[T](idg: PIDGen[T]; id: T) =
+  idg.freeIDs.add id
diff --git a/tests/manyloc/keineschweine/lib/input_helpers.nim b/tests/manyloc/keineschweine/lib/input_helpers.nim
new file mode 100644
index 000000000..ff1286c8d
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/input_helpers.nim
@@ -0,0 +1,138 @@
+import
+  sfml, tables, hashes
+type
+  TKeyEventKind* = enum down, up
+  TInputFinishedProc* = proc()
+  TKeyCallback = proc()
+  PKeyClient* = ref object
+    onKeyDown: Table[int32, TKeyCallback]
+    onKeyUp: Table[int32, TKeyCallback]
+    name: string
+  PTextInput* = ref object
+    text*: string
+    cursor: int
+    onEnter: TInputFinishedProc
+var
+  keyState:    array[-MouseButtonCount.int32 .. KeyCount.int32, bool]
+  mousePos: TVector2f
+  activeClient: PKeyClient = nil
+  activeInput: PTextInput  = nil
+
+proc setActive*(client: PKeyClient) =
+  activeClient = client
+  echo("** set active client ", client.name)
+proc newKeyClient*(name: string = "unnamed", setactive = false): PKeyClient =
+  new(result)
+  result.onKeyDown = initTable[int32, TKeyCallback](16)
+  result.onKeyUp   = initTable[int32, TKeyCallback](16)
+  result.name = name
+  if setActive:
+    setActive(result)
+
+proc keyPressed*(key: TKeyCode): bool {.inline.} =
+  return keyState[key.int32]
+proc buttonPressed*(btn: TMouseButton): bool {.inline.} =
+  return keyState[-btn.int32]
+
+proc clearKey*(key: TKeyCode) {.inline.} =
+  keyState[key.int32]  = false
+proc clearButton*(btn: TMouseButton) {.inline.} =
+  keyState[-btn.int32] = false
+
+proc addKeyEvent*(key: TKeyCode, ev: TKeyEventKind) {.inline.} =
+  if activeClient.isNil: return
+  let k = key.int32
+  case ev
+  of down:
+    keyState[k] = true
+    if activeClient.onKeyDown.hasKey(k):
+      activeClient.onKeyDown[k]()
+  else:
+    keyState[k] = false
+    if activeClient.onKeyUp.hasKey(k):
+      activeClient.onKeyUp[k]()
+proc addButtonEvent*(btn: TMouseButton, ev: TKeyEventKind) {.inline.} =
+  if activeClient.isNil: return
+  let b = -btn.int32
+  case ev
+  of down:
+    keyState[b] = true
+    if activeClient.onKeyDown.hasKey(b):
+      activeClient.onKeyDown[b]()
+  else:
+    keyState[b] = false
+    if activeClient.onKeyUp.hasKey(b):
+      activeClient.onKeyUp[b]()
+proc registerHandler*(client: PKeyClient; key: TKeyCode;
+                       ev: TKeyEventKind; fn: TKeyCallback) =
+  case ev
+  of down: client.onKeyDown[key.int32] = fn
+  of up:   client.onKeyUp[key.int32]   = fn
+proc registerHandler*(client: PKeyClient; btn: TMouseButton;
+                       ev: TKeyEventKind; fn: TKeyCallback) =
+  case ev
+  of down: client.onKeyDown[-btn.int32] = fn
+  of up:   client.onKeyUp[-btn.int32]   = fn
+
+proc newTextInput*(text = "", pos = 0, onEnter: TInputFinishedProc = nil): PTextInput =
+  new(result)
+  result.text = text
+  result.cursor = pos
+  result.onEnter = onEnter
+proc setActive*(i: PTextInput) =
+  activeInput = i
+proc stopCapturingText*() =
+  activeInput = nil
+proc clear*(i: PTextInput) =
+  i.text.setLen 0
+  i.cursor = 0
+proc recordText*(i: PTextInput; c: cint) =
+  if c > 127 or i.isNil: return
+  if c in 32..126: ##printable
+    if i.cursor == i.text.len: i.text.add(c.int.chr)
+    else:
+      let rem = i.text.substr(i.cursor)
+      i.text.setLen(i.cursor)
+      i.text.add(chr(c.int))
+      i.text.add(rem)
+    inc(i.cursor)
+  elif c == 8: ## \b  backspace
+    if i.text.len > 0 and i.cursor > 0:
+      dec(i.cursor)
+      let rem = i.text.substr(i.cursor + 1)
+      i.text.setLen(i.cursor)
+      i.text.add(rem)
+  elif c == 10 or c == 13:## \n, \r  enter
+    if not i.onEnter.isNil: i.onEnter()
+proc recordText*(i: PTextInput; e: TTextEvent) {.inline.} =
+  recordText(i, e.unicode)
+
+proc setMousePos*(x, y: cint) {.inline.} =
+  mousePos.x = x.float
+  mousePos.y = y.float
+proc getMousePos*(): TVector2f {.inline.} = result = mousePos
+
+var event: TEvent
+# Handle and filter input-related events
+iterator filterEvents*(window: PRenderWindow): PEvent =
+  while window.pollEvent(addr event):
+    case event.kind
+    of EvtKeyPressed: addKeyEvent(event.key.code, down)
+    of EvtKeyReleased: addKeyEvent(event.key.code, up)
+    of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
+    of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
+    of EvtTextEntered: recordText(activeInput, event.text)
+    of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
+    else: yield(addr event)
+# Handle and return input-related events
+iterator pollEvents*(window: PRenderWindow): PEvent =
+  while window.pollEvent(addr event):
+    case event.kind
+    of EvtKeyPressed: addKeyEvent(event.key.code, down)
+    of EvtKeyReleased: addKeyEvent(event.key.code, up)
+    of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
+    of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
+    of EvtTextEntered: recordText(activeInput, event.text)
+    of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
+    else: discard
+    yield(addr event)
diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim
new file mode 100644
index 000000000..acb58c60e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/map_filter.nim
@@ -0,0 +1,41 @@
+template filterIt2*(seq, pred: untyped, body: untyped) =
+  ## sequtils defines a filterIt() that returns a new seq, but this one is called
+  ## with a statement body to iterate directly over it
+  for it in items(seq):
+    if pred: body
+
+proc map*[A, B](x: seq[A], fun: proc(y: A): B {.closure.}): seq[B] =
+  result = @[]
+  for item in x.items:
+    result.add fun(item)
+
+proc mapInPlace*[A](x: var seq[A], fun: proc(y: A): A {.closure.}) =
+  for i in 0..x.len-1:
+    x[i] = fun(x[i])
+
+template unless*(condition: untyped; body: untyped) {.dirty.} =
+  if not condition:
+    body
+
+when false:
+  proc dumpSeq[T](x: seq[T]) =
+    for index, item in x.pairs:
+      echo index, " ", item
+    echo "-------"
+
+  var t= @[1,2,3,4,5]
+  var res = t.map(proc(z: int): int = result = z * 10)
+  dumpSeq res
+
+  from strutils import toHex
+  var foocakes = t.map(proc(z: int): string =
+    result = toHex((z * 23).BiggestInt, 4))
+  dumpSeq foocakes
+
+  t.mapInPlace(proc(z: int): int = result = z * 30)
+  dumpSeq t
+
+  var someSeq = @[9,8,7,6,5,4,3,2,1] ## numbers < 6 or even
+  filterIt2 someSeq, it < 6 or (it and 1) == 0:
+    echo(it)
+  echo "-----------"
diff --git a/tests/manyloc/keineschweine/lib/math_helpers.nim b/tests/manyloc/keineschweine/lib/math_helpers.nim
new file mode 100644
index 000000000..5427dd80e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/math_helpers.nim
@@ -0,0 +1,10 @@
+import strutils, math
+
+proc degrees*(rad: float): float =
+  return rad * 180.0 / PI
+proc radians*(deg: float): float =
+  return deg * PI / 180.0
+
+## V not math, sue me
+proc ff*(f: float, precision = 2): string {.inline.} =
+  return formatFloat(f, ffDecimal, precision)
diff --git a/tests/manyloc/keineschweine/lib/sfml_stuff.nim b/tests/manyloc/keineschweine/lib/sfml_stuff.nim
new file mode 100644
index 000000000..5ff80b295
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sfml_stuff.nim
@@ -0,0 +1,37 @@
+import
+  math, strutils,
+  sfml, input_helpers
+when not defined(NoChipmunk):
+  import chipmunk
+  proc floor*(a: TVector): TVector2f {.inline.} =
+    result.x = a.x.floor
+    result.y = a.y.floor
+  proc sfml2cp*(a: TVector2f): TVector {.inline.} =
+    result.x = a.x
+    result.y = a.y
+  proc cp2sfml*(a: TVector): TVector2f {.inline.} =
+    result.x = a.x
+    result.y = a.y
+
+proc vec2f*(a: TVector2i): TVector2f =
+  result.x = a.x.cfloat
+  result.y = a.y.cfloat
+proc vec2i*(a: TVector2f): TVector2i =
+  result.x = a.x.cint
+  result.y = a.y.cint
+proc vec3f*(x, y, z: float): TVector3f =
+  result.x = x.cfloat
+  result.y = y.cfloat
+  result.z = z.cfloat
+
+proc `$`*(a: var TIntRect): string =
+  result = "[TIntRect $1,$2 $3x$4]".format($a.left, $a.top, $a.width, $a.height)
+proc `$`*(a: TKeyEvent): string =
+  return "KeyEvent: code=$1 alt=$2 control=$3 shift=$4 system=$5".format(
+    $a.code, $a.alt, $a.control, $a.shift, $a.system)
+
+proc `wmod`*(x, y: float): float = return x - y * (x/y).floor
+proc move*(a: var TIntRect, left, top: cint): bool =
+  if a.left != left or a.top != top: result = true
+  a.left = left
+  a.top  = top
diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim
new file mode 100644
index 000000000..96c962dc3
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_assets.nim
@@ -0,0 +1,611 @@
+import ../../../../dist/checksums/src/checksums/md5
+
+import
+  re, json, strutils, tables, math, os, math_helpers,
+  sg_packets, zlib_helpers
+
+when defined(NoSFML):
+  import server_utils
+  type TVector2i = object
+    x*, y*: int32
+  proc vec2i(x, y: int32): TVector2i =
+    result.x = x
+    result.y = y
+else:
+  import sfml, sfml_audio, sfml_stuff
+when not defined(NoChipmunk):
+  import chipmunk
+
+type
+  TChecksumFile* = object
+    unpackedSize*: int
+    sum*: MD5Digest
+    compressed*: string
+  PZoneSettings* = ref TZoneSettings
+  TZoneSettings* = object
+    vehicles: seq[PVehicleRecord]
+    items: seq[PItemRecord]
+    objects: seq[PObjectRecord]
+    bullets: seq[PBulletRecord]
+    levelSettings: PLevelSettings
+  PLevelSettings* = ref TLevelSettings
+  TLevelSettings* = object
+    size*: TVector2i
+    starfield*: seq[PSpriteSheet]
+  PVehicleRecord* = ref TVehicleRecord
+  TVehicleRecord* = object
+    id*: int16
+    name*: string
+    playable*: bool
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+    handling*: THandlingRecord
+  TItemKind* = enum
+    Projectile, Utility, Ammo
+  PObjectRecord* = ref TObjectRecord
+  TObjectRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+  PItemRecord* = ref TItemRecord
+  TItemRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord ##apply when the item is dropped in the arena
+    cooldown*: float
+    energyCost*: float
+    useSound*: PSoundRecord
+    case kind*: TItemKind
+    of Projectile:
+      bullet*: PBulletRecord
+    else:
+      discard
+  PBulletRecord* = ref TBulletRecord
+  TBulletRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+    lifetime*, inheritVelocity*, baseVelocity*: float
+    explosion*: TExplosionRecord
+    trail*: TTrailRecord
+  TTrailRecord* = object
+    anim*: PAnimationRecord
+    timer*: float ##how often it should be created
+  TPhysicsRecord* = object
+    mass*: float
+    radius*: float
+    moment*: float
+  THandlingRecord = object
+    thrust*, top_speed*: float
+    reverse*, strafe*, rotation*: float
+  TSoulRecord = object
+    energy*: int
+    health*: int
+  TExplosionRecord* = object
+    anim*: PAnimationRecord
+    sound*: PSoundRecord
+  PAnimationRecord* = ref TAnimationRecord
+  TAnimationRecord* = object
+    spriteSheet*: PSpriteSheet
+    angle*: float
+    delay*: float  ##animation delay
+  PSoundRecord* = ref TSoundRecord
+  TSoundRecord* = object
+    file*: string
+    when defined(NoSFML):
+      contents*: TChecksumFile
+    else:
+      soundBuf*: PSoundBuffer
+  PSpriteSheet* = ref TSpriteSheet
+  TSpriteSheet* = object
+    file*: string
+    framew*,frameh*: int
+    rows*, cols*: int
+    when defined(NoSFML):
+      contents*: TChecksumFile
+    when not defined(NoSFML):
+      sprite*: PSprite
+      tex*: PTexture
+  TGameState* = enum
+    Lobby, Transitioning, Field
+const
+  MomentMult* = 0.62 ## global moment of inertia multiplier
+var
+  cfg: PZoneSettings
+  SpriteSheets* = initTable[string, PSpriteSheet](64)
+  SoundCache  * = initTable[string, PSoundRecord](64)
+  nameToVehID*: Table[string, int]
+  nameToItemID*: Table[string, int]
+  nameToObjID*: Table[string, int]
+  nameToBulletID*: Table[string, int]
+  activeState = Lobby
+
+proc newSprite*(filename: string; errors: var seq[string]): PSpriteSheet
+proc load*(ss: PSpriteSheet): bool {.discardable.}
+proc newSound*(filename: string; errors: var seq[string]): PSoundRecord
+proc load*(s: PSoundRecord): bool {.discardable.}
+
+proc validateSettings*(settings: JsonNode; errors: var seq[string]): bool
+proc loadSettings*(rawJson: string, errors: var seq[string]): bool
+proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool
+
+proc fetchVeh*(name: string): PVehicleRecord
+proc fetchItm*(itm: string): PItemRecord
+proc fetchObj*(name: string): PObjectRecord
+proc fetchBullet(name: string): PBulletRecord
+
+proc importLevel(data: JsonNode; errors: var seq[string]): PLevelSettings
+proc importVeh(data: JsonNode; errors: var seq[string]): PVehicleRecord
+proc importObject(data: JsonNode; errors: var seq[string]): PObjectRecord
+proc importItem(data: JsonNode; errors: var seq[string]): PItemRecord
+proc importPhys(data: JsonNode): TPhysicsRecord
+proc importAnim(data: JsonNode; errors: var seq[string]): PAnimationRecord
+proc importHandling(data: JsonNode): THandlingRecord
+proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord
+proc importSoul(data: JsonNode): TSoulRecord
+proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord
+proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = ""): PSoundRecord
+
+## this is the only pipe between lobby and main.nim
+proc getActiveState*(): TGameState =
+  result = activeState
+proc transition*() =
+  assert activeState == Lobby, "Transition() called from a state other than lobby!"
+  activeState = Transitioning
+proc doneWithSaidTransition*() =
+  assert activeState == Transitioning, "Finished() called from a state other than transitioning!"
+  activeState = Field
+
+
+proc checksumFile*(filename: string): TChecksumFile =
+  let fullText = readFile(filename)
+  result.unpackedSize = fullText.len
+  result.sum = toMD5(fullText)
+  result.compressed = compress(fullText)
+proc checksumStr*(str: string): TChecksumFile =
+  result.unpackedSize = str.len
+  result.sum = toMD5(str)
+  result.compressed = compress(str)
+
+
+##at this point none of these should ever be freed
+proc free*(obj: PZoneSettings) =
+  echo "Free'd zone settings"
+proc free*(obj: PSpriteSheet) =
+  echo "Free'd ", obj.file
+proc free*(obj: PSoundRecord) =
+  echo "Free'd ", obj.file
+
+proc loadAllAssets*() =
+  var
+    loaded = 0
+    failed = 0
+  for name, ss in SpriteSheets.pairs():
+    if load(ss):
+      inc loaded
+    else:
+      inc failed
+  echo loaded," sprites loaded. ", failed, " sprites failed."
+  loaded = 0
+  failed = 0
+  for name, s in SoundCache.pairs():
+    if load(s):
+      inc loaded
+    else:
+      inc failed
+  echo loaded, " sounds loaded. ", failed, " sounds failed."
+proc getLevelSettings*(): PLevelSettings =
+  result = cfg.levelSettings
+
+iterator playableVehicles*(): PVehicleRecord =
+  for v in cfg.vehicles.items():
+    if v.playable:
+      yield v
+
+template allAssets*(body: untyped) {.dirty.}=
+  block:
+    var assetType = FGraphics
+    for file, asset in pairs(SpriteSheets):
+      body
+    assetType = FSound
+    for file, asset in pairs(SoundCache):
+      body
+
+template cacheImpl(procName, cacheName, resultType, body: untyped) {.dirty.} =
+  proc procName*(filename: string; errors: var seq[string]): resulttype =
+    if hasKey(cacheName, filename):
+      return cacheName[filename]
+    new(result, free)
+    body
+    cacheName[filename] = result
+
+template checkFile(path: untyped) {.dirty.} =
+  if not fileExists(path):
+    errors.add("File missing: " & path)
+
+cacheImpl newSprite, SpriteSheets, PSpriteSheet:
+  result.file = filename
+  if filename =~ re"\S+_(\d+)x(\d+)\.\S\S\S":
+    result.framew = strutils.parseInt(matches[0])
+    result.frameh = strutils.parseInt(matches[1])
+    checkFile("data/gfx"/result.file)
+  else:
+    errors.add "Bad file: " & filename & " must be in format name_WxH.png"
+    return
+
+cacheImpl newSound, SoundCache, PSoundRecord:
+  result.file = filename
+  checkFile("data/sfx"/result.file)
+
+proc expandPath*(assetType: TAssetType; fileName: string): string =
+  result = "data/"
+  case assetType
+  of FGraphics: result.add "gfx/"
+  of FSound:    result.add "sfx/"
+  else: discard
+  result.add fileName
+proc expandPath*(fc: ScFileChallenge): string {.inline.} =
+  result = expandPath(fc.assetType, fc.file)
+
+when defined(NoSFML):
+  proc load*(ss: PSpriteSheet): bool =
+    if not ss.contents.unpackedSize == 0: return
+    ss.contents = checksumFile(expandPath(FGraphics, ss.file))
+    result = true
+  proc load*(s: PSoundRecord): bool =
+    if not s.contents.unpackedSize == 0: return
+    s.contents = checksumFile(expandPath(FSound, s.file))
+    result = true
+else:
+  proc load*(ss: PSpriteSheet): bool =
+    if not ss.sprite.isNil:
+      return
+    var image = sfml.newImage("data/gfx/"/ss.file)
+    if image == nil:
+      echo "Image could not be loaded"
+      return
+    let size = image.getSize()
+    ss.rows = int(size.y / ss.frameh) #y is h
+    ss.cols = int(size.x / ss.framew) #x is w
+    ss.tex = newTexture(image)
+    image.destroy()
+    ss.sprite = newSprite()
+    ss.sprite.setTexture(ss.tex, true)
+    ss.sprite.setTextureRect(intrect(0, 0, ss.framew.cint, ss.frameh.cint))
+    ss.sprite.setOrigin(vec2f(ss.framew / 2, ss.frameh / 2))
+    result = true
+  proc load*(s: PSoundRecord): bool =
+    s.soundBuf = newSoundBuffer("data/sfx"/s.file)
+    if not s.soundBuf.isNil:
+      result = true
+
+template addError(e: untyped) =
+  errors.add(e)
+  result = false
+proc validateSettings*(settings: JsonNode, errors: var seq[string]): bool =
+  result = true
+  if settings.kind != JObject:
+    addError("Settings root must be an object")
+    return
+  if not settings.hasKey("vehicles"):
+    addError("Vehicles section missing")
+  if not settings.hasKey("objects"):
+    errors.add("Objects section is missing")
+    result = false
+  if not settings.hasKey("level"):
+    errors.add("Level settings section is missing")
+    result = false
+  else:
+    let lvl = settings["level"]
+    if lvl.kind != JObject or not lvl.hasKey("size"):
+      errors.add("Invalid level settings")
+      result = false
+    elif not lvl.hasKey("size") or lvl["size"].kind != JArray or lvl["size"].len != 2:
+      errors.add("Invalid/missing level size")
+      result = false
+  if not settings.hasKey("items"):
+    errors.add("Items section missing")
+    result = false
+  else:
+    let items = settings["items"]
+    if items.kind != JArray or items.len == 0:
+      errors.add "Invalid or empty item list"
+    else:
+      var id = 0
+      for i in items.items:
+        if i.kind != JArray: errors.add("Item #$1 is not an array" % $id)
+        elif i.len != 3: errors.add("($1) Item record should have 3 fields"%($id))
+        elif i[0].kind != JString or i[1].kind != JString or i[2].kind != JObject:
+          errors.add("($1) Item should be in form [name, type, {item: data}]" % $id)
+          result = false
+        inc id
+
+proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool =
+  if not fileExists(filename):
+    errors.add("File does not exist: "&filename)
+  else:
+    result = loadSettings(readFile(filename), errors)
+
+proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
+  var settings: JsonNode
+  try:
+    settings = parseJson(rawJson)
+  except JsonParsingError:
+    errors.add("JSON parsing error: " & getCurrentExceptionMsg())
+    return
+  except:
+    errors.add("Unknown exception: " & getCurrentExceptionMsg())
+    return
+  if not validateSettings(settings, errors):
+    return
+  if cfg != nil: #TODO try this
+    echo("Overwriting zone settings")
+    free(cfg)
+    cfg = nil
+  new(cfg, free)
+  cfg.levelSettings = importLevel(settings, errors)
+  cfg.vehicles = @[]
+  cfg.items = @[]
+  cfg.objects = @[]
+  cfg.bullets = @[]
+  nameToVehID = initTable[string, int](32)
+  nameToItemID = initTable[string, int](32)
+  nameToObjID = initTable[string, int](32)
+  nameToBulletID = initTable[string, int](32)
+  var
+    vID = 0'i16
+    bID = 0'i16
+  for vehicle in settings["vehicles"].items:
+    var veh = importVeh(vehicle, errors)
+    veh.id = vID
+    cfg.vehicles.add veh
+    nameToVehID[veh.name] = veh.id
+    inc vID
+  vID = 0
+  if settings.hasKey("bullets"):
+    for blt in settings["bullets"].items:
+      var bullet = importBullet(blt, errors)
+      bullet.id = bID
+      cfg.bullets.add bullet
+      nameToBulletID[bullet.name] = bullet.id
+      inc bID
+  for item in settings["items"].items:
+    var itm = importItem(item, errors)
+    itm.id = vID
+    cfg.items.add itm
+    nameToItemID[itm.name] = itm.id
+    inc vID
+    if itm.kind == Projectile:
+      if itm.bullet.isNil:
+        errors.add("Projectile #$1 has no bullet!" % $vID)
+      elif itm.bullet.id == -1:
+        ## this item has an anonymous bullet, fix the ID and name
+        itm.bullet.id = bID
+        itm.bullet.name = itm.name
+        cfg.bullets.add itm.bullet
+        nameToBulletID[itm.bullet.name] = itm.bullet.id
+        inc bID
+  vID = 0
+  for obj in settings["objects"].items:
+    var o = importObject(obj, errors)
+    o.id = vID
+    cfg.objects.add o
+    nameToObjID[o.name] = o.id
+    inc vID
+  result = (errors.len == 0)
+
+proc `$`*(obj: PSpriteSheet): string =
+  return "<Sprite $1 ($2x$3) $4 rows $5 cols>" % [obj.file, $obj.framew, $obj.frameh, $obj.rows, $obj.cols]
+
+proc fetchVeh*(name: string): PVehicleRecord =
+  return cfg.vehicles[nameToVehID[name]]
+proc fetchItm*(itm: string): PItemRecord =
+  return cfg.items[nameToItemID[itm]]
+proc fetchObj*(name: string): PObjectRecord =
+  return cfg.objects[nameToObjID[name]]
+proc fetchBullet(name: string): PBulletRecord =
+  return cfg.bullets[nameToBulletID[name]]
+
+proc getField(node: JsonNode, field: string, target: var float) =
+  if not node.hasKey(field):
+    return
+  if node[field].kind == JFloat:
+    target = node[field].fnum
+  elif node[field].kind == JInt:
+    target = node[field].num.float
+proc getField(node: JsonNode, field: string, target: var int) =
+  if not node.hasKey(field):
+    return
+  if node[field].kind == JInt:
+    target = node[field].num.int
+  elif node[field].kind == JFloat:
+    target = node[field].fnum.int
+proc getField(node: JsonNode; field: string; target: var bool) =
+  if not node.hasKey(field):
+    return
+  case node[field].kind
+  of JBool:
+    target = node[field].bval
+  of JInt:
+    target = (node[field].num != 0)
+  of JFloat:
+    target = (node[field].fnum != 0.0)
+  else: discard
+
+template checkKey(node: untyped; key: string) =
+  if not hasKey(node, key):
+    return
+
+proc importTrail(data: JsonNode; errors: var seq[string]): TTrailRecord =
+  checkKey(data, "trail")
+  result.anim = importAnim(data["trail"], errors)
+  result.timer = 1000.0
+  getField(data["trail"], "timer", result.timer)
+  result.timer /= 1000.0
+proc importLevel(data: JsonNode; errors: var seq[string]): PLevelSettings =
+  new(result)
+  result.size = vec2i(5000, 5000)
+  result.starfield = @[]
+
+  checkKey(data, "level")
+  var level = data["level"]
+  if level.hasKey("size") and level["size"].kind == JArray and level["size"].len == 2:
+    result.size.x = level["size"][0].num.cint
+    result.size.y = level["size"][1].num.cint
+  if level.hasKey("starfield"):
+    for star in level["starfield"].items:
+      result.starfield.add(newSprite(star.str, errors))
+proc importPhys(data: JsonNode): TPhysicsRecord =
+  result.radius = 20.0
+  result.mass = 10.0
+
+  if data.hasKey("physics") and data["physics"].kind == JObject:
+    let phys = data["physics"]
+    phys.getField("radius", result.radius)
+    phys.getField("mass", result.mass)
+  when not defined(NoChipmunk):
+    result.moment = momentForCircle(result.mass, 0.0, result.radius, VectorZero) * MomentMult
+proc importHandling(data: JsonNode): THandlingRecord =
+  result.thrust = 45.0
+  result.topSpeed = 100.0 #unused
+  result.reverse = 30.0
+  result.strafe = 30.0
+  result.rotation = 2200.0
+
+  checkKey(data, "handling")
+  if data["handling"].kind != JObject:
+    return
+
+  let hand = data["handling"]
+  hand.getField("thrust", result.thrust)
+  hand.getField("top_speed", result.topSpeed)
+  hand.getField("reverse", result.reverse)
+  hand.getField("strafe", result.strafe)
+  hand.getField("rotation", result.rotation)
+proc importAnim(data: JsonNode, errors: var seq[string]): PAnimationRecord =
+  new(result)
+  result.angle = 0.0
+  result.delay = 1000.0
+  result.spriteSheet = nil
+
+  if data.hasKey("anim"):
+    let anim = data["anim"]
+    if anim.kind == JObject:
+      if anim.hasKey("file"):
+        result.spriteSheet = newSprite(anim["file"].str, errors)
+
+      anim.getField "angle", result.angle
+      anim.getField "delay", result.delay
+    elif data["anim"].kind == JString:
+      result.spriteSheet = newSprite(anim.str, errors)
+
+  result.angle = radians(result.angle) ## comes in as degrees
+  result.delay /= 1000 ## delay comes in as milliseconds
+proc importSoul(data: JsonNode): TSoulRecord =
+  result.energy = 10000
+  result.health = 1
+  checkKey(data, "soul")
+  let soul = data["soul"]
+  soul.getField("energy", result.energy)
+  soul.getField("health", result.health)
+proc importExplosion(data: JsonNode; errors: var seq[string]): TExplosionRecord =
+  checkKey(data, "explode")
+  let expl = data["explode"]
+  result.anim = importAnim(expl, errors)
+  result.sound = importSound(expl, errors, "sound")
+proc importSound*(data: JsonNode; errors: var seq[string]; fieldName: string = ""): PSoundRecord =
+  if data.kind == JObject:
+    checkKey(data, fieldName)
+    result = newSound(data[fieldName].str, errors)
+  elif data.kind == JString:
+    result = newSound(data.str, errors)
+
+proc importVeh(data: JsonNode; errors: var seq[string]): PVehicleRecord =
+  new(result)
+  result.playable = false
+  if data.kind != JArray or data.len != 2 or
+    (data.kind == JArray and
+      (data[0].kind != JString or data[1].kind != JObject)):
+    result.name = "(broken)"
+    errors.add "Vehicle record is malformed"
+    return
+  var vehData = data[1]
+  result.name = data[0].str
+  result.anim = importAnim(vehdata, errors)
+  result.physics = importPhys(vehdata)
+  result.handling = importHandling(vehdata)
+  vehdata.getField("playable", result.playable)
+  if result.anim.spriteSheet.isNil and result.playable:
+    result.playable = false
+proc importObject(data: JsonNode; errors: var seq[string]): PObjectRecord =
+  new(result)
+  if data.kind != JArray or data.len != 2:
+    result.name = "(broken)"
+    return
+  result.name = data[0].str
+  result.anim = importAnim(data[1], errors)
+  result.physics = importPhys(data[1])
+proc importItem(data: JsonNode; errors: var seq[string]): PItemRecord =
+  new(result)
+  if data.kind != JArray or data.len != 3:
+    result.name = "(broken)"
+    errors.add "Item record is malformed"
+    return
+  result.name = data[0].str
+  result.anim = importAnim(data[2], errors)
+  result.physics = importPhys(data[2])
+
+  result.cooldown = 100.0
+  data[2].getField("cooldown", result.cooldown)
+  result.cooldown /= 1000.0  ##cooldown is stored in ms
+
+  result.useSound = importSound(data[2], errors, "useSound")
+
+  case data[1].str.toLowerAscii
+  of "projectile":
+    result.kind = Projectile
+    if data[2]["bullet"].kind == JString:
+      result.bullet = fetchBullet(data[2]["bullet"].str)
+    elif data[2]["bullet"].kind == JInt:
+      result.bullet = cfg.bullets[data[2]["bullet"].num.int]
+    elif data[2]["bullet"].kind == JObject:
+      result.bullet = importBullet(data[2]["bullet"], errors)
+    else:
+      errors.add "UNKNOWN BULLET TYPE for item " & result.name
+  of "ammo":
+    result.kind = Ammo
+  of "utility":
+    discard
+  else:
+    errors.add "Invalid item type \""&data[1].str&"\" for item "&result.name
+
+proc importBullet(data: JsonNode; errors: var seq[string]): PBulletRecord =
+  new(result)
+  result.id = -1
+
+  var bdata: JsonNode
+  if data.kind == JArray:
+    result.name = data[0].str
+    bdata = data[1]
+  elif data.kind == JObject:
+    bdata = data
+  else:
+    errors.add "Malformed bullet record"
+    return
+
+  result.anim = importAnim(bdata, errors)
+  result.physics = importPhys(bdata)
+
+  result.lifetime = 2000.0
+  result.inheritVelocity = 1000.0
+  result.baseVelocity = 30.0
+  getField(bdata, "lifetime", result.lifetime)
+  getField(bdata, "inheritVelocity", result.inheritVelocity)
+  getField(bdata, "baseVelocity", result.baseVelocity)
+  result.lifetime /= 1000.0 ## lifetime is stored as milliseconds
+  result.inheritVelocity /= 1000.0 ## inherit velocity 1000 = 1.0 (100%)
+  result.explosion = importExplosion(bdata, errors)
+  result.trail = importTrail(bdata, errors)
diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim
new file mode 100644
index 000000000..bcf415556
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_gui.nim
@@ -0,0 +1,281 @@
+import
+  sfml, sfml_colors,
+  input_helpers, sg_packets
+from strutils import countlines
+
+type
+  PGuiContainer* = ref TGuiContainer
+  TGuiContainer* = object of RootObj
+    position: TVector2f
+    activeEntry: PTextEntry
+    widgets: seq[PGuiObject]
+    buttons: seq[PButton]
+  PGuiObject* = ref TGuiObject
+  TGuiObject* = object of RootObj
+  PButton* = ref TButton
+  TButton* = object of TGuiObject
+    enabled: bool
+    bg*: sfml.PRectangleShape
+    text*: PText
+    onClick*: TButtonClicked
+    bounds: TFloatRect
+  PButtonCollection* = ref TButtonCollection
+  TButtonCollection* = object of TGuiContainer
+  PTextEntry* = ref TTextEntry
+  TTextEntry* = object of TButton
+    inputClient: input_helpers.PTextInput
+  PMessageArea* = ref TMessageArea
+  TMessageArea* = object of TGuiObject
+    pos: TVector2f
+    messages: seq[TMessage]
+    texts: seq[PText]
+    scrollBack*: int
+    sizeVisible*: int
+    direction*: int
+  TMessage = object
+    color: TColor
+    text: string
+    lines: int
+  TButtonClicked = proc(button: PButton)
+var
+  guiFont* = newFont("data/fnt/LiberationMono-Regular.ttf")
+  messageProto* = newText("", guiFont, 16)
+let
+  vectorZeroF* = vec2f(0.0, 0.0)
+
+proc newGuiContainer*(): PGuiContainer
+proc newGuiContainer*(pos: TVector2f): PGuiContainer {.inline.}
+proc free*(container: PGuiContainer)
+proc add*(container: PGuiContainer; widget: PGuiObject)
+proc clearButtons*(container: PGuiContainer)
+proc click*(container: PGuiContainer; position: TVector2f)
+proc setActive*(container: PGuiContainer; entry: PTextEntry)
+proc setPosition*(container: PGuiContainer; position: TVector2f)
+
+proc update*(container: PGuiContainer; dt: float)
+proc draw*(window: PRenderWindow; container: PGuiContainer) {.inline.}
+
+proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea {.discardable.}
+proc add*(m: PMessageArea; msg: ScChat)
+
+proc draw*(window: PRenderWindow; b: PButton) {.inline.}
+proc click*(b: PButton; p: TVector2f)
+proc setPosition*(b: PButton; p: TVector2f)
+proc setString*(b: PButton; s: string) {.inline.}
+
+proc newButton*(container: PGuiContainer; text: string; position: TVector2f;
+  onClick: TButtonClicked; startEnabled: bool = true): PButton {.discardable.}
+proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked)
+proc setEnabled*(b: PButton; enabled: bool)
+proc disable*(b: PButton) {.inline.}
+proc enable*(b: PButton) {.inline.}
+
+proc newTextEntry*(container: PGuiContainer; text: string;
+                    position: TVector2f; onEnter: TInputFinishedProc = nil): PTextEntry {.discardable.}
+proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc)
+proc draw*(window: PRenderWindow, t: PTextEntry) {.inline.}
+proc setActive*(t: PTextEntry) {.inline.}
+proc clearText*(t: PTextEntry) {.inline.}
+proc getText*(t: PTextEntry): string {.inline.}
+
+proc update*(m: PMessageArea)
+
+if guiFont == nil:
+  echo("Could not load font, crying softly to myself.")
+  quit(1)
+
+proc newGuiContainer*(): PGuiContainer =
+  new(result, free)
+  result.widgets = @[]
+  result.buttons = @[]
+proc newGuiContainer*(pos: TVector2f): PGuiContainer =
+  result = newGuiContainer()
+  result.setPosition pos
+proc free*(container: PGuiContainer) =
+  container.widgets = @[]
+  container.buttons = @[]
+proc add*(container: PGuiContainer; widget: PGuiObject) =
+  container.widgets.add(widget)
+proc add*(container: PGuiContainer; button: PButton) =
+  if container.isNil: return
+  container.buttons.add(button)
+proc clearButtons*(container: PGuiContainer) =
+  container.buttons.setLen 0
+proc click*(container: PGuiContainer; position: TVector2f) =
+  for b in container.buttons:
+    click(b, position)
+proc setActive*(container: PGuiContainer; entry: PTextEntry) =
+  container.activeEntry = entry
+  setActive(entry)
+proc setPosition*(container: PGuiContainer; position: TVector2f) =
+  container.position = position
+
+
+proc update*(container: PGuiContainer; dt: float) =
+  if not container.activeEntry.isNil:
+    container.activeEntry.setString(container.activeEntry.getText())
+proc draw*(window: PRenderWindow; container: PGuiContainer) =
+  for b in container.buttons:
+    window.draw b
+
+proc free(c: PButton) =
+  c.bg.destroy()
+  c.text.destroy()
+  c.bg = nil
+  c.text = nil
+  c.onClick = nil
+proc newButton*(container: PGuiContainer; text: string;
+                 position: TVector2f; onClick: TButtonClicked;
+                 startEnabled: bool = true): PButton =
+  new(result, free)
+  init(result,
+       text,
+       if not container.isNil: position + container.position else: position,
+       onClick)
+  container.add result
+  if not startEnabled: disable(result)
+
+proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked) =
+  b.bg = newRectangleShape()
+  b.bg.setSize(vec2f(80.0, 16.0))
+  b.bg.setFillColor(color(20, 30, 15))
+  b.text = newText(text, guiFont, 16)
+  b.onClick = onClick
+  b.setPosition(position)
+  b.enabled = true
+proc copy*(c: PButton): PButton =
+  new(result, free)
+  result.bg = c.bg.copy()
+  result.text = c.text.copy()
+  result.onClick = c.onClick
+  result.setPosition(result.bg.getPosition())
+
+proc setEnabled*(b: PButton; enabled: bool) =
+  b.enabled = enabled
+  if enabled:
+    b.text.setColor(White)
+  else:
+    b.text.setColor(Gray)
+proc enable*(b: PButton) = setEnabled(b, true)
+proc disable*(b: PButton) = setEnabled(b, false)
+
+proc draw*(window: PRenderWindow; b: PButton) =
+  window.draw b.bg
+  window.draw b.text
+proc setPosition*(b: PButton, p: TVector2f) =
+  b.bg.setPosition(p)
+  b.text.setPosition(p)
+  b.bounds = b.text.getGlobalBounds()
+proc setString*(b: PButton; s: string) =
+  b.text.setString(s)
+proc click*(b: PButton, p: TVector2f) =
+  if b.enabled and (addr b.bounds).contains(p.x, p.y):
+    b.onClick(b)
+
+proc free(obj: PTextEntry) =
+  free(PButton(obj))
+proc newTextEntry*(container: PGuiContainer; text: string;
+                    position: TVector2F; onEnter: TInputFinishedProc = nil): PTextEntry =
+  new(result, free)
+  init(PButton(result), text, position + container.position, proc(b: PButton) =
+    setActive(container, PTextEntry(b)))
+  init(result, text, onEnter)
+  container.add result
+proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc) =
+  t.inputClient = newTextInput(text, text.len, onEnter)
+proc draw(window: PRenderWindow; t: PTextEntry) =
+  window.draw PButton(t)
+proc clearText*(t: PTextEntry) =
+  t.inputClient.clear()
+proc getText*(t: PTextEntry): string =
+  return t.inputClient.text
+proc setActive*(t: PTextEntry) =
+  if not t.isNil and not t.inputClient.isNil:
+    input_helpers.setActive(t.inputClient)
+
+when false:
+  proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea =
+    new(result)
+    result.messages = @[]
+    result.pos = position
+    container.add(result)
+  proc add*(m: PMessageArea, text: string): PText =
+    result = messageProto.copy()
+    result.setString(text)
+    m.messages.add(result)
+    let nmsgs = len(m.messages)
+    var pos   = vec2f(m.pos.x, m.pos.y)
+    for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)):
+      setPosition(m.messages[i], pos)
+      pos.y -= 16.0
+
+  proc draw*(window: PRenderWindow; m: PMessageArea) =
+    let nmsgs = len(m.messages)
+    if nmsgs == 0: return
+    for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)):
+      window.draw(m.messages[i])
+
+proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea =
+  new(result)
+  result.messages = @[]
+  result.texts = @[]
+  result.pos = position + container.position
+  result.sizeVisible = 10
+  result.scrollBack = 0
+  result.direction = -1 ## to push old messages up
+  container.add(result)
+
+proc add*(m: PMessageArea, msg: ScChat) =
+  const prependName = {CPub, CPriv}
+  var mmm: TMessage
+  if msg.kind in prependName:
+    mmm.text = "<"
+    mmm.text.add msg.fromPlayer
+    mmm.text.add "> "
+    mmm.text.add msg.text
+  else:
+    mmm.text = msg.text
+  case msg.kind
+  of CPub:  mmm.color = RoyalBlue
+  of CPriv, CSystem: mmm.color = Green
+  of CError: mmm.color = Red
+
+  mmm.lines = countLines(mmm.text)
+
+  m.messages.add mmm
+  update m
+proc add*(m: PMessageArea, msg: string) {.inline.} =
+  var chat = newScChat(kind = CSystem, text = msg)
+  add(m, chat)
+
+proc proctor*(m: PText; msg: ptr TMessage; pos: ptr TVector2f) =
+  m.setString msg.text
+  m.setColor msg.color
+  m.setPosition pos[]
+proc update*(m: PMessageArea) =
+  if m.texts.len < m.sizeVisible:
+    echo "adding ", m.sizeVisible - m.texts.len, " fields"
+    for i in 1..m.sizeVisible - m.texts.len:
+      var t = messageProto.copy()
+      m.texts.add messageProto.copy()
+  elif m.texts.len > m.sizeVisible:
+    echo "cutting ", m.texts.len - m.sizeVisible, " fields"
+    for i in m.sizeVisible ..< m.texts.len:
+      m.texts.pop().destroy()
+  let nmsgs = m.messages.len()
+  if m.sizeVisible == 0 or nmsgs == 0:
+    echo "no messages? ", m.sizeVisible, ", ", nmsgs
+    return
+  var pos = vec2f(m.pos.x, m.pos.y)
+  for i in 0.. min(m.sizeVisible, nmsgs)-1:
+    ##echo nmsgs - i - 1 - m.scrollBack
+    let msg = addr m.messages[nmsgs - i - 1 - m.scrollBack]
+    proctor(m.texts[i], msg, addr pos)
+    pos.y += (16 * m.direction * msg.lines).cfloat
+
+proc draw*(window: PRenderWindow; m: PMessageArea) =
+  let nmsgs = len(m.texts)
+  if nmsgs == 0: return
+  for i in countdown(nmsgs - 1, max(nmsgs - m.sizeVisible, 0)):
+    window.draw m.texts[i]
+
diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim
new file mode 100644
index 000000000..797a60706
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_packets.nim
@@ -0,0 +1,110 @@
+import ../../../../dist/checksums/src/checksums/md5
+
+import genpacket_enet, nativesockets, net, enet
+defPacketImports()
+
+type
+  PacketID* = char
+
+template idpacket(pktName, id, s2c, c2s: untyped) {.dirty.} =
+  let `H pktName`* {.inject.} = id
+  defPacket(`Sc pktName`, s2c)
+  defPacket(`Cs pktName`, c2s)
+
+forwardPacketT(uint8, int8)
+forwardPacketT(uint16, int16)
+forwardPacketT(Port, int16)
+
+idPacket(Login, 'a',
+  tuple[id: int32; alias: string; sessionKey: string],
+  tuple[alias: string, passwd: string])
+
+let HZoneJoinReq* = 'j'
+defPacket(CsZoneJoinReq, tuple[session: ScLogin])
+
+defPacket(ScZoneRecord, tuple[
+  name: string = "", desc: string = "",
+  ip: string = "", port: Port = 0.Port])
+idPacket(ZoneList, 'z',
+  tuple[network: string = "", zones: seq[ScZoneRecord]],
+  tuple[time: string])
+
+let HPoing* = 'p'
+defPacket(Poing, tuple[id: int32, time: float32])
+
+type ChatType* = enum
+  CPub = 0'i8, CPriv, CSystem, CError
+forwardPacketT(ChatType, int8)
+idPacket(Chat, 'C',
+  tuple[kind: ChatType = CPub; fromPlayer: string = ""; text: string = ""],
+  tuple[target: string = ""; text: string = ""])
+
+idPacket(Hello, 'h',
+  tuple[resp: string],
+  tuple[i: int8 = 14])
+
+let HPlayerList* = 'P'
+defPacket(ScPlayerRec, tuple[id: int32; alias: string = ""])
+defPacket(ScPlayerList, tuple[players: seq[ScPlayerRec]])
+
+let HTeamList* = 'T'
+defPacket(ScTeam, tuple[id: int8; name: string = ""])
+defPacket(ScTeamList, tuple[teams: seq[ScTeam]])
+let HTeamChange* = 't'
+
+idPacket(ZoneQuery, 'Q',
+  tuple[playerCount: uint16], ##i should include a time here or something
+  tuple[pad: char = '\0'])
+
+type SpawnKind = enum
+  SpawnDummy,
+  SpawnItem, SpawnVehicle, SpawnObject
+forwardPacketT(SpawnKind, int8)
+defPacket(ScSpawn, tuple[
+  kind: SpawnKind; id: uint16; record: uint16; amount: uint16])
+
+
+
+
+type TAssetType* = enum
+  FDummy,
+  FZoneCfg, FGraphics, FSound
+
+forwardPacketT(TAssetType, int8)
+forwardPacket(MD5Digest, array[0..15, int8])
+
+idPacket(FileChallenge, 'F',
+  tuple[file: string; assetType: TAssetType; fullLen: int32],
+  tuple[needFile: bool; checksum: MD5Digest])
+
+
+let HChallengeResult* = '('
+defPacket(ScChallengeResult, tuple[status: bool])
+
+let HFileTransfer* = 'f'
+defPacket(ScFileTransfer, tuple[fileSize: int32; pos: int32; data: string])
+defPacket(CsFilepartAck, tuple[lastpos: int32])
+
+##dir server messages
+let HZoneLogin* = 'u'
+defPacket(SdZoneLogin, tuple[name: string; key: string; record: ScZoneRecord])
+defPacket(DsZoneLogin, tuple[status: bool])
+let HDsMsg* = 'c'
+defPacket(DsMsg, tuple[msg: string])
+let HVerifyClient* = 'v'
+defPacket(SdVerifyClient, tuple[session: ScLogin])
+
+when true:
+
+  var buf = newBuffer(100)
+  var m = toMd5("hello there")
+  echo(repr(m))
+  buf.pack m
+
+  echo(repr(buf.data))
+  echo(len(buf.data))
+
+  buf.reset()
+
+  var x = buf.readMD5Digest()
+  echo(repr(x))
diff --git a/tests/manyloc/keineschweine/lib/sound_buffer.nim b/tests/manyloc/keineschweine/lib/sound_buffer.nim
new file mode 100644
index 000000000..a88eb08de
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sound_buffer.nim
@@ -0,0 +1,38 @@
+when defined(NoSFML) or defined(NoChipmunk):
+  {.error.}
+import sfml_audio, sfml_stuff, sg_assets, chipmunk
+const
+  MinDistance* = 350.0
+  Attenuation* = 20.0
+var
+  liveSounds: seq[PSound] = @[]
+  deadSounds: seq[PSound] = @[]
+
+proc playSound*(sound: PSoundRecord, pos: TVector) =
+  if sound.isNil or sound.soundBuf.isNil: return
+  var s: PSound
+  if deadSounds.len == 0:
+    s = sfml_audio.newSound()
+    s.setLoop false
+    s.setRelativeToListener true
+    s.setAttenuation Attenuation
+    s.setMinDistance MinDistance
+  else:
+    s = deadSounds.pop()
+  s.setPosition(vec3f(pos.x, 0, pos.y))
+  s.setBuffer(sound.soundBuf)
+  s.play()
+  liveSounds.add s
+
+proc updateSoundBuffer*() =
+  var i = 0
+  while i < len(liveSounds):
+    if liveSounds[i].getStatus == Stopped:
+      deadSounds.add liveSounds[i]
+      liveSounds.del i
+    else:
+      inc i
+
+proc report*() =
+  echo "live: ", liveSounds.len
+  echo "dead: ", deadSounds.len
diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim
new file mode 100644
index 000000000..2c6e54d2b
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/vehicles.nim
@@ -0,0 +1,35 @@
+import
+  sfml, chipmunk,
+  sg_assets, sfml_stuff#, "../keineschweine"
+
+
+proc accel*(obj: PVehicle, dt: float) =
+  #obj.velocity += vec2f(
+  #  cos(obj.angle) * obj.record.handling.thrust.float * dt,
+  #  sin(obj.angle) * obj.record.handling.thrust.float * dt)
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.thrust,
+    VectorZero)
+proc reverse*(obj: PVehicle, dt: float) =
+  #obj.velocity += vec2f(
+  #  -cos(obj.angle) * obj.record.handling.reverse.float * dt,
+  #  -sin(obj.angle) * obj.record.handling.reverse.float * dt)
+  obj.body.applyImpulse(
+    -vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.reverse,
+    VectorZero)
+proc strafe_left*(obj: PVehicle, dt: float) =
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()).perp() * obj.record.handling.strafe * dt,
+    VectorZero)
+proc strafe_right*(obj: PVehicle, dt: float) =
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()).rperp() * obj.record.handling.strafe * dt,
+    VectorZero)
+proc turn_right*(obj: PVehicle, dt: float) =
+  #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
+  obj.body.setTorque(obj.record.handling.rotation)
+proc turn_left*(obj: PVehicle, dt: float) =
+  #obj.angle = (obj.angle - (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
+  obj.body.setTorque(-obj.record.handling.rotation)
+proc offsetAngle*(obj: PVehicle): float {.inline.} =
+  return (obj.record.anim.angle + obj.body.getAngle())
diff --git a/tests/manyloc/keineschweine/lib/wingl.nim b/tests/manyloc/keineschweine/lib/wingl.nim
new file mode 100644
index 000000000..5bd199911
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/wingl.nim
@@ -0,0 +1,368 @@
+import
+  gl, windows
+
+proc wglGetExtensionsStringARB*(hdc: HDC): cstring{.dynlib: dllname,
+    importc: "wglGetExtensionsStringARB".}
+const
+  WGL_FRONT_COLOR_BUFFER_BIT_ARB* = 0x00000001
+  WGL_BACK_COLOR_BUFFER_BIT_ARB* = 0x00000002
+  WGL_DEPTH_BUFFER_BIT_ARB* = 0x00000004
+  WGL_STENCIL_BUFFER_BIT_ARB* = 0x00000008
+
+proc WinChoosePixelFormat*(DC: HDC, p2: PPixelFormatDescriptor): int{.
+    dynlib: "gdi32", importc: "ChoosePixelFormat".}
+proc wglCreateBufferRegionARB*(hDC: HDC, iLayerPlane: TGLint, uType: TGLuint): THandle{.
+    dynlib: dllname, importc: "wglCreateBufferRegionARB".}
+proc wglDeleteBufferRegionARB*(hRegion: THandle){.dynlib: dllname,
+    importc: "wglDeleteBufferRegionARB".}
+proc wglSaveBufferRegionARB*(hRegion: THandle, x: TGLint, y: TGLint,
+                             width: TGLint, height: TGLint): BOOL{.
+    dynlib: dllname, importc: "wglSaveBufferRegionARB".}
+proc wglRestoreBufferRegionARB*(hRegion: THandle, x: TGLint, y: TGLint,
+                                width: TGLint, height: TGLint, xSrc: TGLint,
+                                ySrc: TGLint): BOOL{.dynlib: dllname,
+    importc: "wglRestoreBufferRegionARB".}
+proc wglAllocateMemoryNV*(size: TGLsizei, readFrequency: TGLfloat,
+                          writeFrequency: TGLfloat, priority: TGLfloat): PGLvoid{.
+    dynlib: dllname, importc: "wglAllocateMemoryNV".}
+proc wglFreeMemoryNV*(pointer: PGLvoid){.dynlib: dllname,
+    importc: "wglFreeMemoryNV".}
+const
+  WGL_IMAGE_BUFFER_MIN_ACCESS_I3D* = 0x00000001
+  WGL_IMAGE_BUFFER_LOCK_I3D* = 0x00000002
+
+proc wglCreateImageBufferI3D*(hDC: HDC, dwSize: DWORD, uFlags: UINT): PGLvoid{.
+    dynlib: dllname, importc: "wglCreateImageBufferI3D".}
+proc wglDestroyImageBufferI3D*(hDC: HDC, pAddress: PGLvoid): BOOL{.
+    dynlib: dllname, importc: "wglDestroyImageBufferI3D".}
+proc wglAssociateImageBufferEventsI3D*(hdc: HDC, pEvent: PHandle,
+                                       pAddress: PGLvoid, pSize: PDWORD,
+                                       count: UINT): BOOL{.dynlib: dllname,
+    importc: "wglAssociateImageBufferEventsI3D".}
+proc wglReleaseImageBufferEventsI3D*(hdc: HDC, pAddress: PGLvoid, count: UINT): BOOL{.
+    dynlib: dllname, importc: "wglReleaseImageBufferEventsI3D".}
+proc wglEnableFrameLockI3D*(): BOOL{.dynlib: dllname,
+                                     importc: "wglEnableFrameLockI3D".}
+proc wglDisableFrameLockI3D*(): BOOL{.dynlib: dllname,
+                                      importc: "wglDisableFrameLockI3D".}
+proc wglIsEnabledFrameLockI3D*(pFlag: PBOOL): BOOL{.dynlib: dllname,
+    importc: "wglIsEnabledFrameLockI3D".}
+proc wglQueryFrameLockMasterI3D*(pFlag: PBOOL): BOOL{.dynlib: dllname,
+    importc: "wglQueryFrameLockMasterI3D".}
+proc wglGetFrameUsageI3D*(pUsage: PGLfloat): BOOL{.dynlib: dllname,
+    importc: "wglGetFrameUsageI3D".}
+proc wglBeginFrameTrackingI3D*(): BOOL{.dynlib: dllname,
+                                        importc: "wglBeginFrameTrackingI3D".}
+proc wglEndFrameTrackingI3D*(): BOOL{.dynlib: dllname,
+                                      importc: "wglEndFrameTrackingI3D".}
+proc wglQueryFrameTrackingI3D*(pFrameCount: PDWORD, pMissedFrames: PDWORD,
+                               pLastMissedUsage: PGLfloat): BOOL{.
+    dynlib: dllname, importc: "wglQueryFrameTrackingI3D".}
+const
+  WGL_NUMBER_PIXEL_FORMATS_ARB* = 0x00002000
+  WGL_DRAW_TO_WINDOW_ARB* = 0x00002001
+  WGL_DRAW_TO_BITMAP_ARB* = 0x00002002
+  WGL_ACCELERATION_ARB* = 0x00002003
+  WGL_NEED_PALETTE_ARB* = 0x00002004
+  WGL_NEED_SYSTEM_PALETTE_ARB* = 0x00002005
+  WGL_SWAP_LAYER_BUFFERS_ARB* = 0x00002006
+  WGL_SWAP_METHOD_ARB* = 0x00002007
+  WGL_NUMBER_OVERLAYS_ARB* = 0x00002008
+  WGL_NUMBER_UNDERLAYS_ARB* = 0x00002009
+  WGL_TRANSPARENT_ARB* = 0x0000200A
+  WGL_TRANSPARENT_RED_VALUE_ARB* = 0x00002037
+  WGL_TRANSPARENT_GREEN_VALUE_ARB* = 0x00002038
+  WGL_TRANSPARENT_BLUE_VALUE_ARB* = 0x00002039
+  WGL_TRANSPARENT_ALPHA_VALUE_ARB* = 0x0000203A
+  WGL_TRANSPARENT_INDEX_VALUE_ARB* = 0x0000203B
+  WGL_SHARE_DEPTH_ARB* = 0x0000200C
+  WGL_SHARE_STENCIL_ARB* = 0x0000200D
+  WGL_SHARE_ACCUM_ARB* = 0x0000200E
+  WGL_SUPPORT_GDI_ARB* = 0x0000200F
+  WGL_SUPPORT_OPENGL_ARB* = 0x00002010
+  WGL_DOUBLE_BUFFER_ARB* = 0x00002011
+  WGL_STEREO_ARB* = 0x00002012
+  WGL_PIXEL_TYPE_ARB* = 0x00002013
+  WGL_COLOR_BITS_ARB* = 0x00002014
+  WGL_RED_BITS_ARB* = 0x00002015
+  WGL_RED_SHIFT_ARB* = 0x00002016
+  WGL_GREEN_BITS_ARB* = 0x00002017
+  WGL_GREEN_SHIFT_ARB* = 0x00002018
+  WGL_BLUE_BITS_ARB* = 0x00002019
+  WGL_BLUE_SHIFT_ARB* = 0x0000201A
+  WGL_ALPHA_BITS_ARB* = 0x0000201B
+  WGL_ALPHA_SHIFT_ARB* = 0x0000201C
+  WGL_ACCUM_BITS_ARB* = 0x0000201D
+  WGL_ACCUM_RED_BITS_ARB* = 0x0000201E
+  WGL_ACCUM_GREEN_BITS_ARB* = 0x0000201F
+  WGL_ACCUM_BLUE_BITS_ARB* = 0x00002020
+  WGL_ACCUM_ALPHA_BITS_ARB* = 0x00002021
+  WGL_DEPTH_BITS_ARB* = 0x00002022
+  WGL_STENCIL_BITS_ARB* = 0x00002023
+  WGL_AUX_BUFFERS_ARB* = 0x00002024
+  WGL_NO_ACCELERATION_ARB* = 0x00002025
+  WGL_GENERIC_ACCELERATION_ARB* = 0x00002026
+  WGL_FULL_ACCELERATION_ARB* = 0x00002027
+  WGL_SWAP_EXCHANGE_ARB* = 0x00002028
+  WGL_SWAP_COPY_ARB* = 0x00002029
+  WGL_SWAP_UNDEFINED_ARB* = 0x0000202A
+  WGL_TYPE_RGBA_ARB* = 0x0000202B
+  WGL_TYPE_COLORINDEX_ARB* = 0x0000202C
+
+proc wglGetPixelFormatAttribivARB*(hdc: HDC, iPixelFormat: TGLint,
+                                   iLayerPlane: TGLint, nAttributes: TGLuint,
+                                   piAttributes: PGLint, piValues: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribivARB".}
+proc wglGetPixelFormatAttribfvARB*(hdc: HDC, iPixelFormat: TGLint,
+                                   iLayerPlane: TGLint, nAttributes: TGLuint,
+                                   piAttributes: PGLint, pfValues: PGLfloat): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribfvARB".}
+proc wglChoosePixelFormatARB*(hdc: HDC, piAttribIList: PGLint,
+                              pfAttribFList: PGLfloat, nMaxFormats: TGLuint,
+                              piFormats: PGLint, nNumFormats: PGLuint): BOOL{.
+    dynlib: dllname, importc: "wglChoosePixelFormatARB".}
+const
+  WGL_ERROR_INVALID_PIXEL_TYPE_ARB* = 0x00002043
+  WGL_ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB* = 0x00002054
+
+proc wglMakeContextCurrentARB*(hDrawDC: HDC, hReadDC: HDC, hglrc: HGLRC): BOOL{.
+    dynlib: dllname, importc: "wglMakeContextCurrentARB".}
+proc wglGetCurrentReadDCARB*(): HDC{.dynlib: dllname,
+                                     importc: "wglGetCurrentReadDCARB".}
+const
+  WGL_DRAW_TO_PBUFFER_ARB* = 0x0000202D # WGL_DRAW_TO_PBUFFER_ARB  { already defined }
+  WGL_MAX_PBUFFER_PIXELS_ARB* = 0x0000202E
+  WGL_MAX_PBUFFER_WIDTH_ARB* = 0x0000202F
+  WGL_MAX_PBUFFER_HEIGHT_ARB* = 0x00002030
+  WGL_PBUFFER_LARGEST_ARB* = 0x00002033
+  WGL_PBUFFER_WIDTH_ARB* = 0x00002034
+  WGL_PBUFFER_HEIGHT_ARB* = 0x00002035
+  WGL_PBUFFER_LOST_ARB* = 0x00002036
+
+proc wglCreatePbufferARB*(hDC: HDC, iPixelFormat: TGLint, iWidth: TGLint,
+                          iHeight: TGLint, piAttribList: PGLint): THandle{.
+    dynlib: dllname, importc: "wglCreatePbufferARB".}
+proc wglGetPbufferDCARB*(hPbuffer: THandle): HDC{.dynlib: dllname,
+    importc: "wglGetPbufferDCARB".}
+proc wglReleasePbufferDCARB*(hPbuffer: THandle, hDC: HDC): TGLint{.
+    dynlib: dllname, importc: "wglReleasePbufferDCARB".}
+proc wglDestroyPbufferARB*(hPbuffer: THandle): BOOL{.dynlib: dllname,
+    importc: "wglDestroyPbufferARB".}
+proc wglQueryPbufferARB*(hPbuffer: THandle, iAttribute: TGLint, piValue: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglQueryPbufferARB".}
+proc wglSwapIntervalEXT*(interval: TGLint): BOOL{.dynlib: dllname,
+    importc: "wglSwapIntervalEXT".}
+proc wglGetSwapIntervalEXT*(): TGLint{.dynlib: dllname,
+                                       importc: "wglGetSwapIntervalEXT".}
+const
+  WGL_BIND_TO_TEXTURE_RGB_ARB* = 0x00002070
+  WGL_BIND_TO_TEXTURE_RGBA_ARB* = 0x00002071
+  WGL_TEXTURE_FORMAT_ARB* = 0x00002072
+  WGL_TEXTURE_TARGET_ARB* = 0x00002073
+  WGL_MIPMAP_TEXTURE_ARB* = 0x00002074
+  WGL_TEXTURE_RGB_ARB* = 0x00002075
+  WGL_TEXTURE_RGBA_ARB* = 0x00002076
+  WGL_NO_TEXTURE_ARB* = 0x00002077
+  WGL_TEXTURE_CUBE_MAP_ARB* = 0x00002078
+  WGL_TEXTURE_1D_ARB* = 0x00002079
+  WGL_TEXTURE_2D_ARB* = 0x0000207A # WGL_NO_TEXTURE_ARB  { already defined }
+  WGL_MIPMAP_LEVEL_ARB* = 0x0000207B
+  WGL_CUBE_MAP_FACE_ARB* = 0x0000207C
+  WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB* = 0x0000207D
+  WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB* = 0x0000207E
+  WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB* = 0x0000207F
+  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB* = 0x00002080
+  WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB* = 0x00002081
+  WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB* = 0x00002082
+  WGL_FRONT_LEFT_ARB* = 0x00002083
+  WGL_FRONT_RIGHT_ARB* = 0x00002084
+  WGL_BACK_LEFT_ARB* = 0x00002085
+  WGL_BACK_RIGHT_ARB* = 0x00002086
+  WGL_AUX0_ARB* = 0x00002087
+  WGL_AUX1_ARB* = 0x00002088
+  WGL_AUX2_ARB* = 0x00002089
+  WGL_AUX3_ARB* = 0x0000208A
+  WGL_AUX4_ARB* = 0x0000208B
+  WGL_AUX5_ARB* = 0x0000208C
+  WGL_AUX6_ARB* = 0x0000208D
+  WGL_AUX7_ARB* = 0x0000208E
+  WGL_AUX8_ARB* = 0x0000208F
+  WGL_AUX9_ARB* = 0x00002090
+
+proc wglBindTexImageARB*(hPbuffer: THandle, iBuffer: TGLint): BOOL{.
+    dynlib: dllname, importc: "wglBindTexImageARB".}
+proc wglReleaseTexImageARB*(hPbuffer: THandle, iBuffer: TGLint): BOOL{.
+    dynlib: dllname, importc: "wglReleaseTexImageARB".}
+proc wglSetPbufferAttribARB*(hPbuffer: THandle, piAttribList: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglSetPbufferAttribARB".}
+proc wglGetExtensionsStringEXT*(): cstring{.dynlib: dllname,
+    importc: "wglGetExtensionsStringEXT".}
+proc wglMakeContextCurrentEXT*(hDrawDC: HDC, hReadDC: HDC, hglrc: HGLRC): BOOL{.
+    dynlib: dllname, importc: "wglMakeContextCurrentEXT".}
+proc wglGetCurrentReadDCEXT*(): HDC{.dynlib: dllname,
+                                     importc: "wglGetCurrentReadDCEXT".}
+const
+  WGL_DRAW_TO_PBUFFER_EXT* = 0x0000202D
+  WGL_MAX_PBUFFER_PIXELS_EXT* = 0x0000202E
+  WGL_MAX_PBUFFER_WIDTH_EXT* = 0x0000202F
+  WGL_MAX_PBUFFER_HEIGHT_EXT* = 0x00002030
+  WGL_OPTIMAL_PBUFFER_WIDTH_EXT* = 0x00002031
+  WGL_OPTIMAL_PBUFFER_HEIGHT_EXT* = 0x00002032
+  WGL_PBUFFER_LARGEST_EXT* = 0x00002033
+  WGL_PBUFFER_WIDTH_EXT* = 0x00002034
+  WGL_PBUFFER_HEIGHT_EXT* = 0x00002035
+
+proc wglCreatePbufferEXT*(hDC: HDC, iPixelFormat: TGLint, iWidth: TGLint,
+                          iHeight: TGLint, piAttribList: PGLint): THandle{.
+    dynlib: dllname, importc: "wglCreatePbufferEXT".}
+proc wglGetPbufferDCEXT*(hPbuffer: THandle): HDC{.dynlib: dllname,
+    importc: "wglGetPbufferDCEXT".}
+proc wglReleasePbufferDCEXT*(hPbuffer: THandle, hDC: HDC): TGLint{.
+    dynlib: dllname, importc: "wglReleasePbufferDCEXT".}
+proc wglDestroyPbufferEXT*(hPbuffer: THandle): BOOL{.dynlib: dllname,
+    importc: "wglDestroyPbufferEXT".}
+proc wglQueryPbufferEXT*(hPbuffer: THandle, iAttribute: TGLint, piValue: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglQueryPbufferEXT".}
+const
+  WGL_NUMBER_PIXEL_FORMATS_EXT* = 0x00002000
+  WGL_DRAW_TO_WINDOW_EXT* = 0x00002001
+  WGL_DRAW_TO_BITMAP_EXT* = 0x00002002
+  WGL_ACCELERATION_EXT* = 0x00002003
+  WGL_NEED_PALETTE_EXT* = 0x00002004
+  WGL_NEED_SYSTEM_PALETTE_EXT* = 0x00002005
+  WGL_SWAP_LAYER_BUFFERS_EXT* = 0x00002006
+  WGL_SWAP_METHOD_EXT* = 0x00002007
+  WGL_NUMBER_OVERLAYS_EXT* = 0x00002008
+  WGL_NUMBER_UNDERLAYS_EXT* = 0x00002009
+  WGL_TRANSPARENT_EXT* = 0x0000200A
+  WGL_TRANSPARENT_VALUE_EXT* = 0x0000200B
+  WGL_SHARE_DEPTH_EXT* = 0x0000200C
+  WGL_SHARE_STENCIL_EXT* = 0x0000200D
+  WGL_SHARE_ACCUM_EXT* = 0x0000200E
+  WGL_SUPPORT_GDI_EXT* = 0x0000200F
+  WGL_SUPPORT_OPENGL_EXT* = 0x00002010
+  WGL_DOUBLE_BUFFER_EXT* = 0x00002011
+  WGL_STEREO_EXT* = 0x00002012
+  WGL_PIXEL_TYPE_EXT* = 0x00002013
+  WGL_COLOR_BITS_EXT* = 0x00002014
+  WGL_RED_BITS_EXT* = 0x00002015
+  WGL_RED_SHIFT_EXT* = 0x00002016
+  WGL_GREEN_BITS_EXT* = 0x00002017
+  WGL_GREEN_SHIFT_EXT* = 0x00002018
+  WGL_BLUE_BITS_EXT* = 0x00002019
+  WGL_BLUE_SHIFT_EXT* = 0x0000201A
+  WGL_ALPHA_BITS_EXT* = 0x0000201B
+  WGL_ALPHA_SHIFT_EXT* = 0x0000201C
+  WGL_ACCUM_BITS_EXT* = 0x0000201D
+  WGL_ACCUM_RED_BITS_EXT* = 0x0000201E
+  WGL_ACCUM_GREEN_BITS_EXT* = 0x0000201F
+  WGL_ACCUM_BLUE_BITS_EXT* = 0x00002020
+  WGL_ACCUM_ALPHA_BITS_EXT* = 0x00002021
+  WGL_DEPTH_BITS_EXT* = 0x00002022
+  WGL_STENCIL_BITS_EXT* = 0x00002023
+  WGL_AUX_BUFFERS_EXT* = 0x00002024
+  WGL_NO_ACCELERATION_EXT* = 0x00002025
+  WGL_GENERIC_ACCELERATION_EXT* = 0x00002026
+  WGL_FULL_ACCELERATION_EXT* = 0x00002027
+  WGL_SWAP_EXCHANGE_EXT* = 0x00002028
+  WGL_SWAP_COPY_EXT* = 0x00002029
+  WGL_SWAP_UNDEFINED_EXT* = 0x0000202A
+  WGL_TYPE_RGBA_EXT* = 0x0000202B
+  WGL_TYPE_COLORINDEX_EXT* = 0x0000202C
+
+proc wglGetPixelFormatAttribivEXT*(hdc: HDC, iPixelFormat: TGLint,
+                                   iLayerPlane: TGLint, nAttributes: TGLuint,
+                                   piAttributes: PGLint, piValues: PGLint): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribivEXT".}
+proc wglGetPixelFormatAttribfvEXT*(hdc: HDC, iPixelFormat: TGLint,
+                                   iLayerPlane: TGLint, nAttributes: TGLuint,
+                                   piAttributes: PGLint, pfValues: PGLfloat): BOOL{.
+    dynlib: dllname, importc: "wglGetPixelFormatAttribfvEXT".}
+proc wglChoosePixelFormatEXT*(hdc: HDC, piAttribIList: PGLint,
+                              pfAttribFList: PGLfloat, nMaxFormats: TGLuint,
+                              piFormats: PGLint, nNumFormats: PGLuint): BOOL{.
+    dynlib: dllname, importc: "wglChoosePixelFormatEXT".}
+const
+  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D* = 0x00002050
+  WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D* = 0x00002051
+  WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D* = 0x00002052
+  WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D* = 0x00002053
+
+proc wglGetDigitalVideoParametersI3D*(hDC: HDC, iAttribute: TGLint,
+                                      piValue: PGLint): BOOL{.dynlib: dllname,
+    importc: "wglGetDigitalVideoParametersI3D".}
+proc wglSetDigitalVideoParametersI3D*(hDC: HDC, iAttribute: TGLint,
+                                      piValue: PGLint): BOOL{.dynlib: dllname,
+    importc: "wglSetDigitalVideoParametersI3D".}
+const
+  WGL_GAMMA_TABLE_SIZE_I3D* = 0x0000204E
+  WGL_GAMMA_EXCLUDE_DESKTOP_I3D* = 0x0000204F
+
+proc wglGetGammaTableParametersI3D*(hDC: HDC, iAttribute: TGLint,
+                                    piValue: PGLint): BOOL{.dynlib: dllname,
+    importc: "wglGetGammaTableParametersI3D".}
+proc wglSetGammaTableParametersI3D*(hDC: HDC, iAttribute: TGLint,
+                                    piValue: PGLint): BOOL{.dynlib: dllname,
+    importc: "wglSetGammaTableParametersI3D".}
+proc wglGetGammaTableI3D*(hDC: HDC, iEntries: TGLint, puRed: PGLUSHORT,
+                          puGreen: PGLUSHORT, puBlue: PGLUSHORT): BOOL{.
+    dynlib: dllname, importc: "wglGetGammaTableI3D".}
+proc wglSetGammaTableI3D*(hDC: HDC, iEntries: TGLint, puRed: PGLUSHORT,
+                          puGreen: PGLUSHORT, puBlue: PGLUSHORT): BOOL{.
+    dynlib: dllname, importc: "wglSetGammaTableI3D".}
+const
+  WGL_GENLOCK_SOURCE_MULTIVIEW_I3D* = 0x00002044
+  WGL_GENLOCK_SOURCE_EXTERNAL_SYNC_I3D* = 0x00002045
+  WGL_GENLOCK_SOURCE_EXTERNAL_FIELD_I3D* = 0x00002046
+  WGL_GENLOCK_SOURCE_EXTERNAL_TTL_I3D* = 0x00002047
+  WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D* = 0x00002048
+  WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D* = 0x00002049
+  WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D* = 0x0000204A
+  WGL_GENLOCK_SOURCE_EDGE_RISING_I3D* = 0x0000204B
+  WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D* = 0x0000204C
+  WGL_FLOAT_COMPONENTS_NV* = 0x000020B0
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_R_NV* = 0x000020B1
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RG_NV* = 0x000020B2
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGB_NV* = 0x000020B3
+  WGL_BIND_TO_TEXTURE_RECTANGLE_FLOAT_RGBA_NV* = 0x000020B4
+  WGL_TEXTURE_FLOAT_R_NV* = 0x000020B5
+  WGL_TEXTURE_FLOAT_RG_NV* = 0x000020B6
+  WGL_TEXTURE_FLOAT_RGB_NV* = 0x000020B7
+  WGL_TEXTURE_FLOAT_RGBA_NV* = 0x000020B8
+
+proc wglEnableGenlockI3D*(hDC: HDC): BOOL{.dynlib: dllname,
+    importc: "wglEnableGenlockI3D".}
+proc wglDisableGenlockI3D*(hDC: HDC): BOOL{.dynlib: dllname,
+    importc: "wglDisableGenlockI3D".}
+proc wglIsEnabledGenlockI3D*(hDC: HDC, pFlag: PBOOL): BOOL{.dynlib: dllname,
+    importc: "wglIsEnabledGenlockI3D".}
+proc wglGenlockSourceI3D*(hDC: HDC, uSource: TGLuint): BOOL{.dynlib: dllname,
+    importc: "wglGenlockSourceI3D".}
+proc wglGetGenlockSourceI3D*(hDC: HDC, uSource: PGLUINT): BOOL{.dynlib: dllname,
+    importc: "wglGetGenlockSourceI3D".}
+proc wglGenlockSourceEdgeI3D*(hDC: HDC, uEdge: TGLuint): BOOL{.dynlib: dllname,
+    importc: "wglGenlockSourceEdgeI3D".}
+proc wglGetGenlockSourceEdgeI3D*(hDC: HDC, uEdge: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglGetGenlockSourceEdgeI3D".}
+proc wglGenlockSampleRateI3D*(hDC: HDC, uRate: TGLuint): BOOL{.dynlib: dllname,
+    importc: "wglGenlockSampleRateI3D".}
+proc wglGetGenlockSampleRateI3D*(hDC: HDC, uRate: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglGetGenlockSampleRateI3D".}
+proc wglGenlockSourceDelayI3D*(hDC: HDC, uDelay: TGLuint): BOOL{.
+    dynlib: dllname, importc: "wglGenlockSourceDelayI3D".}
+proc wglGetGenlockSourceDelayI3D*(hDC: HDC, uDelay: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglGetGenlockSourceDelayI3D".}
+proc wglQueryGenlockMaxSourceDelayI3D*(hDC: HDC, uMaxLineDelay: PGLUINT,
+                                       uMaxPixelDelay: PGLUINT): BOOL{.
+    dynlib: dllname, importc: "wglQueryGenlockMaxSourceDelayI3D".}
+const
+  WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV* = 0x000020A0
+  WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV* = 0x000020A1
+  WGL_TEXTURE_RECTANGLE_NV* = 0x000020A2
+
+const
+  WGL_RGBA_FLOAT_MODE_ATI* = 0x00008820
+  WGL_COLOR_CLEAR_UNCLAMPED_VALUE_ATI* = 0x00008835
+  WGL_TYPE_RGBA_FLOAT_ATI* = 0x000021A0
+
+# implementation
diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
new file mode 100644
index 000000000..e51c000c8
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
@@ -0,0 +1,45 @@
+# xxx this test is bad (echo instead of error, etc)
+
+import zip/zlib
+
+proc compress*(source: string): string =
+  var
+    sourcelen = source.len
+    destLen = sourcelen + (sourcelen.float * 0.1).int + 16
+  result = ""
+  result.setLen destLen
+  # see http://www.zlib.net/zlib-1.2.11.tar.gz for correct definitions
+  var destLen2 = destLen.Ulongf
+  var res = zlib.compress(cstring(result), addr destLen2, cstring(source), sourceLen.Ulong)
+  if res != Z_OK:
+    echo "Error occurred: ", res
+  elif destLen2.int < result.len:
+    result.setLen(destLen2.int)
+
+proc uncompress*(source: string, destLen: var int): string =
+  result = ""
+  result.setLen destLen
+  var destLen2 = destLen.Ulongf
+  var res = zlib.uncompress(cstring(result), addr destLen2, cstring(source), source.len.Ulong)
+  if res != Z_OK:
+    echo "Error occurred: ", res
+
+
+when true:
+  import strutils
+  var r = compress("Hello")
+  echo repr(r)
+  var ln = "Hello".len
+  var rr = uncompress(r, ln)
+  echo repr(rr)
+  assert rr == "Hello"
+
+  proc `*`(a: string; b: int): string {.inline.} = result = repeat(a, b)
+  var s = "yo dude sup bruh homie" * 50
+  r = compress(s)
+  echo s.len, " -> ", r.len
+
+  ln = s.len
+  rr = uncompress(r, ln)
+  echo r.len, " -> ", rr.len
+  assert rr == s
diff --git a/tests/manyloc/keineschweine/server/dirserver_settings.json b/tests/manyloc/keineschweine/server/dirserver_settings.json
new file mode 100644
index 000000000..18c15fb46
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/dirserver_settings.json
@@ -0,0 +1,7 @@
+{
+ "network":"lamenet",
+ "port":2049,
+ "zones":[
+  {"name":"alphazone","key":"skittles"} 
+ ]
+}
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/nim.cfg b/tests/manyloc/keineschweine/server/nim.cfg
new file mode 100644
index 000000000..211ad3003
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/nim.cfg
@@ -0,0 +1,5 @@
+debugger = off
+path = ".."
+path = "../genpacket"
+path = "../helpers"
+define = NoSFML
diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim
new file mode 100644
index 000000000..a63829691
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_dirserver.nim
@@ -0,0 +1,201 @@
+## directory server
+## handles client authorization and assets
+import ../../../dist/checksums/src/checksums/md5
+import
+  sockets, times, streams, streams_enh, tables, json, os,
+  sg_packets, sg_assets, server_utils, map_filter
+type
+  THandler = proc(client: PCLient; stream: PStream)
+var
+  server: TSocket
+  handlers = initTable[char, THandler](16)
+  thisZone = newScZoneRecord("local", "sup")
+  zoneList = newScZoneList()
+  thisZoneSettings: string
+  zoneSlots: seq[tuple[name: string; key: string]] = @[]
+  zones: seq[PClient] = @[]
+  ## I was high.
+  clients = initTable[TupAddress, PClient](16)
+  alias2client = initTable[string, PClient](32)
+  allClients: seq[PClient] = @[]
+
+proc findClient*(host: string; port: int16): PClient =
+  let addy: TupAddress = (host, port)
+  if clients.hasKey(addy):
+    return clients[addy]
+  result = newClient(addy)
+  clients[addy] = result
+  allClients.add(result)
+
+proc loginZone(client: PClient; login: SdZoneLogin): bool =
+  if not client.auth:
+    for s in zoneSlots.items:
+      if s.name == login.name and s.key == login.key:
+        client.auth = true
+        client.kind = CServer
+        client.record = login.record
+        result = true
+        break
+
+proc sendZoneList(client: PClient) =
+  echo(">> zonelist ", client, ' ', HZoneList)
+  client.send(HZonelist, zonelist)
+proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
+  var m = newScChat(CPriv, sender.alias, txt)
+  rcv.send(HChat, m)
+proc sendChat(client: PClient; kind: ChatType; txt: string) =
+  echo(">> chat ", client)
+  var m = newScChat(kind, "", txt)
+  client.send(HChat, m)
+
+
+
+var pubChatQueue = newIncomingBuffer()
+proc queuePub(sender: string, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
+  pubChatQueue.write(HChat)
+  chat.pack(pubChatQueue)
+
+handlers[HHello] = (proc(client: PClient; stream: PStream) =
+  var h = readCsHello(stream)
+  if h.i == 14:
+    var greet = newScHello("Well hello there")
+    client.send(HHello, greet))
+handlers[HLogin] = proc(client: PClient; stream: PStream) =
+  var loginInfo = readCsLogin(stream)
+  echo("** login: alias = ", loginInfo.alias)
+  if alias2client.hasKey(loginInfo.alias):
+    client.sendError("Alias in use.")
+    return
+  if client.loginPlayer(loginInfo):
+    alias2client[client.alias] = client
+    client.sendMessage("Welcome "& client.alias)
+    var session = newScLogin(client.id, client.alias, client.session)
+    client.send HLogin, session
+    client.sendZonelist()
+
+handlers[HZoneList] = proc(client: PClient; stream: PStream) =
+  var pinfo = readCsZoneList(stream)
+  echo("** zonelist req")
+  sendZoneList client
+handlers[HChat] = proc(client: PClient; stream: PStream) =
+  var chat = readCsChat(stream)
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  if chat.target != "": ##private
+    if alias2client.hasKey(chat.target):
+      alias2client[chat.target].forwardPrivate(client, chat.text)
+  else:
+    queuePub(client.alias, chat)
+
+proc sendServMsg(client: PClient; msg: string) =
+  var m = newDsMsg(msg)
+  client.send HDsMsg, m
+handlers[HZoneLogin] = proc(client: PClient; stream: PStream) =
+  var
+    login = readSdZoneLogin(stream)
+  if not client.loginZone(login):
+    client.sendServMsg "Invalid login"
+  else:
+    client.sendServMsg "Welcome to the servers"
+    echo "** Zone logged in: ", login
+    zones.add client
+    zonelist.zones.add client.record
+
+
+handlers[HFileChallenge] = proc(client: PClient; stream: PStream) =
+  if client.auth:
+    if client.kind == CServer:
+      var chg = readScFileChallenge(stream)
+
+proc handlePkt(s: PClient; stream: PStream) =
+  while not stream.atEnd:
+    var typ = readChar(stream)
+    if not handlers.hasKey(typ):
+      break
+    else:
+      handlers[typ](s, stream)
+
+proc createServer(port: TPort) =
+  if not server.isNil:
+    server.close()
+  server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
+  server.bindAddr(port)
+
+
+var clientIndex = 0
+var incoming = newIncomingBuffer()
+proc poll*(timeout: int = 250) =
+  if server.isNil: return
+  var
+    reads = @[server]
+    writes = @[server]
+  if select(reads, timeout) > 0:
+    var
+      addy = ""
+      port: TPort
+    incoming.data.setLen 512
+    let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
+    if not res:
+      echo("No recv")
+      return
+    else:
+      var client = findClient(addy, port.int16)
+      echo "<< ", res, " ", client, ": ", len(incoming.data), " ", repr(incoming.data)
+      handlePkt(client, incoming)
+    incoming.flush()
+  if selectWrite(writes, timeout) > 0:
+    let nclients = allClients.len
+    if nclients == 0:
+      return
+    clientIndex = (clientIndex + 1) mod nclients
+    var c = allClients[clientIndex]
+    if c.outputBuf.getPosition > 0:
+      let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
+      echo("Write ", c, " result: ", res, " data: ", repr(c.outputBuf.data))
+      c.outputBuf.flush()
+
+when true:
+  import parseopt, strutils
+  var cfgFile = "dirserver_settings.json"
+  for kind, key, val in getopt():
+    case kind
+    of cmdShortOption, cmdLongOption:
+      case key
+      of "f", "file":
+        if fileExists(val):
+          cfgFile = val
+        else:
+          echo("File does not exist: ", val)
+      else:
+        echo("Unknown option: ", key," ", val)
+    else:
+      echo("Unknown option: ", key, " ", val)
+  var jsonSettings = parseFile(cfgFile)
+  let port = TPort(jsonSettings["port"].num)
+  zonelist.network = jsonSettings["network"].str
+  for slot in jsonSettings["zones"].items:
+    zoneSlots.add((slot["name"].str, slot["key"].str))
+
+  createServer(port)
+  echo("Listening on port ", port, "...")
+  var pubChatTimer = cpuTime() #newClock()
+  const PubChatDelay = 1000/1000
+  while true:
+    poll(15)
+    ## TODO sort this type of thing VV into a queue api
+    if cpuTime() - pubChatTimer > PubChatDelay:       #.getElapsedTime.asMilliseconds > 100:
+      pubChatTimer -= pubChatDelay
+      if pubChatQueue.getPosition > 0:
+        var cn = 0
+        let sizePubChat = pubChatQueue.data.len
+        var sent = 0
+        filterIt2(allClients, it.auth == true and it.kind == CPlayer):
+          it.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+          sent += 1
+        #for c in allClients:
+        #  c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+        pubChatQueue.flush()
+        echo "pubChatQueue flushed to ", sent, "clients"
+
diff --git a/tests/manyloc/keineschweine/server/old_server_utils.nim b/tests/manyloc/keineschweine/server/old_server_utils.nim
new file mode 100644
index 000000000..f389c0836
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_server_utils.nim
@@ -0,0 +1,100 @@
+import ../../../dist/checksums/src/checksums/md5
+
+import
+  streams, sockets,
+  sg_packets, zlib_helpers, idgen
+type
+  TClientType* = enum
+    CServer = 0'i8, CPlayer, CUnknown
+  PClient* = ref TClient
+  TClient* = object of TObject
+    id*: int32
+    addy*: TupAddress
+    clientID*: uint16
+    auth*: bool
+    outputBuf*: PStringStream
+    case kind*: TClientType
+    of CPlayer:
+      alias*: string
+      session*: string
+      lastPing*: float
+      failedPings*: int
+    of CServer:
+      record*: ScZoneRecord
+      cfg*: TChecksumFile
+    of CUnknown: nil
+  TChecksumFile* = object
+    unpackedSize*: int
+    sum*: MD5Digest
+    compressed*: string
+  TupAddress* = tuple[host: string, port: int16]
+  PIDGen*[T: Ordinal] = ref TIDGen[T]
+  TIDGen[T: Ordinal] = object
+    max: T
+    freeIDs: seq[T]
+var cliID = newIdGen[int32]()
+
+proc sendMessage*(client: PClient; txt: string)
+proc sendError*(client: PClient; txt: string)
+proc `$`*(client: PClient): string
+
+proc newIncomingBuffer*(size = 1024): PStringStream =
+  result = newStringStream("")
+  result.data.setLen size
+  result.data.setLen 0
+  result.flushImpl = proc(stream: PStream) =
+    stream.setPosition(0)
+    PStringStream(stream).data.setLen(0)
+
+
+proc free*(c: PClient) =
+  echo "Client freed: ", c
+  cliID.del c.id
+  c.outputBuf.flush()
+  c.outputBuf = nil
+proc newClient*(addy: TupAddress): PClient =
+  new(result, free)
+  result.addy = addy
+  result.outputBuf = newStringStream("")
+  result.outputBuf.flushImpl = proc(stream: PStream) =
+    stream.setPosition 0
+    PStringStream(stream).data.setLen 0
+
+proc loginPlayer*(client: PClient; login: CsLogin): bool =
+  if client.auth:
+    client.sendError("You are already logged in.")
+    return
+  client.id = cliID.next()
+  client.auth = true
+  client.kind = CPlayer
+  client.alias = login.alias
+  client.session = getMD5(client.alias & $rand(10000))
+  result = true
+
+proc `$`*(client: PClient): string =
+  if not client.auth: return $client.addy
+  case client.kind
+  of CPlayer: result = client.alias
+  of CServer: result = client.record.name
+  else: result = $client.addy
+proc send*[T](client: PClient; pktType: char; pkt: var T) =
+  client.outputBuf.write(pktType)
+  pkt.pack(client.outputBuf)
+
+proc sendMessage*(client: PClient; txt: string) =
+  var m = newScChat(CSystem, text = txt)
+  client.send HChat, m
+proc sendError*(client: PClient; txt: string) =
+  var m = newScChat(CError, text = txt)
+  client.send HChat, m
+
+proc checksumFile*(filename: string): TChecksumFile =
+  let fullText = readFile(filename)
+  result.unpackedSize = fullText.len
+  result.sum = toMD5(fullText)
+  result.compressed = compress(fullText)
+proc checksumStr*(str: string): TChecksumFile =
+  result.unpackedSize = str.len
+  result.sum = toMD5(str)
+  result.compressed = compress(str)
+
diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim
new file mode 100644
index 000000000..d6fbbe99e
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_sg_server.nim
@@ -0,0 +1,254 @@
+import
+  sockets, times, streams, streams_enh, tables, json, os,
+  sg_packets, sg_assets, md5, server_utils, client_helpers
+var
+  dirServer: PServer
+  thisZone = newScZoneRecord("local", "sup")
+  thisZoneSettings: PZoneSettings
+  dirServerConnected = false
+  ## I was high.
+  clients = initTable[TupAddress, PClient](16)
+  alias2client = initTable[string, PClient](32)
+  allClients: seq[PClient] = @[]
+  zonePlayers: seq[PClient] = @[]
+const
+  PubChatDelay = 100/1000 #100 ms
+
+import hashes
+proc hash*(x: uint16): THash {.inline.} =
+  result = int32(x)
+
+proc findClient*(host: string; port: int16): PClient =
+  let addy: TupAddress = (host, port)
+  if clients.hasKey(addy):
+    return clients[addy]
+  result = newClient(addy)
+  clients[addy] = result
+  allClients.add(result)
+
+
+proc sendZoneList(client: PClient) =
+  echo(">> zonelist ", client)
+  #client.send(HZonelist, zonelist)
+
+proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
+  var m = newScChat(CPriv, sender.alias, txt)
+  rcv.send(HChat, m)
+proc sendChat(client: PClient; kind: ChatType; txt: string) =
+  echo(">> chat ", client)
+  var m = newScChat(kind, "", txt)
+  client.send(HChat, m)
+
+var pubChatQueue = newStringStream("")
+pubChatQueue.flushImpl = proc(stream: PStream) =
+  stream.setPosition(0)
+  PStringStream(stream).data.setLen(0)
+proc queuePub(sender: string, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
+  pubChatQueue.write(HChat)
+  chat.pack(pubChatQueue)
+
+handlers[HHello] = (proc(client: PClient; stream: PStream) =
+  var h = readCsHello(stream)
+  if h.i == 14:
+    var greet = newScHello("Well hello there")
+    client.send(HHello, greet))
+handlers[HLogin] = proc(client: PClient; stream: PStream) =
+  var loginInfo = readCsLogin(stream)
+  echo("** login: alias = ", loginInfo.alias)
+  if not dirServerConnected and client.loginPlayer(loginInfo):
+    client.sendMessage("Welcome "& client.alias)
+    alias2client[client.alias] = client
+    client.sendZonelist()
+handlers[HZoneList] = proc(client: PClient; stream: PStream) =
+  var pinfo = readCsZoneList(stream)
+  echo("** zonelist req")
+handlers[HChat] = proc(client: PClient; stream: PStream) =
+  var chat = readCsChat(stream)
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  if chat.target != "": ##private
+    if alias2client.hasKey(chat.target):
+      alias2client[chat.target].forwardPrivate(client, chat.text)
+  else:
+    queuePub(client.alias, chat)
+handlers[HZoneQuery] = proc(client: PClient; stream: PStream) =
+  echo("Got zone query")
+  var q = readCsZoneQuery(stream)
+  var resp = newScZoneQuery(zonePlayers.len.uint16)
+  client.send(HZoneQuery, resp)
+
+
+
+handlers[HZoneJoinReq] = proc(client: PClient; stream: PStream) =
+  var req = readCsZoneJoinReq(stream)
+  echo "Join zone request from (",req.session.id,") ", req.session.alias
+  if client.auth and client.kind == CPlayer:
+    echo "Client is authenticated, verifying filez"
+    client.startVerifyingFiles()
+  elif dirServerConnected:
+    echo "Dirserver is connected, verifying client"
+    dirServer.send HVerifyClient, req.session
+  else:
+    echo "Dirserver is disconnected =("
+    client.startVerifyingFiles()
+
+
+
+proc handlePkt(s: PClient; stream: PStream) =
+  while not stream.atEnd:
+    var typ = readChar(stream)
+    if not handlers.hasKey(typ):
+      break
+    else:
+      handlers[typ](s, stream)
+
+proc createServer(port: TPort) =
+  if not server.isNil:
+    server.close()
+  server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
+  server.bindAddr(port)
+
+var clientIndex = 0
+var incoming = newIncomingBuffer()
+proc poll*(timeout: int = 250) =
+  if server.isNil: return
+  var
+    reads = @[server]
+    writes = @[server]
+  if select(reads, timeout) > 0:
+    var
+      addy = ""
+      port: TPort
+    let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
+    if not res:
+      echo("No recv")
+      return
+    else:
+      var client = findClient(addy, port.int16)
+      #echo("<< ", res, " ", client.alias, ": ", len(line.data), " ", repr(line.data))
+      handlePkt(client, incoming)
+    incoming.flush()
+  if selectWrite(writes, timeout) > 0:
+    let nclients = allClients.len
+    if nclients == 0:
+      return
+    clientIndex = (clientIndex + 1) mod nclients
+    var c = allClients[clientIndex]
+    if c.outputBuf.getPosition > 0:
+      let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
+      echo("Write ", c, " result: ", res, " data: ", c.outputBuf.data)
+      c.outputBuf.flush()
+
+when true:
+  import parseopt, strutils
+  var zoneCfgFile = "./server_settings.json"
+  for kind, key, val in getopt():
+    case kind
+    of cmdShortOption, cmdLongOption:
+      case key
+      of "f", "file":
+        if fileExists(val):
+          zoneCfgFile = val
+        else:
+          echo("File does not exist: ", val)
+      else:
+        echo("Unknown option: ", key," ", val)
+    else:
+      echo("Unknown option: ", key, " ", val)
+  var jsonSettings = parseFile(zoneCfgFile)
+  let
+    host = jsonSettings["host"].str
+    port = TPort(jsonSettings["port"].num)
+    zoneFile = jsonSettings["settings"].str
+    dirServerInfo = jsonSettings["dirserver"]
+
+  var path = getAppDir()/../"data"/zoneFile
+  if not fileExists(path):
+    echo("Zone settings file does not exist: ../data/", zoneFile)
+    echo(path)
+    quit(1)
+
+  ## Test file
+  block:
+    var
+      TestFile: FileChallengePair
+      contents = repeat("abcdefghijklmnopqrstuvwxyz", 2)
+    testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32)
+    testFile.file = checksumStr(contents)
+    myAssets.add testFile
+
+  setCurrentDir getAppDir().parentDir()
+  block:
+    let zonesettings = readFile(path)
+    var
+      errors: seq[string] = @[]
+    if not loadSettings(zoneSettings, errors):
+      echo("You have errors in your zone settings:")
+      for e in errors: echo("**", e)
+      quit(1)
+    errors.setLen 0
+
+    var pair: FileChallengePair
+    pair.challenge.file = zoneFile
+    pair.challenge.assetType = FZoneCfg
+    pair.challenge.fullLen = zoneSettings.len.int32
+    pair.file = checksumStr(zoneSettings)
+    myAssets.add pair
+
+    allAssets:
+      if not load(asset):
+        echo "Invalid or missing file ", file
+      else:
+        var pair: FileChallengePair
+        pair.challenge.file = file
+        pair.challenge.assetType = assetType
+        pair.challenge.fullLen = getFileSize(
+          expandPath(assetType, file)).int32
+        pair.file = asset.contents
+        myAssets.add pair
+
+    echo "Zone has ", myAssets.len, " associated assets"
+
+
+    dirServer = newServerConnection(dirServerInfo[0].str, dirServerInfo[1].num.TPort)
+    dirServer.handlers[HDsMsg] = proc(serv: PServer; stream: PStream) =
+      var m = readDsMsg(stream)
+      echo("DirServer> ", m.msg)
+    dirServer.handlers[HZoneLogin] = proc(serv: PServer; stream: PStream) =
+      let loggedIn = readDsZoneLogin(stream).status
+      if loggedIn:
+        dirServerConnected = true
+    dirServer.writePkt HZoneLogin, login
+
+  thisZone.name = jsonSettings["name"].str
+  thisZone.desc = jsonSettings["desc"].str
+  thisZone.ip = "localhost"
+  thisZone.port = port
+  var login = newSdZoneLogin(
+    dirServerInfo[2].str, dirServerInfo[3].str,
+    thisZone)
+  #echo "MY LOGIN: ", $login
+
+
+
+  createServer(port)
+  echo("Listening on port ", port, "...")
+  var pubChatTimer = cpuTime()#newClock()
+  while true:
+    discard dirServer.pollServer(15)
+    poll(15)
+    ## TODO sort this type of thing VV into a queue api
+    #let now = cpuTime()
+    if cpuTime() - pubChatTimer > PubChatDelay:       #.getElapsedTime.asMilliseconds > 100:
+      pubChatTimer -= pubChatDelay #.restart()
+      if pubChatQueue.getPosition > 0:
+        var cn = 0
+        let sizePubChat = pubChatQueue.data.len
+        for c in allClients:
+          c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+        pubChatQueue.flush()
+
+
+
diff --git a/tests/manyloc/keineschweine/server/sg_lobby.nim b/tests/manyloc/keineschweine/server/sg_lobby.nim
new file mode 100644
index 000000000..04ce10f08
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/sg_lobby.nim
@@ -0,0 +1,268 @@
+import ../../../dist/checksums/src/checksums/md5
+
+import
+  sockets, streams, tables, times, math, strutils, json, os,
+  sfml, sfml_vector, sfml_colors,
+  streams_enh, input_helpers, zlib_helpers, client_helpers, sg_packets, sg_assets, sg_gui
+type
+  TClientSettings = object
+    resolution*: TVideoMode
+    offlineFile: string
+    dirserver: tuple[host: string, port: TPort]
+    website*: string
+var
+  clientSettings: TClientSettings
+  gui = newGuiContainer()
+  zonelist = newGuiContainer()
+  u_alias, u_passwd: PTextEntry
+  activeInput = 0
+  aliasText, passwdText: PText
+  fpsTimer: PButton
+  loginBtn: PButton
+  playBtn: PButton
+  keyClient = newKeyClient("lobby")
+  showZonelist = false
+  chatInput*: PTextEntry
+  messageArea*: PMessageArea
+  mySession*: ScLogin
+var
+  dirServer: PServer
+  zone*: PServer
+  activeServer: PServer
+  bConnected = false
+  outgoing = newStringStream("")
+  downloadProgress: PButton
+  connectionButtons: seq[PButton] #buttons that depend on connection to function
+
+template dispmessage(m: expr): stmt =
+  messageArea.add(m)
+proc connectZone(host: string; port: TPort)
+proc connectToDirserv()
+
+proc writePkt[T](pid: PacketID; p: var T) =
+  if activeServer.isNil: return
+  activeServer.writePkt pid, p
+
+proc setConnected(state: bool) =
+  if state:
+    bConnected = true
+    for b in connectionButtons: enable(b)
+  else:
+    bConnected = false
+    for b in connectionButtons: disable(b)
+
+proc setActiveZone(ind: int; zone: ScZoneRecord) =
+  #highlight it or something
+  dispmessage("Selected " & zone.name)
+  connectZone(zone.ip, zone.port)
+  playBtn.enable()
+
+proc handleChat(serv: PServer; s: PStream) =
+  var msg = readScChat(s)
+  messageArea.add(msg)
+
+proc connectToDirserv() =
+  if dirServer.isNil:
+    dirServer = newServerConnection(clientSettings.dirserver.host, clientSettings.dirserver.port)
+    dirServer.handlers[HHello] = proc(serv: PServer; s: PStream) =
+      let msg = readScHello(s)
+      dispMessage(msg.resp)
+      setConnected(true)
+    dirServer.handlers[HLogin] = proc(serv: PServer; s: PStream) =
+      mySession = readScLogin(s)
+      ##do something here
+    dirServer.handlers[HZonelist] = proc(serv: PServer; s: PStream) =
+      var
+        info = readScZonelist(s)
+        zones = info.zones
+      if zones.len > 0:
+        zonelist.clearButtons()
+        var pos = vec2f(0.0, 0.0)
+        zonelist.newButton(
+          text = "Zonelist - "& info.network,
+          position = pos,
+          onClick = proc(b: PButton) =
+            dispmessage("Click on header"))
+        pos.y += 20
+        for i in 0..zones.len - 1:
+          var z = zones[i]
+          zonelist.newButton(
+            text = z.name, position = pos,
+            onClick = proc(b: PButton) =
+              setActiveZone(i, z))
+          pos.y += 20
+        showZonelist = true
+    dirServer.handlers[HPoing] = proc(serv: PServer; s: PStream) =
+      var ping = readPoing(s)
+      dispmessage("Ping: "& $ping.time)
+      ping.time = epochTime().float32
+      serv.writePkt HPoing, ping
+    dirServer.handlers[HChat] = handleChat
+    dirServer.handlers[HFileChallenge] = handleFileChallenge
+  var hello = newCsHello()
+  dirServer.writePkt HHello, hello
+  activeServer = dirServer
+
+
+proc zoneListReq() =
+  var pkt = newCsZonelist("sup")
+  writePkt HZonelist, pkt
+
+##key handlers
+keyClient.registerHandler(MouseMiddle, down, proc() =
+  gui.setPosition(getMousePos()))
+
+keyClient.registerHandler(KeyO, down, proc() =
+  if keyPressed(KeyRShift): echo(repr(outgoing)))
+keyClient.registerHandler(KeyTab, down, proc() =
+  activeInput = (activeInput + 1) mod 2) #does this work?
+keyClient.registerHandler(MouseLeft, down, proc() =
+  let p = getMousePos()
+  gui.click(p)
+  if showZonelist: zonelist.click(p))
+var mptext = newText("", guiFont, 16)
+keyClient.registerHandler(MouseRight, down, proc() =
+  let p = getMousePos()
+  mptext.setPosition(p)
+  mptext.setString("($1,$2)"%[$p.x.int,$p.y.int]))
+
+
+proc connectZone(host: string, port: TPort) =
+  echo "Connecting to zone at ", host, ':', port
+  if zone.isNil:
+    zone = newServerConnection(host, port)
+    zone.handlers[HFileChallenge] = handleFileChallenge
+    zone.handlers[HChallengeResult] = handleFileChallengeResult
+    zone.handlers[HFileTransfer] = handleFileTransfer
+    zone.handlers[HChat] = handleChat
+  else:
+    zone.sock.connect(host, port)
+  var hello = newCsHello()
+  zone.writePkt HHello, hello
+
+
+
+proc lobbyReady*() =
+  keyClient.setActive()
+  gui.setActive(u_alias)
+
+proc tryConnect*(b: PButton) =
+  connectToDirserv()
+proc tryLogin*(b: PButton) =
+  var login = newCsLogin(
+    alias = u_alias.getText(),
+    passwd = u_passwd.getText())
+  writePkt HLogin, login
+proc tryTransition*(b: PButton) =
+  ##check if we're logged in
+  #<implementation censored by the church>
+  #var joinReq = newCsJ
+  zone.writePkt HZoneJoinReq, mySession
+  #var errors: seq[string] = @[]
+  #if loadSettings("", errors):
+  #  transition()
+  #else:
+  #  for e in errors: dispmessage(e)
+proc playOffline*(b: PButton) =
+  var errors: seq[string] = @[]
+  if loadSettingsFromFile(clientSettings.offlineFile, errors):
+    transition()
+  else:
+    dispmessage("Errors reading the file ("& clientSettings.offlineFile &"):")
+    for e in errors: dispmessage(e)
+
+proc getClientSettings*(): TClientSettings =
+  result = clientSettings
+
+proc lobbyInit*() =
+  var s = json.parseFile("./client_settings.json")
+  clientSettings.offlineFile = "data/"
+  clientSettings.offlineFile.add s["default-file"].str
+  let dirserv = s["directory-server"]
+  clientSettings.dirserver.host = dirserv["host"].str
+  clientSettings.dirserver.port = dirserv["port"].num.TPort
+  clientSettings.resolution.width = s["resolution"][0].num.cint
+  clientSettings.resolution.height= s["resolution"][1].num.cint
+  clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint
+  clientSettings.website = s["website"].str
+  zonelist.setPosition(vec2f(200.0, 100.0))
+  connectionButtons = @[]
+
+  downloadProgress = gui.newButton(
+    text = "", position = vec2f(10, 130), onClick = nil)
+  downloadProgress.bg.setFillColor(color(34, 139, 34))
+  downloadProgress.bg.setSize(vec2f(0, 0))
+
+  var pos = vec2f(10, 10)
+  u_alias = gui.newTextEntry(
+    if s.existsKey("alias"): s["alias"].str else: "alias",
+    pos)
+  pos.y += 20
+  u_passwd = gui.newTextEntry("buzz", pos)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Login",
+    position = pos,
+    onClick = tryLogin,
+    startEnabled = false))
+  pos.y += 20
+  fpsText.setPosition(pos)
+
+  playBtn = gui.newButton(
+    text = "Play",
+    position = vec2f(680.0, 8.0),
+    onClick = tryTransition,
+    startEnabled = false)
+  gui.newButton(
+    text = "Play Offline",
+    position = vec2f(680.0, 28.0),
+    onClick = playOffline)
+  fpsTimer = gui.newButton(
+    text = "FPS: ",
+    position = vec2f(10.0, 70.0),
+    onClick = proc(b: PButton) = nil)
+  gui.newButton(
+    text = "Connect",
+    position = vec2f(10.0, 90.0),
+    onClick = tryConnect)
+  connectionButtons.add(gui.newButton(
+    text = "Test Chat",
+    position = vec2f(10.0, 110.0),
+    onClick = (proc(b: PButton) =
+      var pkt = newCsChat(text = "ohai")
+      writePkt HChat, pkt),
+    startEnabled = false))
+  chatInput = gui.newTextEntry("...", vec2f(10.0, 575.0), proc() =
+    sendChat dirServer, chatInput.getText()
+    chatInput.clearText())
+  messageArea = gui.newMessageArea(vec2f(10.0, 575.0 - 20.0))
+  messageArea.sizeVisible = 25
+  gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack += 1
+    update(messageArea))
+  gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack -= 1
+    update(messageArea))
+  gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) =
+    for i in 0..< 30:
+      dispMessage($i))
+
+var i = 0
+proc lobbyUpdate*(dt: float) =
+  #let res = disp.poll()
+  gui.update(dt)
+  i = (i + 1) mod 60
+  if i == 0:
+    fpsTimer.setString("FPS: "& $round(1.0/dt))
+  if not pollServer(dirServer, 5) and bConnected:
+    setConnected(false)
+    echo("Lost connection")
+  discard pollServer(zone, 5)
+
+proc lobbyDraw*(window: PRenderWindow) =
+  window.clear(Black)
+  window.draw messageArea
+  window.draw mptext
+  window.draw gui
+  if showZonelist: window.draw zonelist
+  window.display()
diff --git a/tests/manyloc/nake/nake.nim b/tests/manyloc/nake/nake.nim
new file mode 100644
index 000000000..5d3173a20
--- /dev/null
+++ b/tests/manyloc/nake/nake.nim
@@ -0,0 +1,84 @@
+discard """
+DO AS THOU WILST PUBLIC LICENSE
+
+Whoever should stumble upon this document is henceforth and forever
+entitled to DO AS THOU WILST with aforementioned document and the
+contents thereof.
+
+As said in the Olde Country, `Keepe it Gangster'."""
+
+import strutils, parseopt, tables, os
+
+type
+  PTask* = ref object
+    desc*: string
+    action*: TTaskFunction
+  TTaskFunction* = proc() {.closure.}
+var
+  tasks* = initTable[string, PTask](16)
+
+proc newTask*(desc: string; action: TTaskFunction): PTask
+proc runTask*(name: string) {.inline.}
+proc shell*(cmd: varargs[string, `$`]): int {.discardable.}
+proc cd*(dir: string) {.inline.}
+
+template nakeImports*() =
+  import tables, parseopt, strutils, os
+
+template task*(name: string; description: string; body: untyped) {.dirty.} =
+  block:
+    var t = newTask(description, proc() {.closure.} =
+      body)
+    tasks[name] = t
+
+proc newTask*(desc: string; action: TTaskFunction): PTask =
+  new(result)
+  result.desc = desc
+  result.action = action
+proc runTask*(name: string) = tasks[name].action()
+
+proc shell*(cmd: varargs[string, `$`]): int =
+  result = execShellCmd(cmd.join(" "))
+proc cd*(dir: string) = setCurrentDir(dir)
+template withDir*(dir: string; body: untyped) =
+  ## temporary cd
+  ## withDir "foo":
+  ##   # inside foo
+  ## #back to last dir
+  var curDir = getCurrentDir()
+  cd(dir)
+  body
+  cd(curDir)
+
+when true:
+  if not fileExists("nakefile.nim"):
+    echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
+    quit 1
+  var args = ""
+  for i in 1..paramCount():
+    args.add paramStr(i)
+    args.add " "
+  quit(shell("nim", "c", "-r", "nakefile.nim", args))
+else:
+  import std/exitprocs
+  addExitProc(proc() {.noconv.} =
+    var
+      task: string
+      printTaskList: bool
+    for kind, key, val in getopt():
+      case kind
+      of cmdLongOption, cmdShortOption:
+        case key.tolowerAscii
+        of "tasks", "t":
+          printTaskList = true
+        else:
+          echo "Unknown option: ", key, ": ", val
+      of cmdArgument:
+        task = key
+      else: discard
+    if printTaskList or task.len == 0 or not(tasks.hasKey(task)):
+      echo "Available tasks:"
+      for name, task in pairs(tasks):
+        echo name, " - ", task.desc
+      quit 0
+    tasks[task].action())
diff --git a/tests/manyloc/nake/nakefile.nim b/tests/manyloc/nake/nakefile.nim
new file mode 100644
index 000000000..fc479a5c2
--- /dev/null
+++ b/tests/manyloc/nake/nakefile.nim
@@ -0,0 +1,157 @@
+import nake
+import httpclient, zip/zipfiles, times, random, sequtils
+nakeImports
+
+randomize()
+
+const
+  GameAssets = "http://dl.dropbox.com/u/37533467/data-08-01-2012.7z"
+  BinLibs = "http://dl.dropbox.com/u/37533467/libs-2012-09-12.zip"
+  ExeName = "keineschweine"
+  ServerDefines = "-d:NoSFML -d:NoChipmunk"
+  TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNim -d:debugKeys -d:foo -d:recordMode --forceBuild"
+  ReleaseDefines = "-d:release"
+  ReleaseTestDefines = "-d:debugWeps -d:debugKeys --forceBuild"
+
+task "testprofile", "..":
+  if shell("nim", TestBuildDefines, "--profiler:on", "--stacktrace:on", "compile", ExeName) == 0:
+    shell "."/ExeName, "offline"
+
+task "test", "Build with test defines":
+  if shell("nim", TestBuildDefines, "compile", ExeName) != 0:
+    quit "The build failed."
+
+task "testrun", "Build with test defines and run":
+  runTask "test"
+  shell "."/ExeName
+
+task "test2", "Build release test build test release build":
+  if shell("nim", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0:
+    shell "."/ExeName
+
+when false:
+  task "dirserver", "build the directory server":
+    withDir "server":
+      if shell("nim", ServerDefines, "compile", "dirserver") != 0:
+        echo "Failed to build the dirserver"
+        quit 1
+
+task "zoneserver", "build the zone server":
+  withDir "enet_server":
+    if shell("nim", ServerDefines, "compile", "enet_server") != 0:
+      quit "Failed to build the zoneserver"
+task "zoneserver-gui", "build the zone server, with gui!":
+  withDir "enet_server":
+    if shell("nim", ServerDefines, "--app:gui", "compile", "enet_server") != 0:
+      quit "Failed to build the zoneserver"
+
+task "servers", "build the server and directory server":
+  #runTask "dirserver"
+  runTask "zoneserver"
+  echo "Successfully built both servers :')"
+
+task "all", "run SERVERS and TEST tasks":
+  runTask "servers"
+  runTask "test"
+
+task "release", "release build":
+  let res = shell("nim", ReleaseDefines, "compile", ExeName)
+  if res != 0:
+    echo "The build failed."
+    quit 1
+  else:
+    runTask "clean"
+    ## zip up all the files and such or something useful here
+
+task "testskel", "create skeleton test dir for testing":
+  let dirname = "test-" & $rand(5000)
+  removeDir dirName
+  createDir dirName/"data/fnt"
+  copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf"
+  copyFile "client_settings.json", dirName/"client_settings.json"
+  runTask "test"
+  copyFile ExeName, dirName/ExeName
+  withDir dirName:
+    shell "."/ExeName
+
+
+task "clean", "cleanup generated files":
+  var dirs = @["nimcache", "server"/"nimcache"]
+  dirs.apply(proc(x: var string) =
+    if dirExists(x): removeDir(x))
+
+task "download", "download game assets":
+  var
+    skipAssets = false
+    path = expandFilename("data")
+    client = newHttpClient()
+  path.add DirSep
+  path.add(extractFilename(GameAssets))
+  if fileExists(path):
+    echo "The file already exists\n",
+      "[R]emove  [M]ove  [Q]uit  [S]kip    Source: ", GameAssets
+    case stdin.readLine.toLowerAscii
+    of "r":
+      removeFile path
+    of "m":
+      moveFile path, path/../(extractFilename(GameAssets)&"-old")
+    of "s":
+      skipAssets = true
+    else:
+      quit 0
+  else:
+    echo "Downloading from ", GameAssets
+  if not skipAssets:
+    echo "Downloading to ", path
+    client.downloadFile(GameAssets, path)
+    echo "Download finished"
+
+    let targetDir = parentDir(parentDir(path))
+    when defined(linux):
+      let z7 = findExe("7z")
+      if z7 == "":
+        echo "Could not find 7z"
+      elif shell(z7, "t", path) != 0: ##note to self: make sure this is right
+        echo "Bad download"
+      else:
+        echo "Unpacking..."
+        shell(z7, "x", "-w[$1]" % targetDir, path)
+    else:
+      echo "I do not know how to unpack the data on this system. Perhaps you could ",
+        "fill this part in?"
+
+  echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
+    "[Y]es [N]o   Source: ", BinLibs
+  case stdin.readline.toLowerAscii
+  of "y", "yes":
+    discard ## o_O
+  else:
+    return
+  path = extractFilename(BinLibs)
+  client.downloadFile(BinLibs, path)
+  echo "Downloaded dem libs ", path
+  when true: echo "Unpack it yourself, sorry."
+  else:  ## this crashes, dunno why
+    var
+      z: TZipArchive
+      destDir = getCurrentDir()/("unzip" & $rand(5000))
+    if not z.open(path, fmRead):
+      echo "Could not open zip, bad download?"
+      return
+    echo "Extracting to ", destDir
+    createDir destDir
+    #z.extractAll destDir
+    for f in z.walkFiles():
+      z.extractFile(f, destDir/f)
+    z.close()
+    echo "Extracted the libs dir. Copy the ones you need to this dir."
+
+task "zip-lib", "zip up the libs dir":
+  var z: ZipArchive
+  if not z.open("libs-" & getDateStr() & ".zip", fmReadWrite):
+    quit "Could not open zip"
+  for file in walkDirRec("libs", {pcFile, pcDir}):
+    echo "adding file ", file
+    z.addFile(file)
+  z.close()
+  echo "Great success!"
diff --git a/tests/manyloc/nake/nakefile.nim.cfg b/tests/manyloc/nake/nakefile.nim.cfg
new file mode 100644
index 000000000..6f3e86fe6
--- /dev/null
+++ b/tests/manyloc/nake/nakefile.nim.cfg
@@ -0,0 +1 @@
+path = "dependencies/nake"
diff --git a/tests/manyloc/named_argument_bug/gui.nim b/tests/manyloc/named_argument_bug/gui.nim
new file mode 100644
index 000000000..1e0bc6ffd
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/gui.nim
@@ -0,0 +1,44 @@
+import
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/math/rect,
+  tri_engine/math/vec
+
+type
+  TWidgetLayer* = enum
+    wlBg      = 100,
+    wlOverlap = 200,
+    wlMain    = 300,
+    wlOverlay = 400,
+    wlCursor  = 500
+  TWidgetLayerType = TWidgetLayer|int
+  TWidgetType* = enum
+    wtImg
+  PWidget* = ref object
+    `type`* : TWidgetType
+    layer*  : TWidgetLayer
+    rect*   : TRect
+    prim*   : PPrimitive
+
+const
+  baseZ = 5000
+
+proc newWidget*(`type`: TWidgetType, layer: TWidgetLayerType, rect: TRect): PWidget =
+  new(result)
+  result.`type` = `type`
+  result.layer = layer
+  result.rect = rect
+
+  var verts = newVert(rect)
+
+  # This works because z is accessible at this scope.
+  #var z = baseZ + layer.int
+  #result.prim = newPrimitive(verts, z=z)
+
+  # Doesn't work, because the compiler looks for a symbol called z in this scope,
+  # but it should only check that it is the name of one of the params.
+  #result.prim = newPrimitive(verts, z=baseZ + layer.int)
+
+  # This doesn't work either.
+  result.prim = newPrimitive(verts, z=0)
diff --git a/tests/manyloc/named_argument_bug/main.nim b/tests/manyloc/named_argument_bug/main.nim
new file mode 100644
index 000000000..767674428
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/main.nim
@@ -0,0 +1,23 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec,
+  tri_engine/math/circle,
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/tri_engine,
+  gui
+
+var isRunning = true
+
+block:
+  var renderer = newRenderer(w=10, h=10)
+
+  var primitive = newPrimitiveCircle(0.3.TR, color=white(0.5, 0.8), z=15)
+  renderer.addPrimitive(primitive)
+
+  var verts = newVert((min: newV2xy(-0.4), size: newV2xy(0.3)))
+  var primitive2 = newPrimitive(verts, color=red(0.5, 0.8), z=10)
+  renderer.addPrimitive(primitive2)
+
+  var mainMenuWidget = newWidget(wtImg, wlBg, rect=(newV2xy(-1.0), newV2xy(2.0)))
diff --git a/tests/manyloc/named_argument_bug/main.nim.cfg b/tests/manyloc/named_argument_bug/main.nim.cfg
new file mode 100644
index 000000000..7df7a0e97
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/main.nim.cfg
@@ -0,0 +1,3 @@
+# this file only exists to mark 'main.nim' as the main file
+
+--path:"$projectpath"
diff --git a/tests/manyloc/named_argument_bug/tri_engine/config.nim b/tests/manyloc/named_argument_bug/tri_engine/config.nim
new file mode 100644
index 000000000..b90dc0b26
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/config.nim
@@ -0,0 +1,6 @@
+when defined(doublePrecision):
+  type
+    TR* = float64
+else:
+  type
+    TR* = float32
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
new file mode 100644
index 000000000..b84be7a4c
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/color.nim
@@ -0,0 +1,54 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+from strutils import
+  formatFloat,
+  TFloatFormat,
+  `%`,
+  ffDecimal
+
+type
+  TColor* = tuple[r, g, b, a: TR]
+
+converter toColor*(o: uint32): TColor =
+  ## Convert an integer to a color. This is mostly useful when the integer is specified as a hex
+  ## literal such as 0xFF00007F, which is 100% red, with 50% alpha.
+  ## TODO: turn this into a template that can take either 4 or 8 characters?
+  ((((o and 0xff000000'u32) shr 24).TR / 255.0).TR,
+   (((o and 0xff0000'u32) shr 16).TR / 255.0).TR,
+   (((o and 0xff00'u32) shr 8).TR / 255.0).TR,
+   (((o and 0xff'u32)).TR / 255.0).TR)
+
+converter toV4*(o: TColor): TV4[TR] =
+  cast[TV4[TR]](o)
+
+proc newColor*(r, g, b: TR=0.0, a: TR=1.0): TColor =
+  (r, g, b, a)
+
+proc white*(rgb, a: TR=1.0): TColor =
+  (rgb, rgb, rgb, a)
+
+proc red*(r, a: TR=1.0): TColor =
+  newColor(r=r, a=a)
+
+proc green*(g, a: TR=1.0): TColor =
+  newColor(g=g, a=a)
+
+proc yellow*(rg, a: TR=1.0): TColor =
+  newColor(r=rg, g=rg, a=a)
+
+proc blue*(b, a: TR=1.0): TColor =
+  newColor(b=b, a=a)
+
+proc cyan*(gb, a: TR=1.0): TColor =
+  newColor(g=gb, b=gb, a=a)
+
+proc purple*(rb, a: TR=1.0): TColor =
+  newColor(r=rb, b=rb, a=a)
+
+proc `$`*(o: TColor): string =
+  proc f(f: float): string =
+    f.formatFloat(precision=2, format=ffDecimal)
+
+  "(r: $#, g: $#, b: $#, s: $#)" % [f(o.r), f(o.g), f(o.b), f(o.a)]
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
new file mode 100644
index 000000000..29e23f9d0
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/gl.nim
@@ -0,0 +1,61 @@
+import
+  opengl,
+  tri_engine/math/vec
+
+export
+  opengl
+
+type
+  EGL* = object of Exception
+  EGL_code* = object of EGL
+    code*: EGL_err
+  EGL_err {.pure.} = enum
+    none                 = GL_NO_ERROR
+    invalidEnum          = GL_INVALID_ENUM
+    invalidVal           = GL_INVALID_VALUE
+    invalidOp            = GL_INVALID_OPERATION
+    stackOverflow        = GL_STACK_OVERFLOW
+    stackUnderflow       = GL_STACK_UNDERFLOW
+    outOfMem             = GL_OUT_OF_MEMORY
+    invalidFramebufferOp = GL_INVALID_FRAMEBUFFER_OPERATION
+    unknown
+
+proc newGL_codeException*(msg: string, code: EGL_err): ref EGL_code =
+  result      = newException(EGL_code, $code)
+  result.code = code
+
+proc getErr*(): EGL_err =
+  result = glGetError().EGL_err
+  if result notin {EGL_err.none,
+                   EGL_err.invalidEnum,
+                   EGL_err.invalidVal,
+                   EGL_err.invalidOp,
+                   EGL_err.invalidFramebufferOp,
+                   EGL_err.outOfMem,
+                   EGL_err.stackUnderflow,
+                   EGL_err.stackOverflow}:
+    return EGL_err.unknown
+
+proc errCheck*() =
+  let err = getErr()
+  if err != EGL_err.none:
+    raise newGL_codeException($err, err)
+
+macro `?`*(call: expr{nkCall}): expr =
+  result = call
+  # Can't yet reference foreign symbols in macros.
+  #errCheck()
+
+when defined(doublePrecision):
+  const
+    glRealType* = cGLdouble
+else:
+  const
+    glRealType* = cGLfloat
+
+proc setUniformV4*[T](loc: GLint, vecs: var openArray[TV4[T]]) =
+  glUniform4fv(loc, vecs.len.GLsizei, cast[ptr GLfloat](vecs[0].addr))
+
+proc setUniformV4*[T](loc: GLint, vec: TV4[T]) =
+  var vecs = [vec]
+  setUniformV4(loc, vecs)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
new file mode 100644
index 000000000..accc2d96b
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/primitive.nim
@@ -0,0 +1,157 @@
+import
+  math,
+  tri_engine/config,
+  tri_engine/gfx/gl/gl,
+  tri_engine/gfx/tex,
+  tri_engine/gfx/color,
+  tri_engine/math/vec,
+  tri_engine/math/rect,
+  tri_engine/math/circle
+
+import strutils
+
+type
+  TVert* = tuple[pos: TV2[TR], texCoord: TV2[TR]]
+  TVertAttrib* = object
+    i*      : GLuint
+    size*   : GLint
+    stride* : GLsizei
+    offset* : GLvoid
+  TVertMode* = enum
+    vmTriStrip = GLtriangleStrip,
+    vmTriFan   = GLtriangleFan
+  TZ_range* = range[-100_000..100_000]
+  PPrimitive* = ref object
+    verts*        : seq[TVert]
+    indices*      : seq[GLushort]
+    arrBufId*     : GLuint
+    elemArrBufId* : GLuint
+    tex*          : TTex
+    color*        : TColor
+    vertMode*     : TVertMode
+    z*            : int
+
+proc newVert*(pos, texCoord: TV2): TVert =
+  (pos, texCoord)
+
+proc newVertQuad*(min, minRight, maxLeft, max: TV2[TR]): seq[TVert] =
+  @[newVert(min,      newV2()),
+    newVert(minRight, newV2(x=1.0)),
+    newVert(maxLeft,  newV2(y=1.0)),
+    newVert(max,      newV2xy(1.0))
+  ]
+
+proc newVert*(rect: rect.TRect): seq[TVert] =
+  newVertQuad(rect.min, newV2(rect.max.x, rect.min.y), newV2(rect.min.x, rect.max.y), rect.max)
+
+proc newVertAttrib(i: GLuint, size: GLint, stride: GLsizei, offset: GLvoid): TVertAttrib =
+  TVertAttrib(i: i, size: size, stride: stride, offset: offset)
+
+proc genBuf*[T](vboTarget, objUsage: GLenum, data: var openArray[T]): GLuint =
+  result = 0.GLuint
+  ?glGenBuffers(1, result.addr)
+  ?glBindBuffer(vboTarget, result)
+
+  let size = (data.len * T.sizeof).GLsizeiptr
+  ?glBufferData(vboTarget, size, data[0].addr, objUsage)
+
+proc newPrimitive*(verts: var seq[TVert],
+                   vertMode=vmTriStrip,
+                   tex=whiteTex(),
+                   color=white(),
+                   z: TZ_range=0): PPrimitive =
+  var indices = newSeq[GLushort](verts.len)
+  for i in 0 ..< verts.len:
+    indices[i] = i.GLushort
+
+  new(result)
+  result.verts = verts
+  result.indices = indices
+
+  result.arrBufId     = genBuf(GLarrayBuffer, GL_STATIC_DRAW, verts)
+  result.elemArrBufId = genBuf(GLelementArrayBuffer, GL_STATIC_DRAW, indices)
+  result.tex = tex
+  result.color = color
+  result.vertMode = vertMode
+  result.z = z
+
+proc bindBufs*(o: PPrimitive) =
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+  ?glBindBuffer(GLelementArrayBuffer, o.elemArrBufId)
+
+proc enableVertAttribArrs*() =
+  ?glEnableVertexAttribArray(0)
+  ?glEnableVertexAttribArray(1)
+
+proc disableVertAttribArrs*() =
+  ?glDisableVertexAttribArray(1)
+  ?glDisableVertexAttribArray(0)
+
+proc setVertAttribPointers*() =
+  let vertSize {.global.} = TVert.sizeof.GLint
+  ?glVertexAttribPointer(0, 2, glRealType, false, vertSize, nil)
+  ?glVertexAttribPointer(1, 2, glRealType, false, vertSize, cast[GLvoid](TR.sizeof * 2))
+
+proc updVerts*(o: PPrimitive, start, `end`: int, f: proc(i: int, vert: var TVert)) =
+  assert start <= `end`
+  assert `end` < o.verts.len
+  for i in start..`end`:
+    f(i, o.verts[i])
+
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+
+  let byteLen = `end` - start + 1 * TVert.sizeof
+  let byteOffset = start * TVert.sizeof
+  ?glBufferSubData(GLarrayBuffer,
+                   byteOffset.GLintptr, # Offset. Is this right?
+                   byteLen.GLsizeiptr, # Size.
+                   cast[GLvoid](cast[int](o.verts[0].addr) + byteOffset))
+
+proc updAllVerts(o: PPrimitive, f: proc(i: int, vert: var TVert)) =
+  for i in 0 ..< o.verts.len:
+    f(i, o.verts[i])
+
+  ?glBindBuffer(GLarrayBuffer, o.arrBufId)
+
+  # Discard old buffer before creating a new one.
+  let byteLen = (o.verts.len * TVert.sizeof).GLsizeiptr
+  ?glBufferData(GLarrayBuffer, byteLen, nil, GLstaticDraw)
+  ?glBufferData(GLarrayBuffer, byteLen, o.verts[0].addr, GLstaticDraw)
+
+proc newVertCircle*(circle: TCircle, nSegs: Natural=0): seq[TVert] =
+  let nSegs = if nSegs == 0:
+      (circle.r.sqrt() * 400.0).int # TODO: Base this on the window resolution?
+    else:
+      max(nSegs, 3)
+
+  let theta: TR = (PI * 2.0) / (nSegs.TR)
+  let tanFactor = theta.tan()
+  let radialFactor = theta.cos()
+  var x = circle.r
+  var y: TR = 0.0
+
+  result = newSeq[TVert](nSegs)
+  #result[0] = newVert(circle.p, newV2xy(0.5))
+  for i in 1 ..< nSegs:
+    let pos = newV2(x + circle.p.x, y + circle.p.y)
+    let texCoord = pos * newV2xy(1.0 / circle.r)
+
+    result[i] = newVert(pos, texCoord)
+
+    let tx = -y
+    let ty = x
+    x += tx * tanFactor
+    y += ty * tanFactor
+
+    x *= radialFactor
+    y *= radialFactor
+
+  result.add(result[1])
+
+proc newPrimitiveCircle*(circle: TCircle,
+                         nSegs: Natural=0,
+                         tex=whiteTex(),
+                         color=white(),
+                         z: TZ_range=0): PPrimitive =
+  var verts = newVertCircle(circle, nSegs)
+  newPrimitive(verts, vmTriFan, tex, color, z)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
new file mode 100644
index 000000000..970885b3d
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/gl/shader.nim
@@ -0,0 +1,103 @@
+import
+  pure/os,
+  tri_engine/gfx/gl/gl
+
+type
+  TShader* = object
+    id*: GL_handle
+  TShaderType* {.pure.} = enum
+    frag = GL_FRAGMENT_SHADER,
+    vert   = GL_VERTEX_SHADER
+  E_Shader* = object of Exception
+  E_UnknownShaderType* = object of E_Shader
+
+converter pathToShaderType*(s: string): TShaderType =
+  case s.splitFile().ext:
+  of ".vs":
+    return TShaderType.vert
+  of ".fs":
+    return TShaderType.frag
+  else:
+    raise newException(E_UnknownShaderType, "Can't determine shader type from file extension: " & s)
+
+proc setSrc*(shader: TShader, src: string) =
+  var s = src.cstring
+  ?glShaderSource(shader.id, 1, cast[cstringarray](s.addr), nil)
+
+proc newShader*(id: GL_handle): TShader =
+  if id.int != 0 and not (?glIsShader(id)).bool:
+    raise newException(E_GL, "Invalid shader ID: " & $id)
+
+  result.id = id
+
+proc shaderInfoLog*(o: TShader): string =
+  var log {.global.}: array[0..1024, char]
+  var logLen: GLsizei
+  ?glGetShaderInfoLog(o.id.GLuint, log.len.GLsizei, addr logLen, cast[cstring](log.addr))
+  cast[string](log.addr).substr(0, logLen)
+
+proc compile*(shader: TShader, path="") =
+  ?glCompileShader(shader.id)
+  var compileStatus = 0.GLint
+  ?glGetShaderIv(shader.id, GL_COMPILE_STATUS, compileStatus.addr)
+
+  if compileStatus == 0:
+    raise newException(E_GL, if path.len == 0:
+        shaderInfoLog(shader)
+      else:
+        path & ":\n" & shaderInfoLog(shader)
+    )
+
+proc newShaderFromSrc*(src: string, `type`: TShaderType): TShader =
+  result.id = ?glCreateShader(`type`.GLenum)
+  result.setSrc(src)
+  result.compile()
+
+proc newShaderFromFile*(path: string): TShader =
+  newShaderFromSrc(readFile(path), path)
+
+type
+  TProgram* = object
+    id*: GL_handle
+    shaders: seq[TShader]
+
+proc attach*(o: TProgram, shader: TShader) =
+  ?glAttachShader(o.id, shader.id)
+
+proc infoLog*(o: TProgram): string =
+  var log {.global.}: array[0..1024, char]
+  var logLen: GLsizei
+  ?glGetProgramInfoLog(o.id.GLuint, log.len.GLsizei, addr logLen, cast[cstring](log.addr))
+  cast[string](log.addr).substr(0, logLen)
+
+proc link*(o: TProgram) =
+  ?glLinkProgram(o.id)
+  var linkStatus = 0.GLint
+  ?glGetProgramIv(o.id, GL_LINK_STATUS, linkStatus.addr)
+  if linkStatus == 0:
+    raise newException(E_GL, o.infoLog())
+
+proc validate*(o: TProgram) =
+  ?glValidateProgram(o.id)
+  var validateStatus = 0.GLint
+  ?glGetProgramIv(o.id, GL_VALIDATE_STATUS, validateStatus.addr)
+  if validateStatus == 0:
+    raise newException(E_GL, o.infoLog())
+
+proc newProgram*(shaders: seq[TShader]): TProgram =
+  result.id = ?glCreateProgram()
+  if result.id.int == 0:
+    return
+
+  for shader in shaders:
+    if shader.id.int == 0:
+      return
+
+    ?result.attach(shader)
+
+  result.shaders = shaders
+  result.link()
+  result.validate()
+
+proc use*(o: TProgram) =
+  ?glUseProgram(o.id)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim b/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
new file mode 100644
index 000000000..282a1ac99
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/gfx/tex.nim
@@ -0,0 +1,31 @@
+import
+  tri_engine/gfx/gl/gl
+
+type
+  TTex* = object
+    id*: GLuint
+
+var gWhiteTex = TTex(id: 0)
+
+proc setTexParams() =
+  ?glTexParameteri(GLtexture2D, GLtextureMinFilter, GLlinear)
+
+  #glTexParameteri(GLtexture2D, GLtextureMagFilter, GLlinear)
+  ?glTexParameteri(GLtexture2D, GLTextureMagFilter, GLnearest)
+
+  ?glTexParameteri(GLtexture2D, GLTextureWrapS, GLClampToEdge)
+  ?glTexParameteri(GLtexture2D, GLTextureWrapT, GLClampToEdge)
+
+proc whiteTex*(): TTex =
+  if gWhiteTex.id.int != 0:
+    return gWhiteTex
+
+  ?glGenTextures(1, gWhiteTex.id.addr)
+  ?glBindTexture(GLtexture2D, gWhiteTex.id)
+  setTexParams()
+
+  var pixel = [255'u8, 255'u8, 255'u8, 255'u8]
+  ?glTexImage2D(GLtexture2D, 0, GLint GL_RGBA, 1, 1, 0, GL_BGRA, cGLUnsignedByte, pixel[0].addr)
+  ?glBindTexture(GLtexture2D, 0)
+
+  result = gWhiteTex
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim
new file mode 100644
index 000000000..b95cfa379
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/circle.nim
@@ -0,0 +1,9 @@
+import
+  ../config,
+  vec
+
+type
+  TCircle* = tuple[p: TV2[TR], r: TR]
+
+converter toCircle*(o: TR): TCircle =
+  (newV2(), o)
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim b/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim
new file mode 100644
index 000000000..b6fd9ce84
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/rect.nim
@@ -0,0 +1,8 @@
+import
+  tri_engine/config,
+  tri_engine/math/vec
+
+type
+  TRect* = tuple[min, size: TV2[TR]]
+
+proc max*(o: TRect): TV2[TR] = o.min + o.size
diff --git a/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
new file mode 100644
index 000000000..18ede6100
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/math/vec.nim
@@ -0,0 +1,55 @@
+import
+  macros,
+  "../config"
+
+type
+  TV2*[T:SomeNumber=TR] = array[0..1, T]
+  TV3*[T:SomeNumber=TR] = array[0..2, T]
+  TV4*[T:SomeNumber=TR] = array[0..3, T]
+  TVT*[T:SomeNumber=TR] = TV2|TV3|TV4
+  #TV2* = array[0..1, TR]
+  #TV3* = array[0..2, TR]
+  #TV4* = array[0..3, TR]
+
+# TODO: Change to TVT when compiler issue is resolved.
+proc `$`*[T](o: TV2[T]): string =
+  result = "("
+  for i in 0 ..< o.len:
+    result &= $o[0]
+    if i != o.len - 1:
+      result &= ", "
+
+  result & ")"
+
+proc newV2T*[T](x, y: T=0): TV2[T] =
+  [x, y]
+
+proc newV2*(x, y: TR=0.0): TV2[TR] =
+  [x, y]
+
+proc newV2xy*(xy: TR): TV2[TR] =
+  [xy, xy]
+
+proc x*[T](o: TV2[T]): T =
+  o[0]
+
+proc y*[T](o: TV2[T]): T =
+  o[1]
+
+proc `*`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
+  [(lhs.x * rhs.x).TR, (lhs.y * rhs.y).TR]
+
+proc `+`*(lhs: TV2[TR], rhs: TV2[TR]): TV2[TR] =
+  [(lhs.x + rhs.x).TR, (lhs.y + rhs.y).TR]
+
+#proc dotProduct[T](a: TVT[T], b: TVT[T]): T =
+#  for i in 0 .. a.len - 1:
+#    result += a[i] * b[i]
+
+proc dot[T](a, b: TV2[T]): T =
+  for i in 0 ..< a.len:
+    result += a[i] * b[i]
+
+assert dot(newV2(), newV2()) == 0.0
+assert dot(newV2(2, 3), newV2(6, 7)) == 33.0
+assert dot([2.0, 3.0], [6.0, 7.0]) == 33.0
diff --git a/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim b/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
new file mode 100644
index 000000000..ba9989bbb
--- /dev/null
+++ b/tests/manyloc/named_argument_bug/tri_engine/tri_engine.nim
@@ -0,0 +1,106 @@
+import
+  algorithm,
+  tri_engine/config,
+  tri_engine/gfx/gl/gl,
+  tri_engine/gfx/gl/primitive,
+  tri_engine/gfx/gl/shader,
+  tri_engine/gfx/color
+
+const primitiveVs = """
+#version 330 core
+
+layout(location = 0) in vec2 pos;
+layout(location = 1) in vec2 texCoord;
+
+out vec2 uv;
+
+void main()
+{
+    gl_Position = vec4(pos, 0, 1);
+    uv = texCoord;
+}
+
+"""
+const primitiveFs = """
+#version 330 core
+
+in vec2 uv;
+out vec4 color;
+uniform sampler2D tex;
+uniform vec4 inColor;
+
+void main()
+{
+    color = texture(tex, uv) * inColor;
+}
+
+"""
+
+var gW, gH: Natural = 0
+
+proc w*(): int =
+  gW
+
+proc h*(): int =
+  gH
+
+type
+  PRenderer = ref object
+    primitiveProgram: TProgram
+    primitives: seq[PPrimitive]
+
+proc setupGL() =
+  ?glEnable(GLblend)
+  ?glBlendFunc(GLsrcAlpha, GLoneMinusSrcAlpha)
+  ?glClearColor(0.0, 0.0, 0.0, 1.0)
+  ?glPolygonMode(GLfrontAndBack, GLfill)
+
+proc newRenderer*(w, h: Positive): PRenderer =
+  gW = w
+  gH = h
+
+  new(result)
+  newSeq(result.primitives, 0)
+  loadExtensions()
+  setupGL()
+  result.primitiveProgram = newProgram(@[
+    newShaderFromSrc(primitiveVs, TShaderType.vert),
+    newShaderFromSrc(primitiveFs, TShaderType.frag)])
+
+proc draw(o: PRenderer, p: PPrimitive) =
+  let loc = proc(x: string): Glint =
+    result = glGetUniformLocation(o.primitiveProgram.id, x)
+    if result == -1:
+      raise newException(E_GL, "Shader error: " & x & " does not correspond to a uniform variable")
+
+  setUniformV4(loc("inColor"), p.color)
+  ?glActiveTexture(GLtexture0)
+  ?glBindTexture(GLtexture2D, p.tex.id.GLuint)
+  ?glUniform1i(loc("tex"), 0)
+
+  p.bindBufs()
+  setVertAttribPointers()
+
+  ?glDrawElements(p.vertMode.GLenum, p.indices.len.GLsizei, cGLunsignedShort, nil)
+
+proc draw*(o: PRenderer) =
+  ?glClear(GLcolorBufferBit)
+  o.primitiveProgram.use()
+
+  enableVertAttribArrs()
+  var zSortedPrimitives = o.primitives
+  zSortedPrimitives.sort(proc(x, y: PPrimitive): int =
+    if x.z < y.z:
+      -1
+    elif x.z > y.z:
+      1
+    else:
+      0)
+
+  for x in zSortedPrimitives:
+    o.draw(x)
+
+  disableVertAttribArrs()
+
+proc addPrimitive*(o: PRenderer, p: PPrimitive) =
+  o.primitives.add(p)
diff --git a/tests/manyloc/packages/noconflicts.nim b/tests/manyloc/packages/noconflicts.nim
new file mode 100644
index 000000000..2183d01a8
--- /dev/null
+++ b/tests/manyloc/packages/noconflicts.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''package1/strutils
+package2/strutils
+noconflicts
+new os.nim'''
+"""
+
+import package1/strutils as su1
+import package2.strutils as su2
+
+import os
+
+su1.foo()
+su2.foo()
+echo "noconflicts"
+yay()
diff --git a/tests/manyloc/packages/noconflicts.nim.cfg b/tests/manyloc/packages/noconflicts.nim.cfg
new file mode 100644
index 000000000..88974ab8c
--- /dev/null
+++ b/tests/manyloc/packages/noconflicts.nim.cfg
@@ -0,0 +1 @@
+# Mark noconflicts as project file
\ No newline at end of file
diff --git a/tests/manyloc/packages/os.nim b/tests/manyloc/packages/os.nim
new file mode 100644
index 000000000..8a59612f9
--- /dev/null
+++ b/tests/manyloc/packages/os.nim
@@ -0,0 +1,5 @@
+
+# Overrides lib/pure/os.nim
+
+proc yay* = echo "new os.nim"
+
diff --git a/tests/manyloc/packages/package1/p1.babel b/tests/manyloc/packages/package1/p1.babel
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/manyloc/packages/package1/p1.babel
diff --git a/tests/manyloc/packages/package1/strutils.nim b/tests/manyloc/packages/package1/strutils.nim
new file mode 100644
index 000000000..b283600ea
--- /dev/null
+++ b/tests/manyloc/packages/package1/strutils.nim
@@ -0,0 +1,5 @@
+
+# Overrides lib/pure/os.nim
+
+proc foo* = echo "package1/strutils"
+
diff --git a/tests/manyloc/packages/package2/p2.babel b/tests/manyloc/packages/package2/p2.babel
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/manyloc/packages/package2/p2.babel
diff --git a/tests/manyloc/packages/package2/strutils.nim b/tests/manyloc/packages/package2/strutils.nim
new file mode 100644
index 000000000..1fb4abd41
--- /dev/null
+++ b/tests/manyloc/packages/package2/strutils.nim
@@ -0,0 +1,5 @@
+
+# Overrides lib/pure/os.nim
+
+proc foo* = echo "package2/strutils"
+
diff --git a/tests/manyloc/standalone/barebone.nim b/tests/manyloc/standalone/barebone.nim
new file mode 100644
index 000000000..487f6da65
--- /dev/null
+++ b/tests/manyloc/standalone/barebone.nim
@@ -0,0 +1,16 @@
+discard """
+ccodecheck: "\\i !@('systemInit')"
+ccodecheck: "\\i !@('systemDatInit')"
+output: "hello"
+"""
+# bug  #2041: Macros need to be available for os:standalone!
+import macros
+
+proc printf(frmt: cstring) {.varargs, header: "<stdio.h>", cdecl.}
+
+var x = 0
+inc x
+printf("hi %ld\n", x+4777)
+
+proc substr(a: string): string = a[0 .. 3] # This should compile. See #9762
+const a = substr("foobar")
diff --git a/tests/manyloc/standalone/barebone.nim.cfg b/tests/manyloc/standalone/barebone.nim.cfg
new file mode 100644
index 000000000..b956bef8e
--- /dev/null
+++ b/tests/manyloc/standalone/barebone.nim.cfg
@@ -0,0 +1,2 @@
+--os:standalone
+--gc:none
diff --git a/tests/manyloc/standalone/panicoverride.nim b/tests/manyloc/standalone/panicoverride.nim
new file mode 100644
index 000000000..c0b8bb030
--- /dev/null
+++ b/tests/manyloc/standalone/panicoverride.nim
@@ -0,0 +1,14 @@
+
+proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
+proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
+
+{.push stack_trace: off, profiler:off.}
+
+proc rawoutput(s: string) =
+  printf("%s\n", s)
+
+proc panic(s: string) {.noreturn.} =
+  rawoutput(s)
+  exit(1)
+
+{.pop.}
diff --git a/tests/manyloc/standalone2/panicoverride.nim b/tests/manyloc/standalone2/panicoverride.nim
new file mode 100644
index 000000000..c0b8bb030
--- /dev/null
+++ b/tests/manyloc/standalone2/panicoverride.nim
@@ -0,0 +1,14 @@
+
+proc printf(frmt: cstring) {.varargs, importc, header: "<stdio.h>", cdecl.}
+proc exit(code: int) {.importc, header: "<stdlib.h>", cdecl.}
+
+{.push stack_trace: off, profiler:off.}
+
+proc rawoutput(s: string) =
+  printf("%s\n", s)
+
+proc panic(s: string) {.noreturn.} =
+  rawoutput(s)
+  exit(1)
+
+{.pop.}
diff --git a/tests/manyloc/standalone2/tavr.nim b/tests/manyloc/standalone2/tavr.nim
new file mode 100644
index 000000000..6cbc5c699
--- /dev/null
+++ b/tests/manyloc/standalone2/tavr.nim
@@ -0,0 +1,7 @@
+# bug #16404
+
+proc printf(frmt: cstring) {.varargs, header: "<stdio.h>", cdecl.}
+
+var x = 0
+inc x
+printf("hi %ld\n", x+4777)
diff --git a/tests/manyloc/standalone2/tavr.nim.cfg b/tests/manyloc/standalone2/tavr.nim.cfg
new file mode 100644
index 000000000..2a31618d0
--- /dev/null
+++ b/tests/manyloc/standalone2/tavr.nim.cfg
@@ -0,0 +1,5 @@
+--gc:arc
+--cpu:avr
+--os:standalone
+--compileOnly
+--threads:off
diff --git a/tests/metatype/tbindtypedesc.nim b/tests/metatype/tbindtypedesc.nim
new file mode 100644
index 000000000..d9f034432
--- /dev/null
+++ b/tests/metatype/tbindtypedesc.nim
@@ -0,0 +1,95 @@
+discard """
+  output: '''ok'''
+"""
+
+import typetraits
+
+type
+  TFoo = object
+    x, y: int
+
+  TBar = tuple
+    x, y: int
+
+template accept(e) =
+  static: assert(compiles(e))
+
+template reject(e) =
+  static: assert(not compiles(e))
+
+proc genericParamRepeated[T: typedesc](a: T, b: T) =
+  static:
+    echo a.name, " ", b.name
+
+accept genericParamRepeated(int, int)
+accept genericParamRepeated(float, float)
+
+reject genericParamRepeated(string, int)
+reject genericParamRepeated(int, float)
+
+proc genericParamOnce[T: typedesc](a, b: T) =
+  static:
+    echo a.name, " ", b.name
+
+accept genericParamOnce(int, int)
+accept genericParamOnce(TFoo, TFoo)
+
+reject genericParamOnce(string, int)
+reject genericParamOnce(TFoo, float)
+
+type
+  type1 = typedesc
+  type2 = typedesc
+
+proc typePairs(A, B: type1; C, D: type2) = discard
+
+accept typePairs(int, int, TFoo, TFOO)
+accept typePairs(TBAR, TBar, TBAR, TBAR)
+accept typePairs(int, int, string, string)
+
+reject typePairs(TBAR, TBar, TBar, TFoo)
+reject typePairs(string, int, TBAR, TBAR)
+
+proc typePairs2[T: typedesc, U: typedesc](A, B: T; C, D: U) = discard
+
+accept typePairs2(int, int, TFoo, TFOO)
+accept typePairs2(TBAR, TBar, TBAR, TBAR)
+accept typePairs2(int, int, string, string)
+
+reject typePairs2(TBAR, TBar, TBar, TFoo)
+reject typePairs2(string, int, TBAR, TBAR)
+
+proc dontBind(a: typedesc, b: typedesc) =
+  static:
+    echo a.name, " ", b.name
+
+accept dontBind(int, float)
+accept dontBind(TFoo, TFoo)
+
+proc dontBind2(a, b: typedesc) = discard
+
+accept dontBind2(int, float)
+accept dontBind2(TBar, int)
+
+proc bindArg(T: typedesc, U: typedesc, a, b: T, c, d: U) = discard
+
+accept bindArg(int, string, 10, 20, "test", "nest")
+accept bindArg(int, int, 10, 20, 30, 40)
+
+reject bindArg(int, string, 10, "test", "test", "nest")
+reject bindArg(int, int, 10, 20, 30, "test")
+reject bindArg(int, string, 10.0, 20, "test", "nest")
+reject bindArg(int, string, "test", "nest", 10, 20)
+
+echo "ok"
+
+#11058:
+template test(S: type, U: type) =
+  discard
+
+test(int, float)
+
+proc test2(S: type, U: type) =
+  discard
+
+test2(float, int)
diff --git a/tests/metatype/tcompositetypeclasses.nim b/tests/metatype/tcompositetypeclasses.nim
new file mode 100644
index 000000000..43b6a57e4
--- /dev/null
+++ b/tests/metatype/tcompositetypeclasses.nim
@@ -0,0 +1,59 @@
+template accept(e) =
+  static: assert(compiles(e))
+
+template reject(e) =
+  static: assert(not compiles(e))
+
+type
+  TFoo[T, U] = tuple
+    x: T
+    y: U
+
+  TBar[K] = TFoo[K, K]
+
+  TUserClass = int|string
+
+  TBaz = TBar[TUserClass]
+
+var
+  vfoo: TFoo[int, string]
+  vbar: TFoo[string, string]
+  vbaz: TFoo[int, int]
+  vnotbaz: TFoo[RootObj, RootObj]
+
+proc foo(x: TFoo) = echo "foo"
+proc bar(x: TBar) = echo "bar"
+proc baz(x: TBaz) = echo "baz"
+
+accept foo(vfoo)
+accept bar(vbar)
+accept baz(vbar)
+accept baz(vbaz)
+
+reject baz(vnotbaz)
+reject bar(vfoo)
+
+# https://github.com/Araq/Nim/issues/517
+type
+  TVecT*[T] = array[0..1, T]|array[0..2, T]|array[0..3, T]
+  TVec2* = array[0..1, float32]
+
+proc f[T](a: TVecT[T], b: TVecT[T]): T = discard
+
+var x: float = f([0.0'f32, 0.0'f32], [0.0'f32, 0.0'f32])
+var y = f(TVec2([0.0'f32, 0.0'f32]), TVec2([0.0'f32, 0.0'f32]))
+
+# https://github.com/Araq/Nim/issues/602
+type
+  TTest = object
+  TTest2* = object
+  TUnion = TTest | TTest2
+
+proc f(src: ptr TUnion, dst: ptr TUnion) =
+  echo("asd")
+
+var tx: TTest
+var ty: TTest2
+
+accept f(addr tx, addr tx)
+reject f(addr tx, addr ty)
diff --git a/tests/metatype/tcps.nim b/tests/metatype/tcps.nim
new file mode 100644
index 000000000..042e32bd6
--- /dev/null
+++ b/tests/metatype/tcps.nim
@@ -0,0 +1,35 @@
+discard """
+  output: '''10
+string'''
+"""
+
+# bug #18059
+type
+  C = ref object of RootObj
+    fn: ContProc
+    ex: ref Exception
+
+  ContProc = proc (c: C): C {.nimcall.}
+
+proc noop(c: C): C = c
+
+type
+  Env[T] = ref object of C
+    x: T
+
+proc foo_cont[U](c: C): C =
+  proc afterCall[V](c: C): C =
+    echo Env[V](c).x
+
+  c.fn = afterCall[U]
+  return noop(c)
+
+proc foo[T](x: T): C =
+  return Env[T](fn: foo_cont[T], x: x)
+
+proc tramp(c: sink C) =
+  while c != nil and c.fn != nil:
+    c = c.fn(c)
+
+tramp foo(10)
+tramp foo("string")
diff --git a/tests/metatype/tmatrix1.nim b/tests/metatype/tmatrix1.nim
new file mode 100644
index 000000000..15913499f
--- /dev/null
+++ b/tests/metatype/tmatrix1.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "right proc called"
+"""
+
+type
+  TMatrixNM*[M, N, T] = object
+    aij*: array[M, array[N, T]]
+  TMatrix2x2*[T] = TMatrixNM[range[0..1], range[0..1], T]
+  TMatrix3x3*[T] = TMatrixNM[range[0..2], range[0..2], T]
+
+proc test*[T](matrix: TMatrix2x2[T]) =
+  echo "wrong proc called"
+
+proc test*[T](matrix: TMatrix3x3[T]) =
+  echo "right proc called"
+
+var matrix: TMatrix3x3[float]
+
+matrix.test
diff --git a/tests/metatype/tmatrix2.nim b/tests/metatype/tmatrix2.nim
new file mode 100644
index 000000000..bad021390
--- /dev/null
+++ b/tests/metatype/tmatrix2.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "5.0"
+"""
+
+type
+  TMatrixNM*[M, N, T] = object
+    aij*: T
+  TVectorN*[N, T] = TMatrixNM[range[0..0], N, T]
+  TVector3*[T] = TVectorN[range[0..2], T]
+
+proc coeffRef*[M, N, T] (matrix: var TMatrixNM[M, N, T], a: M, b: N): var T =
+  return matrix.aij
+
+proc coeffRef*[N, T] (vector: var TVectorN[N, T], i: N): var T = vector.aij
+
+var
+  testVar: TVector3[float]
+
+testVar.aij = 2.0
+testVar.coeffRef(1) = 5.0
+
+echo testVar.aij
diff --git a/tests/metatype/tmatrix3.nim b/tests/metatype/tmatrix3.nim
new file mode 100644
index 000000000..28e85fcee
--- /dev/null
+++ b/tests/metatype/tmatrix3.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "\n"
+"""
+
+type Matrix[M,N: static[int]] = array[M, array[N, float]]
+
+let a = [[1.0,  1.0,  1.0,   1.0],
+         [2.0,  4.0,  8.0,  16.0],
+         [3.0,  9.0, 27.0,  81.0],
+         [4.0, 16.0, 64.0, 256.0]]
+
+proc `$`(m: Matrix): string =
+  result = ""
+
+proc `*`[M,N,M2,N2](a: Matrix[M,N2]; b: Matrix[M2,N]): Matrix[M,N] =
+  discard
+
+echo a * a
+
diff --git a/tests/metatype/tmatrix4.nim b/tests/metatype/tmatrix4.nim
new file mode 100644
index 000000000..207d76fed
--- /dev/null
+++ b/tests/metatype/tmatrix4.nim
@@ -0,0 +1,39 @@
+import math
+
+type
+  TMatrix*[T; R, C: static[int]] = array[R, array[C, T]] ## Row major matrix type.
+  TMat4* = TMatrix[float32, 4, 4]
+  TVector*[T; C: static[int]] = array[C, T]
+  TVec4* = TVector[float32, 4]
+
+template row*[T; R, C: static[int]](m: TMatrix[T, R, C], rowidx: range[0..R-1]): TVector[T, R] =
+  m[rowidx]
+
+proc col*[T; R, C: static[int]](m: TMatrix[T, R, C], colidx: range[0..C-1]): TVector[T, C] {.noSideEffect.} =
+  for i in low(m)..high(m):
+    result[i] = m[i][colidx]
+
+proc dot(lhs, rhs: TVector): float32 =
+  for i in low(rhs)..high(rhs):
+    result += lhs[i] * rhs[i]
+
+proc `*`*[T; R, N, C: static[int]](a: TMatrix[T, R, N], b: TMatrix[T, N, C]): TMatrix[T, R, C] {.noSideEffect.} =
+  for i in low(a)..high(a):
+    for j in low(a[i])..high(a[i]):
+      result[i][j] = dot(a.row(i), b.col(j))
+
+proc translate*(v: TVec4): TMat4 {.noSideEffect.} =
+  result = [[1f32, 0f32, 0f32, 0f32],
+            [0f32, 1f32, 0f32, 0f32],
+            [0f32, 0f32, 1f32, 0f32],
+            [v[0], v[1], v[2], 1f32]]
+
+proc rotatex*(angle: float): TMat4 =
+  result = [[1f32,          0f32,           0f32,           0f32],
+            [0f32, cos(angle).float32, sin(angle).float32,  0f32],
+            [0f32, -sin(angle).float32, cos(angle).float32, 0f32],
+            [0f32,          0f32,           0f32,           1f32]]
+
+proc orbitxAround(point: TVec4, angle: float): TMat4 =
+  result = translate(point)*rotatex(angle)*translate(point)
+
diff --git a/tests/metatype/tmeta_typeclasses.nim b/tests/metatype/tmeta_typeclasses.nim
new file mode 100644
index 000000000..720527088
--- /dev/null
+++ b/tests/metatype/tmeta_typeclasses.nim
@@ -0,0 +1,70 @@
+discard """
+  output: '''12
+1xxx
+true0
+12
+testtest
+1010
+11string
+testtest1
+seq
+seq
+seq
+foo seq
+foo of numeric'''"""
+
+type
+  TFoo[T] = object
+    val: T
+
+  T1 = auto
+  T2 = auto
+
+  Numeric = int|float
+
+proc takesExpr(x, y: auto) =
+  echo x, y
+
+proc same(x, y: T1) =
+  echo x, y
+
+proc takesFoo(x, y: TFoo) =
+  echo x.val, y.val
+
+proc takes2Types[T1, T2](x,y: T1, z: T2) =
+  echo x, y, z
+
+takesExpr(1, 2)
+takesExpr(1, "xxx")
+takesExpr[bool, int](true, 0)
+
+same(1, 2)
+same("test", "test")
+
+var f: TFoo[int]
+f.val = 10
+
+takesFoo(f, f)
+
+takes2Types(1, 1, "string")
+takes2Types[string, int]("test", "test", 1)
+
+proc takesSeq(x: seq) =
+  echo "seq"
+
+takesSeq(@[1, 2, 3])
+takesSeq(@["x", "y", "z"])
+
+proc takesSeqOfFoos(x: seq[TFoo]) =
+  echo "foo seq"
+
+var sf = newSeq[TFoo[int]](3)
+
+takesSeq(sf)
+takesSeqOfFoos(sf)
+
+proc takesFooOfNumeric(x: TFoo[Numeric]) =
+  echo "foo of numeric"
+
+takesFooOfNumeric(sf[0])
+
diff --git a/tests/metatype/tmetatype_issues.nim b/tests/metatype/tmetatype_issues.nim
new file mode 100644
index 000000000..d33d8dd31
--- /dev/null
+++ b/tests/metatype/tmetatype_issues.nim
@@ -0,0 +1,168 @@
+discard """
+output:'''
+void
+("string", "string")
+1 mod 7
+@[2, 2, 2, 2, 2]
+impl 2 called
+asd
+Foo
+Bar
+'''
+joinable: false
+"""
+
+import typetraits, macros
+
+
+block t898:
+  proc measureTime(e: auto) =
+    echo e.type.name
+
+  proc generate(a: int): void =
+    discard
+
+  proc runExample =
+    var builder: int = 0
+
+    measureTime:
+      builder.generate()
+
+  measureTime:
+    discard
+
+
+
+block t7528:
+  macro bar(n: untyped) =
+    result = newNimNode(nnkStmtList, n)
+    result.add(newCall("write", newIdentNode("stdout"), n))
+
+  proc foo0[T](): auto = return (T.name, T.name)
+  bar foo0[string]()
+  echo ""
+
+
+
+block t5638:
+  type X = object
+    a_impl: int
+
+  proc a(x: X): int =
+    x.a_impl
+
+  var x: X
+  assert(not compiles((block:
+    x.a = 1
+  )))
+
+
+
+block t3706:
+  type Modulo[M: static[int]] = distinct int
+  proc modulo(a: int, M: static[int]): Modulo[M] = Modulo[M](a %% M)
+  proc `+`[M: static[int]](a, b: Modulo[M]): Modulo[M] = (a.int + b.int).modulo(M)
+  proc `$`[M: static[int]](a: Modulo[M]): string = $(a.int) & " mod " & $(M)
+
+  let
+    a = 3.modulo(7)
+    b = 5.modulo(7)
+  echo a + b
+
+
+
+block t3144:
+  type IntArray[N: static[int]] = array[N, int]
+
+  proc `$`(a: IntArray): string = $(@(a))
+
+  proc `+=`[N: static[int]](a: var IntArray[N], b: IntArray[N]) =
+    for i in 0 ..< N:
+      a[i] += b[i]
+
+  proc zeros(N: static[int]): IntArray[N] =
+    for i in 0 ..< N:
+      result[i] = 0
+
+  proc ones(N: static[int]): IntArray[N] =
+    for i in 0 ..< N:
+      result[i] = 1
+
+  proc sum[N: static[int]](vs: seq[IntArray[N]]): IntArray[N] =
+    result = zeros(N)
+    for v in vs:
+      result += v
+
+  echo sum(@[ones(5), ones(5)])
+
+
+
+block t6533:
+  type Value[T: static[int]] = typedesc
+  proc foo(order: Value[1]): auto = 0
+  doAssert foo(Value[1]) == 0
+
+
+
+block t2266:
+  proc impl(op: static[int]) = echo "impl 1 called"
+  proc impl(op: static[int], init: int) = echo "impl 2 called"
+
+  macro wrapper2: untyped = newCall(bindSym"impl", newLit(0), newLit(0))
+
+  wrapper2() # Code generation for this fails.
+
+
+
+block t602:
+  type
+    TTest = object
+    TTest2 = object
+    TFoo = TTest | TTest2
+
+  proc f(src: ptr TFoo, dst: ptr TFoo) =
+    echo("asd")
+
+  var x: TTest
+  f(addr x, addr x)
+
+
+
+block t3338:
+  type
+    Base[T] = Foo[T] | Bar[T]
+
+    Foo[T] = ref object
+      x: T
+
+    Bar[T] = ref object
+      x: T
+
+  proc test[T](ks: Foo[T], x, y: T): T =
+    echo("Foo")
+    return x + y + ks.x
+
+  proc test[T](ks: Bar[T], x, y: T): T =
+    echo("Bar")
+    return x
+
+  proc add[T](ksa: Base[T]) =
+    var test = ksa.test(5, 10)
+    ksa.x = test
+
+  var t1 = Foo[int32]()
+  t1.add()
+  doAssert t1.x == 15
+
+  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/tmetatype_various.nim b/tests/metatype/tmetatype_various.nim
new file mode 100644
index 000000000..45c74432d
--- /dev/null
+++ b/tests/metatype/tmetatype_various.nim
@@ -0,0 +1,73 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''[1, 0, 0, 0, 0, 0, 0, 0] CTBool[Ct[system.uint32]]'''
+"""
+
+block tconstraints:
+  proc myGenericProc[T: object|tuple|int|ptr|ref|distinct](x: T): string =
+    result = $x
+
+  type TMyObj = tuple[x, y: int]
+
+  var x: TMyObj
+
+  assert myGenericProc(232) == "232"
+  assert myGenericProc(x) == "(x: 0, y: 0)"
+
+
+
+block tfieldaccessor:
+  type
+    Test = object
+      x: int
+      case p: bool
+      of true:
+        a: int
+      else:
+        case q: bool
+        of true:
+          b: int
+        else:
+          discard
+
+  proc f[T](t: typedesc[T]): int =
+    1
+
+  assert Test.f == 1
+
+
+
+block tprocbothmeta:
+  proc myFun[A](x: A): auto =
+    result = float(x+10)
+
+  proc myMap[T,S](sIn: seq[T], f: proc (q: T): S): seq[S] =
+    result = newSeq[S](sIn.len)
+    for i in 0..<sIn.len:
+      result[i] = f(sIn[i])
+
+  assert myMap(@[1,2,3], myFun) == @[11.0, 12.0, 13.0]
+
+
+# https://github.com/nim-lang/Nim/issues/13646
+
+type
+  BaseUint* = SomeUnsignedInt or byte
+  Ct*[T] = distinct T
+    ## Constant-Time wrapper
+    ## Only constant-time operations in particular the ternary operator equivalent
+    ##   condition: if true: a else: b
+    ## are allowed
+
+  CTBool*[T] = distinct range[T(0)..T(1)]
+    ## Constant-Time boolean wrapper
+
+var x: array[8, CTBool[Ct[uint32]]]
+x[0] = (CTBool[Ct[uint32]])(1)
+echo x.repr, " ", typeof(x[0])
+
+block: # bug #23139
+  type Foo = enum a, b
+
+  var x: range[a..b]
+  doAssert (repr x) == "a"
diff --git a/tests/metatype/tmetatypematrix.nim b/tests/metatype/tmetatypematrix.nim
new file mode 100644
index 000000000..3ddbc239f
--- /dev/null
+++ b/tests/metatype/tmetatypematrix.nim
@@ -0,0 +1,46 @@
+discard """
+  output: "1.01.01.0"
+"""
+# Test overloading of [] with multiple indices
+
+type
+  TMatrix* = object
+    data: seq[float]
+    fWidth, fHeight: int
+
+template `|`(x, y: int): untyped = y * m.fWidth + x
+
+proc createMatrix*(width, height: int): TMatrix =
+  result.fWidth = width
+  result.fHeight = height
+  newSeq(result.data, width*height)
+
+proc width*(m: TMatrix): int {.inline.} = return m.fWidth
+proc height*(m: TMatrix): int {.inline.} = return m.fHeight
+
+proc `[]`*(m: TMatrix, x, y: int): float {.inline.} =
+  result = m.data[x|y]
+
+proc `[]=`*(m: var TMatrix, x, y: int, val: float) {.inline.} =
+  m.data[x|y] = val
+
+proc `-|`*(m: TMatrix): TMatrix =
+  ## transposes a matrix
+  result = createMatrix(m.height, m.width)
+  for x in 0..m.width-1:
+    for y in 0..m.height-1: result[y,x] = m[x,y]
+
+#m.row(0, 2) # select row
+#m.col(0, 89) # select column
+
+const
+  w = 3
+  h = 20
+
+var m = createMatrix(w, h)
+for i in 0..w-1:
+  m[i, i] = 1.0
+
+for i in 0..w-1:
+  stdout.write(m[i,i]) #OUT 111
+stdout.write "\n"
diff --git a/tests/metatype/tsemistatic.nim b/tests/metatype/tsemistatic.nim
new file mode 100644
index 000000000..56b9a6218
--- /dev/null
+++ b/tests/metatype/tsemistatic.nim
@@ -0,0 +1,31 @@
+discard """
+  nimout: "static 10\ndynamic\nstatic 20\n"
+  output: "s\nd\nd\ns"
+"""
+
+type
+  semistatic[T] =
+    static[T] or T
+
+template isStatic*(x): bool =
+  compiles(static(x))
+
+proc foo(x: semistatic[int]) =
+  when isStatic(x):
+    static: echo "static ", x
+    echo "s"
+  else:
+    static: echo "dynamic"
+    echo "d"
+
+foo 10
+
+var
+  x = 10
+  y: int
+
+foo x
+foo y
+
+foo 20
+
diff --git a/tests/metatype/tshacontext.nim b/tests/metatype/tshacontext.nim
new file mode 100644
index 000000000..7f649d202
--- /dev/null
+++ b/tests/metatype/tshacontext.nim
@@ -0,0 +1,44 @@
+
+# bug #14136
+
+type
+  MDigest*[bits: static[int]] = object
+    ## Message digest type
+    data*: array[bits div 8, byte]
+
+  Sha2Context*[bits: static[int],
+               bsize: static[int],
+               T: uint32|uint64] = object
+    count: array[2, T]
+    state: array[8, T]
+    buffer: array[bsize, byte]
+
+  sha256* = Sha2Context[256, 64, uint32]
+
+template hmacSizeBlock*(h: typedesc): int =
+  when (h is Sha2Context):
+    int(h.bsize)
+  else:
+    {.fatal: "Choosen hash primitive is not yet supported!".}
+
+type
+  HMAC*[HashType] = object
+    ## HMAC context object.
+    mdctx: HashType
+    opadctx: HashType
+    ipad: array[HashType.hmacSizeBlock, byte]
+    opad: array[HashType.hmacSizeBlock, byte]
+
+func hkdfExtract*[T;S,I: char|byte](ctx: var HMAC[T],
+                     prk: var MDigest[T.bits], # <------- error here "Error: type expected"
+                     salt: openArray[S],
+                     ikm: openArray[I]
+                    ) =
+  discard
+
+var ctx: HMAC[sha256]
+var prk: MDigest[sha256.bits]
+let salt = [byte 0x00, 0x01, 0x02]
+let ikm = "CompletelyRandomInput"
+
+ctx.hkdfExtract(prk, salt, ikm)
diff --git a/tests/metatype/tstatic_generic_typeclass.nim b/tests/metatype/tstatic_generic_typeclass.nim
new file mode 100644
index 000000000..0e9256a62
--- /dev/null
+++ b/tests/metatype/tstatic_generic_typeclass.nim
@@ -0,0 +1,30 @@
+type MyThing[T: static int] = object
+  when T == 300:
+    a: int
+
+var a = MyThing[300]()
+proc doThing(myThing: MyThing): string = $myThing
+proc doOtherThing[T](myThing: MyThing[T]): string = $myThing
+assert doThing(a) == $a
+assert doThing(MyThing[0]()) == $MyThing[0]()
+assert doOtherThing(a) == "(a: 0)"
+
+type
+  Backend* = enum
+    Cpu,
+    Cuda
+
+  Tensor*[B: static[Backend]; T] = object
+    shape: seq[int]
+    strides: seq[int]
+    offset: int
+    when B == Backend.Cpu:
+      data: seq[T]
+    else:
+      data_ptr: ptr T
+
+template shape*(t: Tensor): seq[int] =
+  t.shape
+
+
+assert Tensor[Cpu, int]().shape == @[]
diff --git a/tests/metatype/tstaticparammacro.nim b/tests/metatype/tstaticparammacro.nim
new file mode 100644
index 000000000..bcf28d331
--- /dev/null
+++ b/tests/metatype/tstaticparammacro.nim
@@ -0,0 +1,76 @@
+discard """
+  nimout: '''letters
+aa
+bb
+numbers
+11
+22
+AST a
+@[(c: 11, d: 22), (c: 33, d: 44)]
+AST b
+(e: @[55, 66], f: @[77, 88])
+55
+10
+20Test
+20
+'''
+"""
+
+import macros
+
+type
+  TConfig = tuple
+    letters: seq[string]
+    numbers:seq[int]
+
+const data: Tconfig = (@["aa", "bb"], @[11, 22])
+
+macro mymacro(data: static[TConfig]): untyped =
+  echo "letters"
+  for s in items(data.letters):
+    echo s
+  echo "numbers"
+  for n in items(data.numbers):
+    echo n
+
+mymacro(data)
+
+type
+  Ta = seq[tuple[c:int, d:int]]
+  Tb = tuple[e:seq[int], f:seq[int]]
+
+const
+  a : Ta = @[(11, 22), (33, 44)]
+  b : Tb = (@[55,66], @[77, 88])
+
+macro mA(data: static[Ta]): untyped =
+  echo "AST a\n", repr(data)
+
+macro mB(data: static[Tb]): untyped =
+  echo "AST b\n", repr(data)
+  echo data.e[0]
+
+mA(a)
+mB(b)
+
+type
+  Foo[N: static[int], Z: static[string]] = object
+
+macro staticIntMacro(f: static[int]): untyped =
+  echo f
+
+staticIntMacro 10
+
+var
+  x: Foo[20, "Test"]
+
+macro genericMacro[N; Z: static[string]](f: Foo[N, Z], ll = 3, zz = 12): untyped =
+  echo N, Z
+
+genericMacro x
+
+template genericTemplate[N, Z](f: Foo[N, Z], ll = 3, zz = 12): int = N
+
+static:
+  echo genericTemplate(x) # Error: internal error: (filename: compiler/evaltempl.nim, line: 39)
+
diff --git a/tests/metatype/tstaticparams.nim b/tests/metatype/tstaticparams.nim
new file mode 100644
index 000000000..de80d46ae
--- /dev/null
+++ b/tests/metatype/tstaticparams.nim
@@ -0,0 +1,197 @@
+discard """
+  output: "abracadabra\ntest\n3\n15\n4\n2\nfloat\n3\nfloat\nyin\nyang\n2\n4\n4\n2\n3"
+"""
+
+type
+  TFoo[T; Val: static[string]] = object
+    data: array[4, T]
+
+  TBar[T; I: static[int]] = object
+    data: array[I, T]
+
+  TA1[T; I: static[int]] = array[I, T]
+  TA2[T; I: static[int]] = array[0..I, T]
+  TA3[T; I: static[int]] = array[I-1, T]
+
+  TObj = object
+    x: TA3[int, 3]
+
+proc takeFoo(x: TFoo) =
+  echo "abracadabra"
+  echo TFoo.Val
+
+var x: TFoo[int, "test"]
+takeFoo(x)
+
+var y: TBar[float, 4]
+echo high(y.data)
+
+var
+  t1: TA1[float, 1]
+  t2: TA2[string, 4]
+  t3: TA3[int, 10]
+  t4: TObj
+
+# example from the manual:
+type
+  Matrix[M,N: static[int]; T] = array[0..(M*N - 1), T]
+    # Note how `Number` is just a type constraint here, while
+    # `static[int]` requires us to supply a compile-time int value
+
+  AffineTransform2D[T] = Matrix[3, 3, T]
+  AffineTransform3D[T] = Matrix[4, 4, T]
+
+var m: AffineTransform3D[float]
+echo high(m)
+
+proc getRows(mtx: Matrix): int =
+  result = mtx.M
+
+echo getRows(m)
+
+# issue 997
+type TTest[T: static[int], U: static[int]] = array[0..T*U, int]
+type TTestSub[N: static[int]] = TTest[1, N]
+
+var z: TTestSub[2]
+echo z.high
+
+# issue 1049
+proc matrix_1*[M, N, T](mat: Matrix[M,N,T], a: array[N, int]) = discard
+proc matrix_2*[M, N, T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
+
+proc matrix_3*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N, int]) = discard
+proc matrix_4*[M, N: static[int]; T](mat: Matrix[M,N,T], a: array[N+1, int]) = discard
+
+var
+  tmat: Matrix[4,4,int]
+  ar1: array[4, int]
+  ar2: array[5, int]
+
+matrix_1(tmat, ar1)
+matrix_2(tmat, ar2)
+matrix_3(tmat, ar1)
+matrix_4(tmat, ar2)
+
+template reject(x): untyped =
+  static: assert(not compiles(x))
+
+# test with arrays of wrong size
+reject matrix_1(tmat, ar2)
+reject matrix_2(tmat, ar1)
+reject matrix_3(tmat, ar2)
+reject matrix_4(tmat, ar1)
+
+# bug 1820
+
+type
+  T1820_1[T; Y: static[int]] = object
+    bar: T
+
+proc intOrFloat*[Y](f: T1820_1[int, Y]) = echo "int"
+proc intOrFloat*[Y](f: T1820_1[float, Y]) = echo "float"
+proc threeOrFour*[T](f: T1820_1[T, 3]) =  echo "3"
+proc threeOrFour*[T](f: T1820_1[T, 4]) = echo "4"
+
+var foo_1: T1820_1[float, 3]
+
+foo_1.intOrFloat
+foo_1.threeOrFour
+
+type
+  YinAndYang = enum
+    Yin,
+    Yang
+
+  T1820_2[T; Y: static[YinAndYang]] = object
+    bar: T
+
+proc intOrFloat*[Y](f: T1820_2[int, Y]) = echo "int"
+proc intOrFloat*[Y](f: T1820_2[float, Y]) = echo "float"
+proc yinOrYang*[T](f: T1820_2[T, YinAndYang.Yin]) = echo "yin"
+proc yinOrYang*[T](f: T1820_2[T, Yang]) = echo "yang"
+
+var foo_2: T1820_2[float, Yin]
+var foo_3: T1820_2[float, YinAndYang.Yang]
+
+foo_2.intOrFloat
+foo_2.yinOrYang
+foo_3.yinOrYang
+
+# bug 1859
+
+type
+  TypeWith2Params[N, M: static[int]] = object
+
+proc bindBothParams[N](x: TypeWith2Params[N, N]) = discard
+proc dontBind1[N,M](x: TypeWith2Params[N, M]) = discard
+proc dontBind2(x: TypeWith2Params) = discard
+
+var bb_1: TypeWith2Params[2, 2]
+var bb_2: TypeWith2Params[2, 3]
+
+bindBothParams(bb_1)
+reject bindBothParams(bb_2)
+
+dontBind1 bb_1
+dontBind1 bb_2
+
+dontBind2 bb_1
+dontBind2 bb_2
+
+# https://github.com/nim-lang/Nim/issues/4524
+const
+  size* = 2
+
+proc arraySize[N: static[int]](A: array[N, int]): int =
+  result = A.high - A.low + 1
+
+var A: array[size, int] = [1, 2]
+echo arraySize(A)
+
+# https://github.com/nim-lang/Nim/issues/3153
+
+proc outSize1[M: static[int], A](xs: array[M, A]): int = M
+echo outSize1([1, 2, 3, 4])
+
+type
+  Arr[N: static[int], A] = array[N, A]
+
+proc outSize2[M: static[int], A](xs: Arr[M, A]): int = M
+echo outSize2([1, 2, 3, 4]) # 4
+
+echo outSize2([
+  [1, 2, 3],
+  [4, 5, 6]
+]) # 2
+
+proc inSize[M, N: static[int]](xs: Arr[M, Arr[N, int]]): int = N
+
+echo inSize([
+  [1, 2, 3],
+  [4, 5, 6]
+])
+
+block: # #12864
+  template fun() =
+    type Object = object
+    proc fun(f: Object): int = 1
+    proc fun(f: static[int]): int = 2
+    doAssert fun(Object()) == 1
+
+    var a: Object
+    doAssert fun(a) == 1
+
+    proc fun2(f: Object): int = 1
+    proc fun2(f: static[Object]): int = 2
+    doAssert fun2(Object()) == 2
+    doAssert fun2(a) == 1
+    const a2 = Object()
+    doAssert fun2(a2) == 2
+
+  fun()
+  static: fun()
+
+when true: #12864 original snippet
+  import times
+  discard times.format(initDateTime(30, mMar, 2017, 0, 0, 0, 0, utc()), TimeFormat())
diff --git a/tests/metatype/tstaticvector.nim b/tests/metatype/tstaticvector.nim
new file mode 100644
index 000000000..85a66974b
--- /dev/null
+++ b/tests/metatype/tstaticvector.nim
@@ -0,0 +1,76 @@
+discard """
+  matrix: "--mm:orc"
+  output: '''0
+0
+2
+100
+30.0 TVec[1, system.float32](data: [2.0])
+'''
+"""
+
+type
+  RectArray*[R, C: static[int], T] = distinct array[R * C, T]
+
+  StaticMatrix*[R, C: static[int], T] = object
+    elements*: RectArray[R, C, T]
+
+  StaticVector*[N: static[int], T] = StaticMatrix[N, 1, T]
+
+proc foo*[N, T](a: StaticVector[N, T]): T = 0.T
+proc foobar*[N, T](a, b: StaticVector[N, T]): T = 0.T
+
+var a: StaticVector[3, int]
+
+echo foo(a) # OK
+echo foobar(a, a) # <--- hangs compiler
+
+# https://github.com/nim-lang/Nim/issues/3112
+
+type
+  Vector[N: static[int]] = array[N, float64]
+  TwoVectors[Na, Nb: static[int]] = tuple
+    a: Vector[Na]
+    b: Vector[Nb]
+
+var v: TwoVectors[2, 100]
+echo v[0].len
+echo v[1].len
+#let xx = 50
+v[1][50] = 0.0
+
+# https://github.com/nim-lang/Nim/issues/1051
+
+type
+  TMatrix[N,M: static[int], T] = object
+    data: array[0..M*N-1, T]
+
+  TMat4f = TMatrix[4,4,float32]
+  TVec3f = TMatrix[1,3,float32]
+  TVec4f = TMatrix[1,4,float32]
+
+  TVec[N: static[int]; T] = TMatrix[1,N,T]
+
+proc dot*(a, b: TVec): TVec.T =
+  #assert(a.data.len == b.data.len)
+  for i in 1..a.data.len:
+    result += a.data[i-1] * b.data[i-1]
+
+proc row*(a: TMatrix; i: int): auto =
+  result = TVec[TMatrix.M, TMatrix.T]()
+  for idx in 1 .. TMatrix.M:
+    result.data[idx-1] = a.data[(TMatrix.N * (idx-1)) + (i-1)]
+
+proc col*(a: TMatrix; j: int): auto =
+  result = TVec[TMatrix.N, TMatrix.T]()
+  for idx in 0 ..< TMatrix.N:
+    result.data[idx] = a.data[(TMatrix.N * (idx)) + (j-1)]
+
+proc mul*(a: TMat4f; b: TMat4f): TMat4f =
+  for i in 1..4:
+    for j in 1..4:
+      result.data[(4 * (j-1)) + (i-1)] = dot(row(a,i), col(b,j))
+
+var test = TVec4f(data: [1.0'f32, 2.0'f32, 3.0'f32, 4.0'f32])
+
+echo dot(test,test), " ", repr(col(test, 2))
+
diff --git a/tests/metatype/ttensor.nim b/tests/metatype/ttensor.nim
new file mode 100644
index 000000000..89a0bf007
--- /dev/null
+++ b/tests/metatype/ttensor.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+before tensor2:
+[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0]
+before tensor3:
+[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0]
+after tensor3:
+[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, 24.0, 25.0, 26.0]
+a3:
+[1000.0, 1001.0, 1002.0, 1003.0, 1004.0, 1005.0, 1006.0, 1007.0, 1008.0, 1009.0, 1010.0, 1011.0, 1012.0, 1013.0, 1014.0, 1015.0, 1016.0, 1017.0, 1018.0, 1019.0, 1020.0, 1021.0, 1022.0, 1023.0, 1024.0, 1025.0, 1026.0]'''
+"""
+
+import macros
+
+type
+  Tensor[Dim : static[int]] = object
+    data: array[Dim, float64]
+
+proc transpose(tensor: Tensor): Tensor =
+  # fake implementation, don't transpose anything at all
+  # just do something to see a change happening
+  for i in 0 ..< tensor.data.len:
+    result.data[i] = 1000 + tensor.data[i]
+
+var tensor2: Tensor[24]
+var tensor3: Tensor[27]
+
+for i, x in tensor2.data.mpairs():
+  x = float64(i)
+
+for i, x in tensor3.data.mpairs():
+  x = float64(i)
+
+echo "before tensor2:\n", tensor2.data.repr
+echo "before tensor3:\n", tensor3.data.repr
+
+var a3 = transpose(tensor3)
+echo "after tensor3:\n", tensor3.data.repr
+echo "a3:\n", a3.data.repr
diff --git a/tests/metatype/ttypedesc1.nim b/tests/metatype/ttypedesc1.nim
new file mode 100644
index 000000000..549dbc62a
--- /dev/null
+++ b/tests/metatype/ttypedesc1.nim
@@ -0,0 +1,68 @@
+import unittest, typetraits
+
+type
+  TFoo[T, U] = object
+    x: T
+    y: U
+
+proc getTypeName1(t: typedesc): string = t.name
+proc getTypeName2(t: type): string = t.name
+
+proc foo(T: type float, a: auto): string =
+  result = "float " & $(a.len > 5)
+
+proc foo(T: typedesc[TFoo], a: int): string =
+  result = "TFoo "  & $(a)
+
+proc foo(T: type[int or bool]): string =
+  var a: T
+  a = 10
+  result = "int or bool " & ($a)
+
+template foo(T: typedesc[seq]): string = "seq"
+
+test "types can be used as proc params":
+  # XXX: `check` needs to know that TFoo[int, float] is a type and
+  # cannot be assigned for a local variable for later inspection
+  check ((string.getTypeName1 == "string"))
+  check ((getTypeName2(int) == "int"))
+
+  check ((foo(TFoo[int, float], 1000) == "TFoo 1000"))
+
+  var f = 10.0
+  check ((foo(float, "long string") == "float true"))
+  check ((foo(type(f), [1, 2, 3]) == "float false"))
+
+  check ((foo(int) == "int or bool 10"))
+
+  check ((foo(seq[int]) == "seq"))
+  check ((foo(seq[TFoo[bool, string]]) == "seq"))
+
+template accept(x) =
+  static: assert(compiles(x))
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+var
+  si: seq[int]
+  ss: seq[string]
+
+proc foo(T: typedesc[seq], s: T) =
+  discard
+
+accept:
+  foo seq[int], si
+
+reject:
+  foo seq[string], si
+
+reject:
+  foo seq[int], ss
+
+# issue #12398
+reject:
+  let xs = [int, float, string]
+
+reject:
+  let data = @[int, typedesc]
diff --git a/tests/metatype/ttypedesc2.nim b/tests/metatype/ttypedesc2.nim
new file mode 100644
index 000000000..96dab9052
--- /dev/null
+++ b/tests/metatype/ttypedesc2.nim
@@ -0,0 +1,93 @@
+discard """
+  output: '''(x: 'a')'''
+"""
+
+type
+  Bar[T] = object
+    x: T
+
+proc infer(T: typeDesc): Bar[T] = Bar[T](x: 'a')
+
+let foo = infer(char)
+echo foo
+
+when true:
+  # bug #1783
+
+  type
+      uoffset_t* = uint32
+      FlatBufferBuilder* = object
+
+      Array* [T] = object
+          o*: uoffset_t
+          len*: int
+          data*: ptr UncheckedArray[T]
+
+  proc ca* (fbb: ptr FlatBufferBuilder, T: typedesc, len: int): Array[T] {.noinit.} =
+      result.len = len
+
+  var fbb: ptr FlatBufferBuilder
+  let boolarray = ca(fbb, bool, 2)
+  let boolarray2 = fbb.ca(bool, 2)
+
+# bug #1664
+type Point[T] = tuple[x, y: T]
+proc origin(T: typedesc): Point[T] = discard
+discard origin(int)
+
+block: # issue #12704
+  const a = $("a", "b")
+  proc fun() =
+    const str = $int
+    let b = $(str, "asdf")
+  fun()
+
+# https://github.com/nim-lang/Nim/issues/7516
+import typetraits
+
+block: #issue #12704
+  const a = $("a", "b")
+  proc fun() =
+    const str = name(int)
+    let b = $(str, "asdf")
+  fun()
+
+proc hasDefault1(T: type = int): auto = return T.name
+doAssert hasDefault1(int) == "int"
+doAssert hasDefault1(string) == "string"
+doAssert hasDefault1() == "int"
+
+proc hasDefault2(T = string): auto = return T.name
+doAssert hasDefault2(int) == "int"
+doAssert hasDefault2(string) == "string"
+doAssert hasDefault2() == "string"
+
+
+# bug #9195
+type
+  Error = enum
+    erA, erB, erC
+  Result[T, U] = object
+    x: T
+    u: U
+  PB = object
+
+proc decodeUVarint*(itzzz: typedesc[SomeUnsignedInt],
+                    data: openArray[char]): Result[itzzz, Error] =
+  result = Result[itzzz, Error](x: 0, u: erC)
+
+discard decodeUVarint(uint32, "abc")
+
+type
+  X = object
+  Y[T] = object
+
+proc testObj(typ: typedesc[object]): Y[typ] =
+  discard
+
+discard testObj(X)
+
+
+#bug 12804
+import typetraits
+discard int.name[0]
\ No newline at end of file
diff --git a/tests/metatype/ttypedesc3.nim b/tests/metatype/ttypedesc3.nim
new file mode 100644
index 000000000..d3a58853d
--- /dev/null
+++ b/tests/metatype/ttypedesc3.nim
@@ -0,0 +1,53 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  output: '''
+proc Base
+proc Child
+method Base
+method Child
+yield Base
+yield Child
+12
+1
+'''
+"""
+
+import typetraits
+
+type
+  Base = object of RootObj
+  Child = object of Base
+
+proc pr(T: type[Base]) = echo "proc " & T.name
+method me(T: type[Base]) = echo "method " & T.name
+iterator it(T: type[Base]): auto = yield "yield " & T.name
+
+Base.pr
+Child.pr
+
+Base.me
+Child.me #<- bug #2710
+
+for s in Base.it: echo s
+for s in Child.it: echo s #<- bug #2662
+
+
+# bug #11747
+
+type
+  MyType = object
+    a: int32
+    b: int32
+    c: int32
+
+  MyRefType = ref MyType
+
+echo sizeof(default(MyRefType)[])
+
+type
+  Foo[T] = object
+    val: T
+
+var x: Foo[int].val
+inc(x)
+echo x
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
new file mode 100644
index 000000000..d0843511d
--- /dev/null
+++ b/tests/metatype/ttypeselectors.nim
@@ -0,0 +1,100 @@
+discard """
+output: "8\n8\n4"
+"""
+
+import
+  macros, typetraits
+
+template selectType(x: int): type =
+  when x < 10:
+    int
+  else:
+    string
+
+template simpleTypeTempl: type =
+  string
+
+macro typeFromMacro: type = bindSym"string"
+
+# The tests below check that the result variable of the
+# selected type matches the literal types in the code:
+
+proc t1*(x: int): simpleTypeTempl() =
+  result = "test"
+
+proc t2*(x: int): selectType(100) =
+  result = "test"
+
+proc t3*(x: int): selectType(1) =
+  result = 10
+
+proc t4*(x: int): typeFromMacro() =
+  result = "test"
+
+var x*: selectType(50) = "test"
+
+proc t5*(x: selectType(5)) =
+  var y = x + 10
+  echo y
+
+var y*: type(t2(100)) = "test"
+
+proc t6*(x: type(t3(0))): type(t1(0)) =
+  result = $x
+
+proc t7*(x: int): type($x) =
+  result = "test"
+
+# This is a more complicated example involving a type
+# selection through a macro:
+# https://github.com/nim-lang/Nim/issues/7230
+
+macro getBase*(bits: static[int]): untyped =
+  if bits >= 128:
+    result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint64"))
+  else:
+    result = newTree(nnkBracketExpr, ident("MpUintBase"), ident("uint32"))
+
+type
+  BaseUint* = SomeUnsignedInt or MpUintBase
+
+  MpUintBase*[T] = object
+      lo*, hi*: T
+
+  ## This gets type mismatch
+  MpUint*[bits: static[int]] = getBase(bits)
+
+var m1: MpUint[128]
+var m2: MpUint[64]
+var m3: getBase(32)
+
+static:
+  # assert m1.type.name == "MpUintBase[uint64]"
+  assert m1.lo.type.name == "uint64"
+  assert m2.lo.type.name == "uint32"
+  assert m3.type.name == "MpUintBase[system.uint32]"
+
+# https://github.com/nim-lang/Nim/issues/7379
+
+import macros, typetraits
+
+macro works(): untyped =
+  result = getType(int64)
+
+macro fails(bits: static[int]): untyped =
+  if bits > 64:
+    result = getType(int64)
+  else:
+    result = getType(int32)
+
+type
+  Foo*[bits: static[int]] = works()
+  Bar*[bits: static[int]] = fails(bits)
+
+var a: Foo[16]
+var b: Bar[256]
+var c: Bar[32]
+
+echo sizeof(a)
+echo sizeof(b)
+echo sizeof(c)
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
new file mode 100644
index 000000000..0523390a7
--- /dev/null
+++ b/tests/metatype/ttypetraits.nim
@@ -0,0 +1,404 @@
+import typetraits
+import macros
+
+block: # toUnsigned, toSigned
+  var a1: toSigned(int16)
+  doAssert a1 is int16
+  var a2: toSigned(uint16)
+  doAssert $a2.typeof == "int16"
+  doAssert toSigned(uint32) is int32
+  doAssert uint64.toSigned is int64
+  doAssert int64.toSigned is int64
+  doAssert int64.toUnsigned is uint64
+  doAssert int.toUnsigned is uint
+  doAssert $uint.toUnsigned == "uint"
+  # disallowed for now
+  doAssert not compiles(toUnsigned(range[0..7]))
+  doAssert not compiles(toSigned(range[0..7]))
+
+block: # isNamedTuple
+  type Foo1 = (a:1,).type
+  type Foo2 = (Field0:1,).type
+  type Foo3 = ().type
+  type Foo4 = object
+  type Foo5[T] = tuple[x:int, y: T]
+  type Foo6[T] = (T,)
+
+  doAssert (a:1,).type.isNamedTuple
+  doAssert Foo1.isNamedTuple
+  doAssert Foo2.isNamedTuple
+  doAssert isNamedTuple(tuple[key: int])
+  doAssert not Foo3.isNamedTuple
+  doAssert not Foo4.isNamedTuple
+  doAssert not (1,).type.isNamedTuple
+  doAssert isNamedTuple(Foo5[int8])
+  doAssert not isNamedTuple(Foo5)
+  doAssert not isNamedTuple(Foo6[int8])
+
+proc typeToString*(t: typedesc, prefer = "preferTypeName"): string {.magic: "TypeTrait".}
+  ## Returns the name of the given type, with more flexibility than `name`,
+  ## and avoiding the potential clash with a variable named `name`.
+  ## prefer = "preferResolved" will resolve type aliases recursively.
+  # Move to typetraits.nim once api stabilized.
+
+block: # name, `$`
+  static:
+    doAssert $type(42) == "int"
+    doAssert int.name == "int"
+
+  const a1 = name(int)
+  const a2 = $(int)
+  const a3 = $int
+  doAssert a1 == "int"
+  doAssert a2 == "int"
+  doAssert a3 == "int"
+
+  proc fun[T: typedesc](t: T) =
+    const a1 = name(t)
+    const a2 = $(t)
+    const a3 = $t
+    doAssert a1 == "int"
+    doAssert a2 == "int"
+    doAssert a3 == "int"
+  fun(int)
+
+  doAssert $(int,) == "(int,)"
+  doAssert $(1,) == "(1,)" # just for comparison to make sure it has same structure
+  doAssert $tuple[] == "tuple[]"
+  doAssert $(int,) == "(int,)"
+  doAssert $(int, float) == "(int, float)"
+  doAssert $((int), tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float)) ==
+    "(int, tuple[], tuple[a: uint], tuple[a: uint, b: float], (int,), (int, float))"
+
+block: # typeToString
+  type MyInt = int
+  type
+    C[T0, T1] = object
+  type C2=C # alias => will resolve as C
+  type C2b=C # alias => will resolve as C (recursively)
+  type C3[U,V] = C[V,U]
+  type C4[X] = C[X,X]
+  template name2(T): string = typeToString(T, "preferResolved")
+  doAssert MyInt.name2 == "int"
+  doAssert C3[MyInt, C2b].name2 == "C3[int, C]"
+    # C3 doesn't get resolved to C, not an alias (nor does C4)
+  doAssert C2b[MyInt, C4[cstring]].name2 == "C[int, C4[cstring]]"
+  doAssert C4[MyInt].name2 == "C4[int]"
+  when BiggestFloat is float and cint is int:
+    doAssert C2b[cint, BiggestFloat].name2 == "C3[int, C3[float, int32]]"
+
+  template name3(T): string = typeToString(T, "preferMixed")
+  doAssert MyInt.name3 == "MyInt{int}"
+  doAssert (tuple[a: MyInt, b: float]).name3 == "tuple[a: MyInt{int}, b: float]"
+  doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 ==
+    "tuple[a: C[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]"
+
+  macro fn(): string =
+    # not 100% sure whether this should even compile; if some PR breaks this test,
+    # this could be revisited, maybe.
+    newLit $($getType(untyped), $getType(typed))
+  doAssert fn() == """("untyped", "typed")"""
+
+block distinctBase:
+  block:
+    type
+      Foo[T] = distinct seq[T]
+    var a: Foo[int]
+    doAssert a.type.distinctBase is seq[int]
+    doAssert seq[int].distinctBase is seq[int]
+    doAssert "abc".distinctBase == "abc"
+
+  block:
+    # simplified from https://github.com/nim-lang/Nim/pull/8531#issuecomment-410436458
+    macro uintImpl(bits: static[int]): untyped =
+      if bits >= 128:
+        let inner = getAST(uintImpl(bits div 2))
+        result = newTree(nnkBracketExpr, ident("UintImpl"), inner)
+      else:
+        result = ident("uint64")
+
+    type
+      BaseUint = UintImpl or SomeUnsignedInt
+      UintImpl[Baseuint] = object
+      Uint[bits: static[int]] = distinct uintImpl(bits)
+
+    doAssert Uint[128].distinctBase is UintImpl[uint64]
+
+    block:
+      type
+        AA = distinct seq[int]
+        BB = distinct string
+        CC = distinct int
+        AAA = AA
+
+      static:
+        var a2: AAA
+        var b2: BB
+        var c2: CC
+
+        doAssert(a2 is distinct)
+        doAssert(b2 is distinct)
+        doAssert(c2 is distinct)
+
+        doAssert($distinctBase(typeof(a2)) == "seq[int]")
+        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))
+
+  type
+    MyTupleType = (int,float,string)
+
+  static: doAssert MyTupleType.tupleLen == 3
+
+  type
+    MyGenericTuple[T] = (T,int,float)
+    MyGenericAlias = MyGenericTuple[string]
+  static: doAssert MyGenericAlias.tupleLen == 3
+
+  type
+    MyGenericTuple2[T,U] = (T,U,string)
+    MyGenericTuple2Alias[T] =  MyGenericTuple2[T,int]
+
+    MyGenericTuple2Alias2 =   MyGenericTuple2Alias[float]
+  static: doAssert MyGenericTuple2Alias2.tupleLen == 3
+
+  static: doAssert (int, float).tupleLen == 2
+  static: doAssert (1, ).tupleLen == 1
+  static: doAssert ().tupleLen == 0
+
+  let x = (1,2,)
+  doAssert x.tupleLen == 2
+  doAssert ().tupleLen == 0
+  doAssert (1,).tupleLen == 1
+  doAssert (int,).tupleLen == 1
+  doAssert type(x).tupleLen == 2
+  doAssert type(x).default.tupleLen == 2
+  type T1 = (int,float)
+  type T2 = T1
+  doAssert T2.tupleLen == 2
+
+block genericParams:
+  type Foo[T1, T2]=object
+  doAssert genericParams(Foo[float, string]) is (float, string)
+  type Foo1 = Foo[float, int]
+  doAssert genericParams(Foo1) is (float, int)
+  type Foo2 = Foo[float, Foo1]
+  doAssert genericParams(Foo2) is (float, Foo[float, int])
+  doAssert genericParams(Foo2) is (float, Foo1)
+  doAssert genericParams(Foo2).get(1) is Foo1
+  doAssert (int,).get(0) is int
+  doAssert (int, float).get(1) is float
+
+  type Bar[N: static int, T] = object
+  type Bar3 = Bar[3, float]
+  doAssert genericParams(Bar3) is (StaticParam[3], float)
+  doAssert genericParams(Bar3).get(0) is StaticParam
+  doAssert genericParams(Bar3).get(0).value == 3
+  doAssert genericParams(Bar[3, float]).get(0).value == 3
+  static: doAssert genericParams(Bar[3, float]).get(0).value == 3
+
+  type
+    VectorElementType = SomeNumber | bool
+    Vec[N: static[int], T: VectorElementType] = object
+      arr: array[N, T]
+    Vec4[T: VectorElementType] = Vec[4,T]
+    Vec4f = Vec4[float32]
+
+    MyTupleType = (int,float,string)
+    MyGenericTuple[T] = (T,int,float)
+    MyGenericAlias = MyGenericTuple[string]
+    MyGenericTuple2[T,U] = (T,U,string)
+    MyGenericTuple2Alias[T] =  MyGenericTuple2[T,int]
+    MyGenericTuple2Alias2 =   MyGenericTuple2Alias[float]
+
+  doAssert genericParams(MyGenericAlias) is (string,)
+  doAssert genericHead(MyGenericAlias) is MyGenericTuple
+  doAssert genericParams(MyGenericTuple2Alias2) is (float,)
+  doAssert genericParams(MyGenericTuple2[float, int]) is (float, int)
+  doAssert genericParams(MyGenericAlias) is (string,)
+  doAssert genericParams(Vec4f) is (float32,)
+  doAssert genericParams(Vec[4, bool]) is (StaticParam[4], bool)
+
+  block:
+    type Foo[T1, T2]=object
+    doAssert genericParams(Foo[float, string]) is (float, string)
+    type Bar[N: static float, T] = object
+    doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
+    type Bar2 = Bar[2.0, string]
+    doAssert genericParams(Bar2) is (StaticParam[2.0], string)
+    type Bar3 = Bar[1.0 + 2.0, string]
+    doAssert genericParams(Bar3) is (StaticParam[3.0], string)
+
+    const F = 5.0
+    type Bar4 = Bar[F, string]
+    doAssert genericParams(Bar4) is (StaticParam[5.0], string)
+    doAssert genericParams(Bar[F, string]) is (StaticParam[5.0], string)
+
+  block typeof:
+    var
+      a: seq[int]
+      b: array[42, float]
+      c: array[char, int]
+      d: array[1..2, char]
+
+    doAssert genericParams(typeof(a)).get(0) is int
+    doAssert genericParams(typeof(b)) is (range[0..41], float)
+    doAssert genericParams(typeof(c)) is (char, int)
+    doAssert genericParams(typeof(d)) is (range[1..2], char)
+
+  block nestedContainers:
+    doAssert genericParams(seq[Foo[string, float]]).get(0) is Foo[string, float]
+    doAssert genericParams(array[10, Foo[Bar[1, int], Bar[2, float]]]) is (StaticParam[10], Foo[Bar[1, int], Bar[2, float]])
+    doAssert genericParams(array[1..9, int]) is (range[1..9], int)
+
+##############################################
+# bug 13095
+
+type
+  CpuStorage[T] {.shallow.} = ref object
+    when supportsCopyMem(T):
+      raw_buffer*: ptr UncheckedArray[T] # 8 bytes
+      memalloc*: pointer                 # 8 bytes
+      isMemOwner*: bool                  # 1 byte
+    else: # Tensors of strings, other ref types or non-trivial destructors
+      raw_buffer*: seq[T]                # 8 bytes (16 for seq v2 backed by destructors?)
+
+var x = CpuStorage[string]()
+
+static:
+  doAssert(not string.supportsCopyMem)
+  doAssert x.T is string          # true
+  doAssert x.raw_buffer is seq
+
+block genericHead:
+  type Foo[T1,T2] = object
+    x1: T1
+    x2: T2
+  type FooInst = Foo[int, float]
+  type Foo2 = genericHead(FooInst)
+  doAssert Foo2 is Foo # issue #13066
+
+  block:
+    type Goo[T] = object
+    type Moo[U] = object
+    type Hoo = Goo[Moo[float]]
+    type Koo = genericHead(Hoo)
+    doAssert Koo is Goo
+    doAssert genericParams(Hoo) is (Moo[float],)
+    doAssert genericParams(Hoo).get(0) is Moo[float]
+    doAssert genericHead(genericParams(Hoo).get(0)) is Moo
+
+  type Foo2Inst = Foo2[int, float]
+  doAssert FooInst.default == Foo2Inst.default
+  doAssert FooInst.default.x2 == 0.0
+  doAssert Foo2Inst is FooInst
+  doAssert FooInst is Foo2Inst
+  doAssert compiles(genericHead(FooInst))
+  doAssert not compiles(genericHead(Foo))
+  type Bar = object
+  doAssert not compiles(genericHead(Bar))
+
+  when false: # xxx not supported yet
+    doAssert seq[int].genericHead is seq
+  when false: # xxx not supported yet, gives: Error: identifier expected
+    type Hoo[T] = object
+    doAssert genericHead(Hoo[int])[float] is Hoo[float]
+
+block: # elementType
+  iterator myiter(n: int): auto =
+    for i in 0..<n: yield i
+  iterator myiter3(): int = yield 10
+  iterator myiter2(n: int): auto {.closure.} =
+    for i in 0..<n: yield i
+  doAssert elementType(@[1,2]) is int
+  doAssert elementType("asdf") is char
+  doAssert elementType(myiter(3)) is int
+  doAssert elementType(myiter2(3)) is int
+  doAssert elementType([1.1]) is float
+  doAssert compiles elementType([1])
+  doAssert not compiles elementType(1)
+  doAssert compiles elementType(myiter3())
+  doAssert not compiles elementType(myiter3)
+  # check that it also works for 0-sized seq:
+  var a: seq[int]
+  doAssert elementType(a) is int
+  doAssert elementType(seq[char].default) is char
+
+block: # enum.len
+  type
+    Direction = enum
+      north, east, south, west
+    
+    Direction2 = Direction
+    Direction3 = Direction2
+
+    TokenType = enum
+      a = 2, b = 4, c = 89
+    
+    MyEnum = enum
+      ##[This is test of enum with a doc comment.
+
+         Which is also a multi line one.]##
+      valueA = (0, "my value A"),
+        ## The items are also commented. This has both integer and string
+        ## values.
+      valueB = "value B",
+        ## This item has only a string value,
+      valueC = 2,
+        ## and this one only an integer.
+      valueD = (3, "abc")
+        ## Both, integer and string values again.
+
+    OtherEnum {.pure.} = enum
+      valueX, valueY, valueZ
+
+    MyFlag {.size: sizeof(cint).} = enum
+      A, B, C, D
+
+  static:
+    doAssert Direction.enumLen == 4
+    doAssert Direction2.enumLen == 4
+    doAssert Direction3.enumLen == 4
+    doAssert TokenType.enumLen == 3
+    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/tunresolved_return_type.nim b/tests/metatype/tunresolved_return_type.nim
new file mode 100644
index 000000000..637a9b733
--- /dev/null
+++ b/tests/metatype/tunresolved_return_type.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "cannot instantiate: 'T'"
+  line: 12
+"""
+
+# bug #2594
+
+
+type
+  ResultValue* = int64
+
+proc toNumber[T: int|uint|int64|uint64](v: ResultValue): T =
+  if v < low(T) or v > high(T):
+    raise newException(RangeDefect, "protocol error")
+  return T(v)
+
+#proc toNumber[T](v: int32): T =
+#  return (v)
+
+echo toNumber(23)
diff --git a/tests/metatype/tvoid_must_not_match.nim b/tests/metatype/tvoid_must_not_match.nim
new file mode 100644
index 000000000..c786c2f16
--- /dev/null
+++ b/tests/metatype/tvoid_must_not_match.nim
@@ -0,0 +1,21 @@
+discard """
+  errormsg: "type mismatch: got <Future[system.int], void>"
+  line: 20
+"""
+
+type
+  Future[T] = object
+    value: T
+
+proc complete[T](x: T) =
+  echo "completed"
+  let y = x
+
+
+proc complete*[T](future: var Future[T], val: T) =
+  future.value = val
+
+var a: Future[int]
+
+complete(a):
+  echo "yielding void"
diff --git a/tests/metatype/twildtypedesc.nim b/tests/metatype/twildtypedesc.nim
new file mode 100644
index 000000000..d1c5ffba5
--- /dev/null
+++ b/tests/metatype/twildtypedesc.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''123
+123
+123
+123
+123
+123'''
+"""
+
+import strutils
+
+proc unpack(t: typedesc[string], v: string): string = $v
+proc unpack(t: typedesc[int], v: string): int = parseInt(v)
+
+proc unpack[T](v: string): T =
+  unpack T, v
+
+var s = "123"
+
+doAssert(unpack[string](s) is string)
+doAssert(unpack[int](s) is int)
+
+echo unpack[int](s)
+echo unpack[string](s)
+
+echo unpack(int,s)
+echo unpack(string,s)
+
+template `as`*(x: untyped, t: typedesc): untyped = unpack(t,x)
+
+echo s as int
+echo s as string
+
+# bug #4534
+
+proc unit(t: typedesc[int]): t = 0
+proc unit(t: typedesc[string]): t = ""
+proc unit(t: typedesc[float]): t = 0.0
+
+doAssert unit(int) == 0
+doAssert unit(string) == ""
+doAssert unit(float) == 0.0
+
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/metatype/tymatrix.nim b/tests/metatype/tymatrix.nim
new file mode 100644
index 000000000..cf36bfa63
--- /dev/null
+++ b/tests/metatype/tymatrix.nim
@@ -0,0 +1,21 @@
+template reject(e) =
+  static: assert(not compiles(e))
+
+type
+  TMatrix[T; M, N: static[int]] = array[M*N, T]
+
+proc `*`[T; R, N, C](a: TMatrix[T, R, N], b: TMatrix[T, N, C]): TMatrix[T, R, C] =
+  discard
+
+var m1: TMatrix[int, 6, 4]
+var m2: TMatrix[int, 4, 3]
+var m3: TMatrix[int, 3, 3]
+
+var m4 = m1*m2
+static: assert m4.M == 6 and m4.N == 3
+
+reject m1 * m3 # not compatible
+
+var m5 = m2 * m3
+static: assert high(m5) == 11 # 4*3 - 1
+
diff --git a/tests/metatype/typeclassinference.nim b/tests/metatype/typeclassinference.nim
new file mode 100644
index 000000000..b3f197718
--- /dev/null
+++ b/tests/metatype/typeclassinference.nim
@@ -0,0 +1,43 @@
+discard """
+  errormsg: "type mismatch: got <string> but expected 'ptr'"
+  line: 20
+"""
+
+import typetraits
+
+type
+  Vec[N: static[int]; T] = distinct array[N, T]
+
+var x = Vec([1, 2, 3])
+
+static:
+  assert x.type.name == "Vec[3, system.int]"
+
+var str1: string = "hello, world!"
+var ptr1: ptr = addr(str1)
+
+var str2: string = "hello, world!"
+var ptr2: ptr = str2
+
+block: # built in typeclass inference
+  proc tupleA(): tuple = return (1, 2)
+  proc tupleB(): tuple = (1f, 2f)
+  assert typeof(tupleA()) is (int, int)
+  assert typeof(tupleB()) is (float32, float32)
+
+  proc a(val: int or float): tuple = 
+    when typeof(val) is int:
+      (10, 10)
+    else:
+      (30f, 30f)
+
+  assert typeof(a(10)) is (int, int)
+  assert typeof(a(10.0)) is (float32, float32)
+
+  proc b(val: int or float): set = 
+    when typeof(val) is int:
+      {10u8, 3}
+    else:
+      {'a', 'b'}
+  assert typeof(b(10)) is set[uint8]
+  assert typeof(b(10.0)) is set[char]
\ No newline at end of file
diff --git a/tests/metatype/typedesc_as_value.nim b/tests/metatype/typedesc_as_value.nim
new file mode 100644
index 000000000..463d23724
--- /dev/null
+++ b/tests/metatype/typedesc_as_value.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "invalid type: 'typedesc[int]' for var"
+"""
+
+
+var x = int
+
+echo x
+
+
+
diff --git a/tests/metatype/utypeclasses.nim b/tests/metatype/utypeclasses.nim
new file mode 100644
index 000000000..f94b39742
--- /dev/null
+++ b/tests/metatype/utypeclasses.nim
@@ -0,0 +1,13 @@
+import unittest
+
+proc concat(a, b): string =
+  result = $a & $b
+
+block: # if proc param types are not supplied, the params are assumed to be generic
+  check concat(1, "test") == "1test"
+  check concat(1, 20) == "120"
+  check concat("foo", "bar") == "foobar"
+
+block: # explicit param types can still be specified
+  check concat[cstring, cstring]("x", "y") == "xy"
+
diff --git a/tests/method/mmultim3.nim b/tests/method/mmultim3.nim
new file mode 100644
index 000000000..a97248203
--- /dev/null
+++ b/tests/method/mmultim3.nim
@@ -0,0 +1,12 @@
+type
+    TObj* {.inheritable.} = object
+
+var myObj* : ref TObj
+
+method test123(a : ref TObj) {.base.} =
+    echo("Hi base!")
+
+proc testMyObj*() =
+    test123(myObj)
+
+
diff --git a/tests/method/t20515.nim b/tests/method/t20515.nim
new file mode 100644
index 000000000..1921f2e46
--- /dev/null
+++ b/tests/method/t20515.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "Base method 'zzz' requires explicit '{.gcsafe.}' to be GC-safe"
+  line: 10
+"""
+
+type
+  A = ref object of RootObj
+  B = ref object of A
+
+method zzz(a: A) {.base.} =
+  discard
+
+var s: seq[int]
+method zzz(a: B) =
+  echo s
+
+proc xxx(someObj: A) {.gcsafe.} =
+  someObj.zzz()
+
+xxx(B())
diff --git a/tests/method/t22673.nim b/tests/method/t22673.nim
new file mode 100644
index 000000000..1689e9d42
--- /dev/null
+++ b/tests/method/t22673.nim
@@ -0,0 +1,21 @@
+discard """
+  matrix: "--warningAsError:UseBase"
+"""
+
+# bug #22673
+type RefEntry = ref object of RootObj
+
+type RefFile = ref object of RefEntry
+    filename*: string
+    data*: string
+
+type RefDir = ref object of RefEntry
+    dirname*: string
+    files*: seq[RefFile]
+
+method name*(e: RefEntry): lent string {.base.} =
+  raiseAssert "Don't call the base method"
+
+method name*(e: RefFile): lent string = e.filename
+
+method name*(e: RefDir): lent string = e.dirname
\ No newline at end of file
diff --git a/tests/method/tcompilegenerics.nim b/tests/method/tcompilegenerics.nim
new file mode 100644
index 000000000..d0732895b
--- /dev/null
+++ b/tests/method/tcompilegenerics.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  output: '''
+newDNode base
+'''
+"""
+
+type
+  SNodeAny = ref object of RootObj
+  SNode[T] = ref object of SNodeAny
+    m: T
+  DNode[T] = ref object
+
+method getStr(s: SNode[float]): string {.base.} = "blahblah"
+
+method newDNode(s: SNodeAny) {.base.} =
+  echo "newDNode base"
+
+method newDNode[T](s: SNode[T]) =
+  echo "newDNode generic"
+
+let m = SNode[float]()
+let s = SNodeAny(m)
+newDnode(s)
\ No newline at end of file
diff --git a/tests/method/tgeneric_methods.nim b/tests/method/tgeneric_methods.nim
new file mode 100644
index 000000000..f8d068cc5
--- /dev/null
+++ b/tests/method/tgeneric_methods.nim
@@ -0,0 +1,42 @@
+discard """

+  matrix: "--mm:arc --multimethods:on -d:nimInternalNonVtablesTesting; --mm:refc --multimethods:on -d:nimInternalNonVtablesTesting"

+  output: '''wow2

+X 1

+X 3'''

+"""

+type

+  First[T] = ref object of RootObj

+    value: T

+

+  Second[T] = ref object of First[T]

+    value2: T

+

+method wow[T](y: int; x: First[T]) {.base.} =

+  echo "wow1"

+

+method wow[T](y: int; x: Second[T]) =

+  echo "wow2"

+

+var

+  x: Second[int]

+new(x)

+

+proc takeFirst(x: First[int]) =

+  wow(2, x)

+

+takeFirst(x)

+

+

+# bug #5479

+type

+  Base[T: static[int]] = ref object of RootObj

+

+method test[T](t: Base[T]) {.base.} =

+  echo "X ", t.T

+

+let ab = Base[1]()

+

+ab.test()

+

+let ac = Base[3]()

+ac.test()

diff --git a/tests/method/tmapper.nim b/tests/method/tmapper.nim
new file mode 100644
index 000000000..9162d0eec
--- /dev/null
+++ b/tests/method/tmapper.nim
@@ -0,0 +1,30 @@
+discard """
+  errormsg: "invalid declaration order; cannot attach 'step' to method defined here: tmapper.nim(22, 8)"
+  line: 25
+"""
+
+# bug #2590
+
+type
+  Console* = ref object
+    mapper*: Mapper
+
+  Mapper* = ref object of RootObj
+
+  Mapper2* = ref object of Mapper
+
+proc newMapper2*: Mapper2 =
+  new result
+
+proc newMapper*: Mapper =
+  result = newMapper2()
+
+method step*(m: Mapper2) {.base.} =
+  echo "Mapper2"
+
+method step*(m: Mapper) {.base.} =
+  echo "Mapper"
+
+var console = Console()
+console.mapper = newMapper()
+console.mapper.step()
diff --git a/tests/method/tmethod.nim b/tests/method/tmethod.nim
new file mode 100644
index 000000000..005294d64
--- /dev/null
+++ b/tests/method/tmethod.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "\'method\' needs a parameter that has an object type"
+  file: "tmethod.nim"
+  line: 7
+"""
+
+method m(i: int): int =
+  return 5
diff --git a/tests/method/tmethod_issues.nim b/tests/method/tmethod_issues.nim
new file mode 100644
index 000000000..daaa46522
--- /dev/null
+++ b/tests/method/tmethod_issues.nim
@@ -0,0 +1,170 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  output: '''
+wof!
+wof!
+type A
+type B
+'''
+"""
+
+
+# bug #1659
+type Animal {.inheritable.} = ref object
+type Dog = ref object of Animal
+
+method say(a: Animal): auto {.base.} = "wat!"
+method say(a: Dog): auto = "wof!"
+
+proc saySomething(a: Animal): auto = a.say()
+
+method ec(a: Animal): auto {.base.} = echo "wat!"
+method ec(a: Dog): auto = echo "wof!"
+
+proc ech(a: Animal): auto = a.ec()
+
+var a = Dog()
+echo saySomething(a)
+ech a
+
+
+
+# bug #2401
+type MyClass = ref object of RootObj
+
+method HelloWorld*(obj: MyClass) {.base.} =
+  when defined(myPragma):
+    echo("Hello World")
+  # discard # with this line enabled it works
+
+var obj = MyClass()
+obj.HelloWorld()
+
+
+
+
+# bug #5432
+type
+  Iterator[T] = ref object of RootObj
+
+# base methods with `T` in the return type are okay
+method methodThatWorks*[T](i: Iterator[T]): T {.base.} =
+  discard
+
+# base methods without `T` (void or basic types) fail
+method methodThatFails*[T](i: Iterator[T]) {.base.} =
+  discard
+
+type
+  SpecificIterator1 = ref object of Iterator[string]
+  SpecificIterator2 = ref object of Iterator[int]
+
+
+
+
+# bug #3431
+type
+  Lexer = object
+    buf*: string
+    pos*: int
+    lastchar*: char
+
+  ASTNode = object
+
+method init*(self: var Lexer; buf: string) {.base.} =
+  self.buf = buf
+  self.pos = 0
+  self.lastchar = self.buf[0]
+
+method init*(self: var ASTNode; val: string) =
+  discard
+
+
+
+# bug #3370
+type
+  RefTestA*[T] = ref object of RootObj
+    data*: T
+
+method tester*[S](self: S): bool =
+  true
+
+type
+  RefTestB* = RefTestA[(string, int)]
+
+method tester*(self: RefTestB): bool =
+  true
+
+type
+  RefTestC = RefTestA[string]
+
+method tester*(self: RefTestC): bool =
+  false
+
+
+
+# bug #3468
+type X = ref object of RootObj
+type Y = ref object of RootObj
+
+method draw*(x: X) {.base.} = discard
+method draw*(y: Y) {.base.} = discard
+
+
+
+# bug #3550
+type 
+  BaseClass = ref object of RootObj
+  Class1 = ref object of BaseClass
+  Class2 = ref object of BaseClass
+  
+method test(obj: Class1, obj2: BaseClass) =
+  discard
+
+method test(obj: Class2, obj2: BaseClass) =
+  discard
+  
+var obj1 = Class1()
+var obj2 = Class2()
+
+obj1.test(obj2) 
+obj2.test(obj1)
+
+
+# -------------------------------------------------------
+# issue #16516
+
+type
+  A = ref object of RootObj
+    x: int
+
+  B = ref object of A
+
+method foo(v: sink A, lst: var seq[A]) {.base,locks:0.} =
+  echo "type A"
+  lst.add v
+
+method foo(v: sink B, lst: var seq[A]) =
+  echo "type B"
+  lst.add v
+
+proc main() =
+  let
+    a = A(x: 5)
+    b: A = B(x: 5)
+
+  var lst: seq[A]
+
+  foo(a, lst)
+  foo(b, lst)
+
+main()
+
+block: # bug #20391
+  type Container[T] = ref object of RootRef
+    item: T
+
+  let a = Container[int]()
+
+  doAssert a of Container[int]
+  doAssert not (a of Container[string])
diff --git a/tests/method/tmethod_various.nim b/tests/method/tmethod_various.nim
new file mode 100644
index 000000000..3b64aea8d
--- /dev/null
+++ b/tests/method/tmethod_various.nim
@@ -0,0 +1,79 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  output: '''
+HELLO WORLD!
+'''
+"""
+
+
+
+
+type
+  TNode* {.inheritable.} = object
+  PNode* = ref TNode
+
+  PNodeFoo* = ref object of TNode
+
+  TSomethingElse = object
+  PSomethingElse = ref TSomethingElse
+
+method foo(a: PNode, b: PSomethingElse) {.base.} = discard
+method foo(a: PNodeFoo, b: PSomethingElse) = discard
+
+
+
+
+# tmproto
+type
+  Obj1 {.inheritable.} = ref object
+  Obj2 = ref object of Obj1
+
+method beta(x: Obj1): int {.base.}
+
+proc delta(x: Obj2): int =
+  beta(x)
+
+method beta(x: Obj2): int
+
+proc alpha(x: Obj1): int =
+  beta(x)
+
+method beta(x: Obj1): int = 1
+method beta(x: Obj2): int = 2
+
+proc gamma(x: Obj1): int =
+  beta(x)
+
+doAssert alpha(Obj1()) == 1
+doAssert gamma(Obj1()) == 1
+doAssert alpha(Obj2()) == 2
+doAssert gamma(Obj2()) == 2
+doAssert delta(Obj2()) == 2
+
+
+
+# tsimmeth
+import strutils
+var x = "hello world!".toLowerAscii.toUpperAscii
+x.echo()
+
+
+
+# trecmeth
+# Note: We only compile this to verify that code generation
+# for recursive methods works, no code is being executed
+type Obj = ref object of RootObj
+
+# Mutual recursion
+method alpha(x: Obj) {.base.}
+method beta(x: Obj) {.base.}
+
+method alpha(x: Obj) =
+  beta(x)
+
+method beta(x: Obj) =
+  alpha(x)
+
+# Simple recursion
+method gamma(x: Obj) {.base.} =
+  gamma(x)
diff --git a/tests/method/tmethods_old.nim b/tests/method/tmethods_old.nim
new file mode 100644
index 000000000..d24eb0cc7
--- /dev/null
+++ b/tests/method/tmethods_old.nim
@@ -0,0 +1,12 @@
+discard """
+  matrix: "--mm:arc -d:nimInternalNonVtablesTesting"
+  output: '''
+do nothing
+'''
+"""
+
+# tmethods1
+method somethin(obj: RootObj) {.base.} =
+  echo "do nothing"
+var o: RootObj
+o.somethin()
diff --git a/tests/method/tmultim.nim b/tests/method/tmultim.nim
new file mode 100644
index 000000000..bba4d8c5c
--- /dev/null
+++ b/tests/method/tmultim.nim
@@ -0,0 +1,97 @@
+discard """

+  matrix: "--multimethods:on"

+  output: '''

+collide: unit, thing

+collide: unit, thing

+collide: thing, unit

+collide: thing, thing

+collide: unit, thing |

+collide: unit, thing |

+collide: thing, unit |

+do nothing

+'''

+  joinable: false

+  disabled: true

+"""

+

+

+# tmultim2

+type

+  TThing {.inheritable.} = object

+  TUnit = object of TThing

+    x: int

+  TParticle = object of TThing

+    a, b: int

+

+method collide(a, b: TThing) {.base, inline.} =

+  echo "collide: thing, thing"

+

+method collide(a: TThing, b: TUnit) {.inline.} =

+  echo "collide: thing, unit"

+

+method collide(a: TUnit, b: TThing) {.inline.} =

+  echo "collide: unit, thing"

+

+proc test(a, b: TThing) {.inline.} =

+  collide(a, b)

+

+proc staticCollide(a, b: TThing) {.inline.} =

+  procCall collide(a, b)

+

+var

+  a: TThing

+  b, c: TUnit

+collide(b, c) # ambiguous (unit, thing) or (thing, unit)? -> prefer unit, thing!

+test(b, c)

+collide(a, b)

+staticCollide(a, b)

+

+

+

+# tmultim6

+type

+  Thing {.inheritable.} = object

+  Unit[T] = object of Thing

+    x: T

+  Particle = object of Thing

+    a, b: int

+

+method collide(a, b: Thing) {.base, inline.} =

+  quit "to override!"

+

+method collide[T](a: Thing, b: Unit[T]) {.inline.} =

+  echo "collide: thing, unit |"

+

+method collide[T](a: Unit[T], b: Thing) {.inline.} =

+  echo "collide: unit, thing |"

+

+proc test(a, b: Thing) {.inline.} =

+  collide(a, b)

+

+var

+  aaa: Thing

+  bbb, ccc: Unit[string]

+collide(bbb, Thing(ccc))

+test(bbb, ccc)

+collide(aaa, bbb)

+

+

+

+# tmethods1

+method somethin(obj: RootObj) {.base.} =

+  echo "do nothing"

+

+type

+  TNode* {.inheritable.} = object

+  PNode* = ref TNode

+

+  PNodeFoo* = ref object of TNode

+

+  TSomethingElse = object

+  PSomethingElse = ref TSomethingElse

+

+method foo(a: PNode, b: PSomethingElse) {.base.} = discard

+method foo(a: PNodeFoo, b: PSomethingElse) = discard

+

+var o: RootObj

+o.somethin()

diff --git a/tests/method/tmultimjs.nim b/tests/method/tmultimjs.nim
new file mode 100644
index 000000000..36960f2e1
--- /dev/null
+++ b/tests/method/tmultimjs.nim
@@ -0,0 +1,73 @@
+discard """
+  output: '''
+7
+Hi derived!
+hello
+'''
+  disabled: true
+"""
+
+
+# tmultim1
+type
+  Expression {.inheritable.} = ref object
+  Literal = ref object of Expression
+    x: int
+  PlusExpr = ref object of Expression
+    a, b: Expression
+
+method eval(e: Expression): int {.base.} = quit "to override!"
+method eval(e: Literal): int = return e.x
+method eval(e: PlusExpr): int = return eval(e.a) + eval(e.b)
+
+proc newLit(x: int): Literal =
+  new(result)
+  result.x = x
+
+proc newPlus(a, b: Expression): PlusExpr =
+  new(result)
+  result.a = a
+  result.b = b
+
+echo eval(newPlus(newPlus(newLit(1), newLit(2)), newLit(4))) #OUT 7
+
+
+
+# tmultim3
+import mmultim3
+
+type TBObj* = object of TObj
+
+method test123(a : ref TBObj) =
+    echo("Hi derived!")
+
+var aa: ref TBObj
+new(aa)
+myObj = aa
+testMyObj()
+
+
+
+# tmultim4
+type Test = object of RootObj
+
+method doMethod(a: ref RootObj) {.base, raises: [IoError].} =
+  quit "override"
+
+method doMethod(a: ref Test) =
+  echo "hello"
+  if a == nil:
+    raise newException(IoError, "arg")
+
+proc doProc(a: ref Test) =
+  echo "hello"
+
+proc newTest(): ref Test =
+  new(result)
+
+var s:ref Test = newTest()
+
+#doesn't work
+for z in 1..4:
+  s.doMethod()
+  break
diff --git a/tests/method/tnildispatcher.nim b/tests/method/tnildispatcher.nim
new file mode 100644
index 000000000..219d2b29f
--- /dev/null
+++ b/tests/method/tnildispatcher.nim
@@ -0,0 +1,21 @@
+discard """
+  outputsub: '''Error: unhandled exception: cannot dispatch; dispatcher is nil [NilAccessDefect]'''
+  exitcode: 1
+"""
+# bug #5599
+type
+    Base = ref object of RootObj
+    Derived = ref object of Base
+
+method inner(obj: Base) {.base.} =
+    quit "to override"
+
+method outer(obj: Base) {.base.} =
+    echo "outer"
+    obj.inner()
+
+method inner(obj: Derived) =
+    echo "inner Derived"
+
+var x: Derived
+x.outer()
diff --git a/tests/method/treturn_var_t.nim b/tests/method/treturn_var_t.nim
new file mode 100644
index 000000000..91d982902
--- /dev/null
+++ b/tests/method/treturn_var_t.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''Inh
+45'''
+"""
+
+type
+  Base = ref object of RootObj
+    field: int
+
+  Inh = ref object of Base
+
+# bug #6777
+method foo(b: Base): var int {.base.} =
+  echo "Base"
+  result = b.field
+
+method foo(b: Inh): var int =
+  echo "Inh"
+  result = b.field
+
+var x: Base
+var y = Inh(field: 45)
+x = y
+echo foo(x)
+
diff --git a/tests/method/tsingle_methods.nim b/tests/method/tsingle_methods.nim
new file mode 100644
index 000000000..b564e7d87
--- /dev/null
+++ b/tests/method/tsingle_methods.nim
@@ -0,0 +1,48 @@
+discard """
+  matrix: "--mm:arc --multimethods:off; --mm:refc --multimethods:off"
+  output: '''base
+base
+base
+base
+base
+base
+'''
+"""
+
+# bug #10912
+
+type
+  X = ref object of RootObj
+
+type
+  A* = ref object of RootObj
+  B* = ref object of A
+  C* = ref object of A
+  D* = ref object of A
+  E* = ref object of A
+  F* = ref object of A
+
+method resolve(self: var X, stmt: A) {.base.} = echo "base"
+
+proc resolveSeq*(self: var X, statements: seq[A]) =
+  for statement in statements:
+    resolve(self, statement)
+
+method resolve(self: var X, stmt: B) =
+  echo "B"
+
+method resolve(self: var X, stmt: D) =
+  echo "D"
+
+method resolve(self: var X, stmt: E) =
+  echo "E"
+
+method resolve(self: var X, stmt: C) =
+  echo "C"
+
+method resolve(self: var X, stmt: F) =
+  echo "F"
+
+var x = X()
+var a = @[A(), B(), C(), D(), E(), F()]
+resolveSeq(x, a)
diff --git a/tests/method/tvtable.nim b/tests/method/tvtable.nim
new file mode 100644
index 000000000..a1b33d6b7
--- /dev/null
+++ b/tests/method/tvtable.nim
@@ -0,0 +1,24 @@
+discard """

+  targets: "c cpp"

+"""

+

+type FooBase = ref object of RootObj

+  dummy: int

+type Foo = ref object of FooBase

+  value : float32

+type Foo2 = ref object of Foo

+  change : float32

+method bar(x: FooBase, a: float32) {.base.} =

+  discard

+method bar(x: Foo, a: float32)  =

+  x.value += a

+method bar(x: Foo2, a: float32)  =

+  x.value += a

+

+

+proc test() =

+  var x = new Foo2

+  x.bar(2.3)

+  doAssert x.value <= 2.3

+

+test()
\ No newline at end of file
diff --git a/tests/misc/99bottles.nim b/tests/misc/99bottles.nim
new file mode 100644
index 000000000..14904ac0f
--- /dev/null
+++ b/tests/misc/99bottles.nim
@@ -0,0 +1 @@
+# Test if the compiler detects invalid module names
diff --git a/tests/misc/m15316.nim b/tests/misc/m15316.nim
new file mode 100644
index 000000000..188d06946
--- /dev/null
+++ b/tests/misc/m15316.nim
@@ -0,0 +1 @@
+proc foo = (if)
diff --git a/tests/misc/m15955.nim b/tests/misc/m15955.nim
new file mode 100644
index 000000000..22da345db
--- /dev/null
+++ b/tests/misc/m15955.nim
@@ -0,0 +1,4 @@
+proc add*(a, b: int): int {.cdecl, exportc.} =
+    a + b
+proc sub*(a, b: int): int {.cdecl, exportc.} =
+    a - b
\ No newline at end of file
diff --git a/tests/misc/m15955_main.nim b/tests/misc/m15955_main.nim
new file mode 100644
index 000000000..a71af8121
--- /dev/null
+++ b/tests/misc/m15955_main.nim
@@ -0,0 +1,11 @@
+import stdtest/specialpaths
+import std/os
+
+const buildLib = buildDir / "libD20220923T19380"
+
+{.passL: buildLib.}
+proc add*(a, b: int):int {.cdecl, importc.}
+proc sub*(a, b: int):int {.cdecl, importc.}
+
+echo add(10, 5)
+echo sub(10, 5)
diff --git a/tests/misc/m20149.nim b/tests/misc/m20149.nim
new file mode 100644
index 000000000..942262a6e
--- /dev/null
+++ b/tests/misc/m20149.nim
@@ -0,0 +1,2 @@
+let x = 12
+echo x
diff --git a/tests/misc/m20456.nims b/tests/misc/m20456.nims
new file mode 100644
index 000000000..8a9313129
--- /dev/null
+++ b/tests/misc/m20456.nims
@@ -0,0 +1 @@
+echo 123
\ No newline at end of file
diff --git a/tests/misc/mbackend.nim b/tests/misc/mbackend.nim
new file mode 100644
index 000000000..b6578a212
--- /dev/null
+++ b/tests/misc/mbackend.nim
@@ -0,0 +1,30 @@
+#[
+We can't merge this test inside a `when defined(cpp)` because some bug that was
+fixed would not trigger in that case.
+]#
+
+import std/compilesettings
+
+static:
+  ## bugfix 1: this used to CT error with: Error: unhandled exception: mimportcpp.nim(6, 18) `defined(cpp)`
+  doAssert defined(cpp)
+  doAssert querySetting(backend) == "cpp"
+
+  ## checks that `--backend:c` has no side effect (ie, can be overridden by subsequent commands)
+  doAssert not defined(c)
+  doAssert not defined(js)
+  doAssert not defined(js)
+
+type
+  std_exception {.importcpp: "std::exception", header: "<exception>".} = object
+proc what(s: std_exception): cstring {.importcpp: "((char *)#.what())".}
+
+var isThrown = false
+try:
+  ## bugfix 2: this used to CT error with: Error: only a 'ref object' can be raised
+  raise std_exception()
+except std_exception as ex:
+  doAssert ex.what().len > 0
+  isThrown = true
+
+doAssert isThrown
diff --git a/tests/misc/mbetterrun.nim b/tests/misc/mbetterrun.nim
new file mode 100644
index 000000000..d4f427af0
--- /dev/null
+++ b/tests/misc/mbetterrun.nim
@@ -0,0 +1,3 @@
+const mbetterrunVal {.strdefine.} = ""
+static: echo "compiling: " & mbetterrunVal
+echo "running: " & mbetterrunVal
diff --git a/tests/misc/mfield_defect.nim b/tests/misc/mfield_defect.nim
new file mode 100644
index 000000000..53bfba40e
--- /dev/null
+++ b/tests/misc/mfield_defect.nim
@@ -0,0 +1,30 @@
+#[
+ran from trunner
+]#
+
+
+
+
+
+
+# line 10
+type Kind = enum k0, k1, k2, k3, k4
+
+type Foo = object
+  case kind: Kind
+  of k0: f0: int
+  of k1: f1: int
+  of k2: f2: int
+  of k3: f3: int
+  of k4: f4: int
+
+proc main()=
+  var foo = Foo(kind: k3, f3: 3)
+  let s1 = foo.f3
+  doAssert s1 == 3
+  let s2 = foo.f2
+
+when defined case1:
+  static: main()
+when defined case2:
+  main()
diff --git a/tests/misc/mimportc.nim b/tests/misc/mimportc.nim
new file mode 100644
index 000000000..602c6372d
--- /dev/null
+++ b/tests/misc/mimportc.nim
@@ -0,0 +1,26 @@
+#[
+this test will grow with more importc+importcpp tests; see driver in trunner.nim
+]#
+
+{.emit:"""
+struct A {
+  static int fun0(int a){
+    return a;
+  }
+  static int& fun1(int& a){
+    return a;
+  }
+};
+""".}
+
+proc fun0*(a: cint): int {.importcpp:"A::$1(@)".}
+proc fun1*(a: var cint): var int {.importcpp:"A::$1(@)".} =
+  ## some comment; this test is for #14314
+  runnableExamples: discard
+
+proc main()=
+  var a = 10.cint
+  doAssert fun0(a) == a
+  doAssert fun1(a).addr == a.addr
+  echo "witness"
+main()
diff --git a/tests/minit.nim b/tests/misc/minit.nim
index d3b4b0be1..513f46af5 100755..100644
--- a/tests/minit.nim
+++ b/tests/misc/minit.nim
@@ -1,2 +1,2 @@
-# Test the new initialization for modules

-write(stdout, "Hallo from module! ")

+# Test the new initialization for modules
+write(stdout, "Hello from module! ")
diff --git a/tests/misc/mjsondoc.nim b/tests/misc/mjsondoc.nim
new file mode 100644
index 000000000..016c8522d
--- /dev/null
+++ b/tests/misc/mjsondoc.nim
@@ -0,0 +1,14 @@
+proc doSomething*(x, y: int): int =
+  ## do something
+  x + y
+
+const
+  a* = 1 ## echo 1234
+  b* = "test"
+
+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/modulea.nim b/tests/misc/modulea.nim
new file mode 100644
index 000000000..a9e6b364e
--- /dev/null
+++ b/tests/misc/modulea.nim
@@ -0,0 +1,2 @@
+type modulea* = object
+  a: int
diff --git a/tests/misc/msizeof5.nim b/tests/misc/msizeof5.nim
new file mode 100644
index 000000000..63573a705
--- /dev/null
+++ b/tests/misc/msizeof5.nim
@@ -0,0 +1,131 @@
+## tests for -d:checkAbi used by addAbiCheck via NIM_STATIC_ASSERT
+
+{.emit:"""/*TYPESECTION*/
+struct Foo1{
+  int a;
+};
+struct Foo2{
+  int a;
+};
+enum Foo3{k1, k2};
+typedef enum Foo3 Foo3b;
+typedef enum Foo4{k3, k4} Foo4;
+
+typedef int Foo5[3];
+
+typedef struct Foo6{
+  int a1;
+  bool a2;
+  double a3;
+  struct Foo6* a4;
+} Foo6;
+""".}
+
+template ensureCgen(T: typedesc) =
+  ## ensures cgen
+  var a {.volatile.}: T
+
+block:
+  type Foo1Alias{.importc: "struct Foo1", size: sizeof(cint).} = object
+    a: cint
+  ensureCgen Foo1Alias
+
+block:
+  type Foo3Alias{.importc: "enum Foo3", size: sizeof(cint).} = enum
+    k1, k2
+  ensureCgen Foo3Alias
+
+block:
+  type Foo3bAlias{.importc: "Foo3b", size: sizeof(cint).} = enum
+    k1, k2
+  ensureCgen Foo3bAlias
+
+block:
+  type Foo3b{.importc, size: sizeof(cint).} = enum
+    k1, k2
+  ensureCgen Foo3b
+  static:
+    doAssert Foo3b.sizeof == cint.sizeof
+
+block:
+  type Foo4{.importc, size: sizeof(cint).} = enum
+    k3, k4
+  # adding entries should not yield duplicate ABI checks, as enforced by
+  # `typeABICache`.
+  # Currently the test doesn't check for this but you can inspect the cgen'd file
+  ensureCgen Foo4
+  ensureCgen Foo4
+  ensureCgen Foo4
+
+block:
+  type Foo5{.importc.} = array[3, cint]
+  ensureCgen Foo5
+
+block:
+  type Foo5{.importc.} = array[3, cint]
+  ensureCgen Foo5
+
+block: # CT sizeof
+  type Foo6GT = object # grountruth
+    a1: cint
+    a2: bool
+    a3: cfloat
+    a4: ptr Foo6GT
+
+  type Foo6{.importc, completeStruct.} = object
+    a1: cint
+    a2: bool
+    a3: cfloat
+    a4: ptr Foo6
+
+  static: doAssert compiles(static(Foo6.sizeof))
+  static: doAssert Foo6.sizeof == Foo6GT.sizeof
+  static: doAssert (Foo6, int, array[2, Foo6]).sizeof ==
+    (Foo6GT, int, array[2, Foo6GT]).sizeof
+
+block:
+  type GoodImportcType {.importc: "signed char", nodecl.} = char
+    # "good" in sense the sizeof will match
+  ensureCgen GoodImportcType
+
+block:
+  type Foo6{.importc.} = object
+    a1: cint
+  doAssert compiles(Foo6.sizeof)
+  static: doAssert not compiles(static(Foo6.sizeof))
+
+when defined caseBad:
+  # Each case below should give a static cgen assert fail message
+
+  block:
+    type BadImportcType {.importc: "unsigned char", nodecl.} = uint64
+      # "sizeof" check will fail
+    ensureCgen BadImportcType
+
+  block:
+    type Foo2AliasBad{.importc: "struct Foo2", size: 1.} = object
+      a: cint
+    ensureCgen Foo2AliasBad
+
+  block:
+    type Foo5{.importc.} = array[4, cint]
+    ensureCgen Foo5
+
+  block:
+    type Foo5{.importc.} = array[3, bool]
+    ensureCgen Foo5
+
+  block:
+    type Foo6{.importc:"struct Foo6", completeStruct.} = object
+      a1: cint
+      # a2: bool # missing this should trigger assert fail
+      a3: cfloat
+      a4: ptr Foo6
+    ensureCgen Foo6
+
+  when false:
+    block:
+      # pre-existing BUG: this should give a CT error in semcheck because `size`
+      # disagrees with `array[3, cint]`
+      type Foo5{.importc, size: 1.} = array[3, cint]
+      ensureCgen Foo5
diff --git a/tests/misc/msizeof5.nim.cfg b/tests/misc/msizeof5.nim.cfg
new file mode 100644
index 000000000..dc0712a8c
--- /dev/null
+++ b/tests/misc/msizeof5.nim.cfg
@@ -0,0 +1,5 @@
+# Do not limit number of error messages from backend compiler.
+gcc.options.always %= "${gcc.options.always} -fmax-errors=100"
+clang.options.always %= "${clang.options.always} -ferror-limit=100"
+gcc.cpp.options.always %= "${gcc.cpp.options.always} -fmax-errors=100"
+clang.cpp.options.always %= "${clang.cpp.options.always} -ferror-limit=100"
diff --git a/tests/misc/mtlsemulation.h b/tests/misc/mtlsemulation.h
new file mode 100644
index 000000000..992977acd
--- /dev/null
+++ b/tests/misc/mtlsemulation.h
@@ -0,0 +1,37 @@
+#include <stdio.h>
+
+struct Foo1 {
+  /*
+  uncommenting would give:
+  error: initializer for thread-local variable must be a constant expression
+  N_LIB_PRIVATE NIM_THREADVAR Foo1 g1__9brEZhPEldbVrNpdRGmWESA;
+  */
+  // Foo1() noexcept { }
+
+  /*
+  uncommenting would give:
+  error: type of thread-local variable has non-trivial destruction
+  */
+  // ~Foo1() { }
+  int x;
+};
+
+struct Foo2 {
+  Foo2() noexcept { }
+  ~Foo2() { }
+  int x;
+};
+
+static int ctorCalls = 0;
+static int dtorCalls = 0;
+
+struct Foo3 {
+  Foo3() noexcept {
+    ctorCalls = ctorCalls + 1;
+    x = 10;
+  }
+  ~Foo3() {
+    dtorCalls = dtorCalls + 1;
+  }
+  int x;
+};
diff --git a/tests/misc/mvarious.nim b/tests/misc/mvarious.nim
new file mode 100644
index 000000000..8efe7c92f
--- /dev/null
+++ b/tests/misc/mvarious.nim
@@ -0,0 +1,6 @@
+# Test a submodule
+
+#type
+#  TStringArr = array[0.. *] of string
+
+proc exportme* = discard
diff --git a/tests/misc/parsecomb.nim b/tests/misc/parsecomb.nim
new file mode 100644
index 000000000..4f149cbf6
--- /dev/null
+++ b/tests/misc/parsecomb.nim
@@ -0,0 +1,109 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+"""
+
+type Input[T] = object
+  toks: seq[T]
+  index: int
+
+type
+  ResultKind* = enum rkSuccess, rkFailure
+  Result*[T, O] = object
+    case kind*: ResultKind
+    of rkSuccess:
+      output*: O
+      input: Input[T]
+    of rkFailure:
+      nil
+
+type
+  Parser*[T, O] = proc (input: Input[T]): Result[T, O]
+
+proc unit*[T, O](v: O): Parser[T, O] =
+  result = proc (inp: Input[T]): Result[T, O] =
+    Result[T, O](kind: rkSuccess, output: v, input: inp)
+
+proc fail*[T, O](): Parser[T, O] =
+  result = proc (inp: Input[T]): Result[T, O] =
+    Result(kind: rkFailure)
+
+method runInput[T, O](self: Parser[T, O], inp: Input[T]): Result[T, O] =
+  # hmmm ..
+  type tmp = proc (input: Input[T]): Result[T, O]
+  # XXX: above needed for now, as without the `tmp` bit below, it compiles to invalid C.
+  tmp(self)(inp)
+
+proc run*[T, O](self: Parser[T, O], toks: seq[T]): Result[T, O] =
+  self.runInput(Input[T](toks: toks, index: 0))
+
+proc chain*[T, O1, O2](self: Parser[T, O1], nextp: proc (v: O1): Parser[T, O2]): Parser[T, O2] =
+  result = proc (inp: Input[T]): Result[T, O2] =
+    let r = self.runInput(inp)
+    case r.kind:
+    of rkSuccess:
+      nextp(r.output).runInput(r.input)
+    of rkFailure:
+      Result[T, O2](kind: rkFailure)
+
+method skip[T](self: Input[T], n: int): Input[T] {.base.} =
+  Input[T](toks: self.toks, index: self.index + n)
+
+proc pskip*[T](n: int): Parser[T, tuple[]] =
+  result = proc (inp: Input[T]): Result[T, tuple[]] =
+    if inp.index + n <= inp.toks.len:
+      Result[T, tuple[]](kind: rkSuccess, output: (), input: inp.skip(n))
+    else:
+      Result[T, tuple[]](kind: rkFailure)
+
+proc tok*[T](t: T): Parser[T, T] =
+  result = proc (inp: Input[T]): Result[T, T] =
+    if inp.index < inp.toks.len and inp.toks[inp.index] == t:
+      pskip[T](1).then(unit[T, T](t)).runInput(inp)
+    else:
+      Result[T, T](kind: rkFailure)
+
+proc `+`*[T, O](first: Parser[T, O], second: Parser[T, O]): Parser[T, O] =
+  result = proc (inp: Input[T]): Result[T, O] =
+    let r = first.runInput(inp)
+    case r.kind
+    of rkSuccess:
+      r
+    else:
+      second.runInput(inp)
+
+# end of primitives (definitions involving Parser(..))
+
+proc map*[T, O1, O2](self: Parser[T, O1], p: proc (v: O1): O2): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    unit[T, O2](p(v)))
+
+proc then*[T, O1, O2](self: Parser[T, O1], next: Parser[T, O2]): Parser[T, O2] =
+  self.chain(proc (v: O1): Parser[T, O2] =
+    next)
+
+proc `*`*[T, O1, O2](first: Parser[T, O1], second: Parser[T, O2]): Parser[T, (O1, O2)] =
+  first.chain(proc (v1: O1): Parser[T, (O1, O2)] =
+    second.map(proc (v2: O2): (O1, O2) =
+      (v1, v2)))
+
+proc repeat0*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  var nothing = unit[T, seq[O]](@[])
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs)) + nothing
+
+proc repeat1*[T, O](inner: Parser[T, O]): Parser[T, seq[O]] =
+  inner.chain(proc(v: O): Parser[T, seq[O]] =
+    repeat0(inner).map(proc(vs: seq[O]): seq[O] =
+      @[v] & vs))
+
+proc leftRec*[T, O, A](inner: Parser[T, O], after: Parser[T, A], fold: proc(i: O, a: A): O): Parser[T, O] =
+  (inner*repeat0(after)).map(proc(ias: (O, seq[A])): O =
+    var (i, asx) = ias
+    for a in asx:
+      i = fold(i, a)
+    i)
+
+proc lazy*[T, O](inner: proc(): Parser[T, O]): Parser[T, O] =
+  unit[T, tuple[]](()).chain(proc(v: tuple[]): Parser[T, O] =
+    inner())
diff --git a/tests/misc/t11634.nim b/tests/misc/t11634.nim
new file mode 100644
index 000000000..390af40f4
--- /dev/null
+++ b/tests/misc/t11634.nim
@@ -0,0 +1,17 @@
+discard """
+  action: reject
+"""
+
+type Foo = ref object
+  val: int
+
+proc divmod(a, b: Foo): (Foo, Foo) =
+  (
+    Foo(val: a.val div b.val),
+    Foo(val: a.val mod b.val)
+  )
+
+block:
+  let a {.compileTime.} = Foo(val: 2)
+  let b {.compileTime.} = Foo(val: 3)
+  let (c11634 {.compileTime.}, d11634 {.compileTime.}) = divmod(a, b)
diff --git a/tests/misc/t12480.nim b/tests/misc/t12480.nim
new file mode 100644
index 000000000..992533ef6
--- /dev/null
+++ b/tests/misc/t12480.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "'return' not allowed here"
+"""
+
+return
\ No newline at end of file
diff --git a/tests/misc/t12869.nim b/tests/misc/t12869.nim
new file mode 100644
index 000000000..054e28a03
--- /dev/null
+++ b/tests/misc/t12869.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "type mismatch: got <openArray[int], proc (x: GenericParam, y: GenericParam): auto, SortOrder>"
+  line: 12
+"""
+
+import sugar
+from algorithm import sorted, SortOrder
+
+let a = 5
+
+proc sorted*[T](a: openArray[T], key: proc(v: T): int, order = SortOrder.Ascending): seq[T] =
+  sorted(a, (x, y) => key(x) < key(y), order)
+
+echo sorted(@[9, 1, 8, 2, 6, 4, 5, 0], (x) => (a - x).abs)
diff --git a/tests/misc/t14667.nim b/tests/misc/t14667.nim
new file mode 100644
index 000000000..3034e2841
--- /dev/null
+++ b/tests/misc/t14667.nim
@@ -0,0 +1,12 @@
+discard """
+  matrix: "--cc:vcc"
+  disabled: "linux"
+  disabled: "bsd"
+  disabled: "osx"
+  disabled: "unix"
+  disabled: "posix"
+"""
+
+type A = tuple
+discard ()
+discard default(A)
diff --git a/tests/misc/t15351.nim b/tests/misc/t15351.nim
new file mode 100644
index 000000000..c31e604a2
--- /dev/null
+++ b/tests/misc/t15351.nim
@@ -0,0 +1,5 @@
+discard """
+  action: "compile"
+"""
+var
+  ## TODO: broken
diff --git a/tests/misc/t15955.nim b/tests/misc/t15955.nim
new file mode 100644
index 000000000..7441e5398
--- /dev/null
+++ b/tests/misc/t15955.nim
@@ -0,0 +1,22 @@
+discard """
+joinable: false
+"""
+
+import stdtest/specialpaths
+import std/[osproc, strformat, os]
+
+const
+  nim = getCurrentCompilerExe()
+  buildLib = buildDir / "libD20220923T19380"
+  currentDir = splitFile(currentSourcePath).dir
+  file = currentDir / "m15955.nim"
+  main = currentDir / "m15955_main.nim"
+
+
+proc runCmd(cmd: string) =
+  let (msg, code) = execCmdEx(cmd)
+  doAssert code == 0, msg
+
+
+runCmd fmt"{nim} c -o:{buildLib} --nomain --nimMainPrefix:libA -f --app:staticlib {file}"
+runCmd fmt"{nim} c -r {main}"
diff --git a/tests/misc/t16244.nim b/tests/misc/t16244.nim
new file mode 100644
index 000000000..5e8128736
--- /dev/null
+++ b/tests/misc/t16244.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "type mismatch: got <int, float64>"
+  line: 9
+"""
+
+proc g(): auto = 1
+proc h(): auto = 1.0
+
+var a = g() + h()
diff --git a/tests/misc/t16264.nim b/tests/misc/t16264.nim
new file mode 100644
index 000000000..afe319e6c
--- /dev/null
+++ b/tests/misc/t16264.nim
@@ -0,0 +1,2 @@
+import times
+doAssert low(Time) == fromUnix(0)
\ No newline at end of file
diff --git a/tests/misc/t16541.nim b/tests/misc/t16541.nim
new file mode 100644
index 000000000..452327e8f
--- /dev/null
+++ b/tests/misc/t16541.nim
@@ -0,0 +1,12 @@
+discard """
+  action: "reject"
+
+"""
+
+import strutils, sugar, nre
+
+proc my_replace*(s: string, r: Regex, by: string | (proc (match: string): string)): string =
+  nre.replace(s, r, by)
+
+discard my_replace("abcde", re"[bcd]", match => match.to_upper) == "aBCDe"
+discard my_replace("abcde", re"[bcd]", (match: string) => match.to_upper) == "aBCDe"
diff --git a/tests/misc/t17286.nim b/tests/misc/t17286.nim
new file mode 100644
index 000000000..3a54e624e
--- /dev/null
+++ b/tests/misc/t17286.nim
@@ -0,0 +1,16 @@
+discard """
+  cmd: "nim check -b:js $file"
+  action: "compile"
+"""
+
+# bug #17286
+
+import std/compilesettings
+
+static:
+  doAssert querySetting(backend) == "js"
+  doAssert defined(js)
+  doAssert not defined(c)
+
+import random
+randomize()
\ No newline at end of file
diff --git a/tests/misc/t18077.nim b/tests/misc/t18077.nim
new file mode 100644
index 000000000..6cd05d575
--- /dev/null
+++ b/tests/misc/t18077.nim
@@ -0,0 +1,21 @@
+discard """
+  cmd: '''nim doc -d:nimTestsT18077b:4 --doccmd:"-d:nimTestsT18077 -d:nimTestsT18077b:3 --hints:off" $file'''
+  action: compile
+"""
+
+# bug #18077
+
+const nimTestsT18077b {.intdefine.} = 1
+
+static:
+  when defined(nimdoc):
+    doAssert nimTestsT18077b == 4
+    doAssert not defined(nimTestsT18077)
+  else:
+    doAssert defined(nimTestsT18077)
+    doAssert nimTestsT18077b == 3
+
+runnableExamples:
+  const nimTestsT18077b {.intdefine.} = 2
+  doAssert nimTestsT18077b == 3
+  doAssert defined(nimTestsT18077)
diff --git a/tests/misc/t18079.nim b/tests/misc/t18079.nim
new file mode 100644
index 000000000..ae64bbff9
--- /dev/null
+++ b/tests/misc/t18079.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+type
+  Foo = object
+    y: int
+
+  Bar = object
+    x: Foo
+
+proc baz(state: var Bar):int = 
+  state.x.y = 2
+  state.x.y
+doAssert baz((ref Bar)(x: (new Foo)[])[]) == 2
diff --git a/tests/misc/t19046.nim b/tests/misc/t19046.nim
new file mode 100644
index 000000000..b3bfec7ae
--- /dev/null
+++ b/tests/misc/t19046.nim
@@ -0,0 +1,19 @@
+discard """
+  targets: "c cpp"
+  matrix: "--threads:on"
+  disabled: "win"
+  disabled: "osx"
+  action: compile
+"""
+
+# bug #19046
+
+import std/os
+
+var t: Thread[void]
+
+proc test = discard
+proc main = 
+  createThread(t, test)
+  pinToCpu(t, 1)
+main()
\ No newline at end of file
diff --git a/tests/misc/t20253.nim b/tests/misc/t20253.nim
new file mode 100644
index 000000000..d47c36c55
--- /dev/null
+++ b/tests/misc/t20253.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "'result' requires explicit initialization"
+  line: 10
+"""
+
+type Meow {.requiresInit.} = object 
+  init: bool
+
+proc initMeow(): Meow =
+  discard
diff --git a/tests/misc/t20289.nim b/tests/misc/t20289.nim
new file mode 100644
index 000000000..5a0a269f0
--- /dev/null
+++ b/tests/misc/t20289.nim
@@ -0,0 +1,15 @@
+discard """
+  action: reject
+"""
+
+type E[T] = object
+  v: T
+
+template j[T](R: type E[T], x: untyped): R = R(v: x)
+template d[T](O: type E, v: T): E[T] = E[T].j(v)
+
+proc w[T](): E[T] =
+  template r(k: int): auto = default(T)
+  E.d r
+
+discard w[int]()
diff --git a/tests/misc/t20456_2.nim b/tests/misc/t20456_2.nim
new file mode 100644
index 000000000..37e52c452
--- /dev/null
+++ b/tests/misc/t20456_2.nim
@@ -0,0 +1,14 @@
+discard """
+  joinable: false
+"""
+
+import std/[osproc, os, strformat]
+from stdtest/specialpaths import testsDir
+
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+
+const
+  nim = getCurrentCompilerExe()
+  file = testsDir / "misc" / "m20456.nims"
+doAssert execCmd(fmt"{nim} check {file}") == 0
diff --git a/tests/misc/t20883.nim b/tests/misc/t20883.nim
new file mode 100644
index 000000000..92e7929f4
--- /dev/null
+++ b/tests/misc/t20883.nim
@@ -0,0 +1,13 @@
+discard """
+  action: reject
+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)) =
+  echo x
+
+foo[float]()
+foo()
diff --git a/tests/misc/t21109.nim b/tests/misc/t21109.nim
new file mode 100644
index 000000000..0f7980896
--- /dev/null
+++ b/tests/misc/t21109.nim
@@ -0,0 +1,13 @@
+discard """
+  action: reject
+  errormsg: "type expected"
+  file: "iterators.nim"
+"""
+
+
+template b(j: untyped) = j
+template m() = discard
+
+b:
+  for t, f in @[]:
+    m()
diff --git a/tests/misc/t21443.nim b/tests/misc/t21443.nim
new file mode 100644
index 000000000..70413c5b3
--- /dev/null
+++ b/tests/misc/t21443.nim
@@ -0,0 +1,6 @@
+import std/envvars
+
+# bug #19292
+putEnv("NimPutEnvTest", "test")
+# bug #21122
+doAssert getEnv("NimPutEnvTest") == "test"
diff --git a/tests/misc/t23240.nim b/tests/misc/t23240.nim
new file mode 100644
index 000000000..d5edcefe8
--- /dev/null
+++ b/tests/misc/t23240.nim
@@ -0,0 +1,6 @@
+discard """
+  cmd: "nim c foo/bar.nim"
+  action: "reject"
+  errormsg: "cannot open 'foo/'"
+  file: ""
+"""
diff --git a/tests/misc/t3482.nim b/tests/misc/t3482.nim
new file mode 100644
index 000000000..33b3b8f40
--- /dev/null
+++ b/tests/misc/t3482.nim
@@ -0,0 +1,15 @@
+discard """
+  action: reject
+  nimout: "t3482.nim(13, 8) Error: undeclared identifier: 'output'"
+"""
+# bug #3482 (correct behavior since 1.4.0, cgen error in 1.2.0)
+template foo*(body: typed) =
+  if true:
+    body
+
+proc test =
+  foo:
+    var output = ""
+  echo output.len
+
+test()
diff --git a/tests/misc/t3907.nim b/tests/misc/t3907.nim
new file mode 100644
index 000000000..45fc75e81
--- /dev/null
+++ b/tests/misc/t3907.nim
@@ -0,0 +1,10 @@
+import std/assertions
+
+let a = 0
+let b = if false: -1 else: a
+doAssert b == 0
+
+let c: range[0..high(int)] = 0
+let d = if false: -1 else: c
+
+doAssert d == 0
diff --git a/tests/misc/t5540.nim b/tests/misc/t5540.nim
new file mode 100644
index 000000000..6a19e70e1
--- /dev/null
+++ b/tests/misc/t5540.nim
@@ -0,0 +1,45 @@
+# bug #5540; works in 1.2.0
+# fails in 1.0 (Error: cannot generate VM code for)
+# fails in 0.18.0 (Error: type mismatch: got <type T>)
+
+block:
+  type
+    Fruit = object
+    Yellow = object
+      a: int
+  template getColor(x: typedesc[Fruit]): typedesc = Yellow
+  type
+    Banana[T] = object
+      b: T
+      a: getColor(Fruit)
+    Apple[T] = object
+      a: T
+      b: getColor(T)
+  block:
+    var x: Banana[int]
+    doAssert x.b == 0
+    doAssert x.a is Yellow
+  block:
+    var x: Apple[Fruit]
+    doAssert x.b is Yellow
+
+block:
+  type
+    Fruit = object
+    Yellow = object
+      a: int
+    
+  template getColor(x: typedesc[Fruit]): typedesc = Yellow
+
+  type
+    Banana[T] = object
+      b: T
+      a: getColor(Fruit)
+
+    Apple[T] = object
+      a: T
+      b: getColor(T)
+      
+  var x: Banana[int]
+  x.b = 13
+  x.a.a = 17
diff --git a/tests/misc/t6549.nim b/tests/misc/t6549.nim
new file mode 100644
index 000000000..1d7393318
--- /dev/null
+++ b/tests/misc/t6549.nim
@@ -0,0 +1,4 @@
+
+const l = $(range[low(uint64) .. high(uint64)])
+const r = "range 0..18446744073709551615(uint64)"
+doAssert l == r
diff --git a/tests/misc/t8404.nim b/tests/misc/t8404.nim
new file mode 100644
index 000000000..87991071c
--- /dev/null
+++ b/tests/misc/t8404.nim
@@ -0,0 +1,33 @@
+discard """
+  targets: "c cpp js"
+"""
+template main() =
+  block: # bug #8404
+    # can conv
+    template float2int(T) =
+      var a = -1.0
+      let b = T(a)
+      doAssert b < 0
+      let c = b + 1
+      doAssert c is T
+      doAssert c == 0
+
+    float2int(int8)
+    float2int(int16)
+    float2int(int32)
+    float2int(int64)
+
+  block:
+    # can handle middle conv
+    # `/` can trigger int to float
+    template float2int(T) =
+      let n = T(1 / 256)
+      doAssert n == 0
+
+    float2int(int8)
+    float2int(int16)
+    float2int(int32)
+    # float2int(int64)
+main()
+static:
+  main()
diff --git a/tests/misc/t8545.nim b/tests/misc/t8545.nim
new file mode 100644
index 000000000..48b886cb8
--- /dev/null
+++ b/tests/misc/t8545.nim
@@ -0,0 +1,24 @@
+discard """
+  # just tests that this doesn't crash the compiler
+  errormsg: "cannot instantiate: 'a:type'"
+"""
+
+# bug #8545
+
+template bar(a: static[bool]): untyped = int
+
+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
+
+  proc foo3(a: static[bool]): bar(cast[static[bool]](a)) = 1
+  doAssert foo3(true) == 1
+
+  proc foo4(a: static[bool]): bar(static(a)) = 1
+  doAssert foo4(true) == 1
+
+static: main()
+main()
diff --git a/tests/misc/t9039.nim b/tests/misc/t9039.nim
new file mode 100644
index 000000000..3271cd34e
--- /dev/null
+++ b/tests/misc/t9039.nim
@@ -0,0 +1,24 @@
+discard """
+  action: reject
+  nimout: '''
+t9039.nim(22, 22) Error: type mismatch: got <array[0..2, int], int, array[0..1, int]>
+but expression 'nesting + 1' is of type: int
+'''
+"""
+
+# bug #9039; this used to hang in 0.19.0
+
+
+
+
+
+# line 15
+func default(T: typedesc[array]): T = discard
+doAssert default(array[3, int]) == [0, 0, 0]
+func shapeBad*[T: not char](s: openArray[T], rank: static[int], nesting = 0, parent_shape = default(array[rank, int])): array[rank, int] =
+  result = parent_shape
+  result[nesting] = s.len
+  when (T is seq|array):
+    result = shapeBad(s[0], nesting + 1, result)
+let a1 = [1, 2, 3].shapeBad(rank = 1)
+let a2 = [[1, 2, 3], [4, 5, 6]].shapeBad(rank = 2)
diff --git a/tests/misc/t9091.nim b/tests/misc/t9091.nim
new file mode 100644
index 000000000..6e7a98ca5
--- /dev/null
+++ b/tests/misc/t9091.nim
@@ -0,0 +1,33 @@
+# bug #9091
+
+import streams
+
+block:
+  type Mine = ref object
+    a: int
+
+  proc write(io: Stream, t: Mine) =
+    io.write("sure")
+
+  let str = newStringStream()
+  let mi = new Mine
+
+  str.write(mi)
+  str.setPosition 0
+  doAssert str.readAll == "sure"
+
+block:
+  type
+    AObj = object
+      x: int
+
+  proc foo(a: int): string = ""
+
+  proc test(args: varargs[string, foo]) =
+    doAssert false
+
+  proc test(a: AObj) =
+    discard
+
+  let x = AObj()
+  test(x)
diff --git a/tests/misc/t9710.nim b/tests/misc/t9710.nim
new file mode 100644
index 000000000..c65cb7bf4
--- /dev/null
+++ b/tests/misc/t9710.nim
@@ -0,0 +1,6 @@
+discard """
+  matrix: "--debugger:native"
+"""
+# bug #9710
+for i in 1 || 200:
+  discard i
diff --git a/tests/misc/t99bott.nim b/tests/misc/t99bott.nim
new file mode 100644
index 000000000..f60023818
--- /dev/null
+++ b/tests/misc/t99bott.nim
@@ -0,0 +1,32 @@
+discard """
+  errormsg: "cannot evaluate at compile time: bn"
+  file: "t99bott.nim"
+  line: 26
+"""
+
+## 99 Bottles of Beer
+## http://www.99-bottles-of-beer.net/
+## Nim version
+
+## Author: Philippe Lhoste <PhiLho(a)GMX.net> http://Phi.Lho.free.fr
+# 2012-11-25
+# Loosely based on my old Lua version... Updated to current official lyrics.
+
+proc GetBottleNumber(n: int): string =
+  var bs: string
+  if n == 0:
+    bs = "No more bottles"
+  elif n == 1:
+    bs = "1 bottle"
+  else:
+    bs = $n & " bottles"
+  return bs & " of beer"
+
+for bn in countdown(99, 1):
+  const cur = GetBottleNumber(bn)
+  echo(cur, " on the wall, ", cur, ".")
+  echo("Take one down and pass it around, ", GetBottleNumber(bn-1),
+       " on the wall.\n")
+
+echo "No more bottles of beer on the wall, no more bottles of beer."
+echo "Go to the store and buy some more, 99 bottles of beer on the wall."
diff --git a/tests/tack.nim b/tests/misc/tack.nim
index 59535e547..458395ef6 100755..100644
--- a/tests/tack.nim
+++ b/tests/misc/tack.nim
@@ -1,15 +1,19 @@
-# the Ackermann function

-

-proc ack(x, y: int): int =

-  if x != 0:

-    if y != 0:

-      return ack(x-1, ack(x, y-1))

-    return ack(x-1, 1)

-  else:

-    return y + 1

-#  if x == 0: return y + 1

-#  elif y == 0: return ack(x-1, 1)

-#  else: return ack(x-1, ack(x, y-1))

-

-# echo(ack(0, 0))

-write(stdout, ack(3, 4)) #OUT 125

+discard """
+  output: "125"
+"""
+# the Ackermann function
+
+proc ack(x, y: int): int =
+  if x != 0:
+    if y != 0:
+      return ack(x-1, ack(x, y-1))
+    return ack(x-1, 1)
+  else:
+    return y + 1
+#  if x == 0: return y + 1
+#  elif y == 0: return ack(x-1, 1)
+#  else: return ack(x-1, ack(x, y-1))
+
+# echo(ack(0, 0))
+write(stdout, ack(3, 4)) #OUT 125
+write stdout, "\n"
diff --git a/tests/misc/taddr.nim b/tests/misc/taddr.nim
new file mode 100644
index 000000000..64f95c7e3
--- /dev/null
+++ b/tests/misc/taddr.nim
@@ -0,0 +1,295 @@
+discard """
+  targets: "c cpp js"
+  matrix: "; -d:release"
+"""
+
+type T = object
+  x: int
+  s: string
+
+var obj: T
+var fieldAddr = addr(obj.x)
+var objAddr = addr(obj)
+
+# Integer tests
+var field = fieldAddr[]
+doAssert field == 0
+
+var objDeref = objAddr[]
+doAssert objDeref.x == 0
+
+# Change value
+obj.x = 42
+
+doAssert field == 0
+doAssert objDeref.x == 0
+
+field = fieldAddr[]
+objDeref = objAddr[]
+
+doAssert field == 42
+doAssert objDeref.x == 42
+
+# String tests
+obj.s = "lorem ipsum dolor sit amet"
+when defined(gcArc) or defined(gcOrc):
+  prepareMutation(obj.s)
+
+
+var indexAddr = addr(obj.s[2])
+
+doAssert indexAddr[] == 'r'
+
+indexAddr[] = 'd'
+
+doAssert indexAddr[] == 'd'
+
+doAssert obj.s == "lodem ipsum dolor sit amet"
+
+# Bug #2148
+var x: array[2, int]
+var y = addr x[1]
+
+y[] = 12
+doAssert(x[1] == 12)
+
+type
+  Foo = object
+    bar: int
+
+var foo: array[2, Foo]
+var z = addr foo[1]
+
+z[].bar = 12345
+doAssert(foo[1].bar == 12345)
+
+var t : tuple[a, b: int]
+var pt = addr t[1]
+pt[] = 123
+doAssert(t.b == 123)
+
+#block: # Test "untyped" pointer.
+proc testPtr(p: pointer, a: int) =
+  doAssert(a == 5)
+  (cast[ptr int](p))[] = 124
+var i = 123
+testPtr(addr i, 5)
+doAssert(i == 124)
+
+var someGlobal = 5
+proc getSomeGlobalPtr(): ptr int = addr someGlobal
+let someGlobalPtr = getSomeGlobalPtr()
+doAssert(someGlobalPtr[] == 5)
+someGlobalPtr[] = 10
+doAssert(someGlobal == 10)
+
+block:
+  # bug #14576
+  # lots of these used to give: Error: internal error: genAddr: 2
+  proc byLent[T](a: T): lent T = a
+  proc byPtr[T](a: T): ptr T = a.addr
+
+  block:
+    let a = (10,11)
+    let (x,y) = byLent(a)
+    doAssert (x,y) == a
+
+  block: # (with -d:release) bug #14578
+    let a = 10
+    doAssert byLent(a) == 10
+    let a2 = byLent(a)
+    doAssert a2 == 10
+
+  block:
+    let a = [11,12]
+    doAssert byLent(a) == [11,12] # bug #15958
+    let a2 = (11,)
+    doAssert byLent(a2) == (11,)
+
+  block:
+    proc byLent2[T](a: seq[T]): lent T = a[1]
+    var a = @[20,21,22]
+    doAssert byLent2(a) == 21
+
+  block: # sanity checks
+    proc bar[T](a: var T): var T = a
+    var a = (10, 11)
+    let (k,v) = bar(a)
+    doAssert (k, v) == a
+    doAssert k == 10
+    bar(a)[0]+=100
+    doAssert a == (110, 11)
+    var a2 = 12
+    doAssert bar(a2) == a2
+    bar(a2).inc
+    doAssert a2 == 13
+
+  block: # pending bug #15959
+    when false:
+      proc byLent2[T](a: T): lent type(a[0]) = a[0]
+
+proc test14420() = # bug #14420
+  # s/proc/template/ would hit bug #16005
+  block:
+    type Foo = object
+      x: float
+
+    proc fn(a: var Foo): var float =
+      ## WAS: discard <- turn this into a comment (or a `discard`) and error disappears
+      # result = a.x # this works
+      a.x #  WAS: Error: limited VM support for 'addr'
+
+    proc fn2(a: var Foo): var float =
+      result = a.x # this works
+      a.x #  WAS: Error: limited VM support for 'addr'
+
+    var a = Foo()
+    discard fn(a)
+    discard fn2(a)
+
+  block:
+    proc byLent2[T](a: T): lent T =
+      runnableExamples: discard
+      a
+    proc byLent3[T](a: T): lent T =
+      runnableExamples: discard
+      result = a
+    var a = 10
+    let x3 = byLent3(a) # works
+    let x2 = byLent2(a) # WAS: Error: internal error: genAddr: nkStmtListExpr
+
+  block:
+    type MyOption[T] = object
+      case has: bool
+      of true:
+        value: T
+      of false:
+        discard
+    func some[T](val: T): MyOption[T] =
+      result = MyOption[T](has: true, value: val)
+    func get[T](opt: MyOption[T]): lent T =
+      doAssert opt.has
+      # result = opt.value # this was ok
+      opt.value # this had the bug
+    let x = some(10)
+    doAssert x.get() == 10
+
+template test14339() = # bug #14339
+  block:
+    type
+      Node = ref object
+        val: int
+    proc bar(c: Node): var int =
+      var n = c # was: Error: limited VM support for 'addr'
+      c.val
+    var a = Node()
+    discard a.bar()
+  block:
+    type
+      Node = ref object
+        val: int
+    proc bar(c: Node): var int =
+      var n = c
+      doAssert n.val == n[].val
+      n.val
+    var a = Node(val: 3)
+    a.bar() = 5
+    when nimvm:
+      doAssert a.val == 5
+    else:
+      when not defined(js): # pending bug #16003
+        doAssert a.val == 5
+
+template testStatic15464() = # bug #15464
+  proc access(s: var seq[char], i: int): var char = s[i]
+  proc access(s: var string, i: int): var char = s[i]
+  static:
+    var s = @['a', 'b', 'c']
+    access(s, 2) = 'C'
+    doAssert access(s, 2) == 'C'
+  static:
+    var s = "abc"
+    access(s, 2) = 'C'
+    doAssert access(s, 2) == 'C'
+
+proc test15464() = # bug #15464 (v2)
+  proc access(s: var seq[char], i: int): var char = s[i]
+  proc access(s: var string, i: int): var char = s[i]
+  block:
+    var s = @['a', 'b', 'c']
+    access(s, 2) = 'C'
+    doAssert access(s, 2) == 'C'
+  block:
+    var s = "abc"
+    access(s, 2) = 'C'
+    doAssert access(s, 2) == 'C'
+
+block: # bug #15939
+  block:
+    const foo = "foo"
+    proc proc1(s: var string) =
+      if s[^1] notin {'a'..'z'}:
+        s = ""
+    proc proc2(f: string): string =
+      result = f
+      proc1(result)
+    const bar = proc2(foo)
+    doAssert bar == "foo"
+
+template prepareMutationForOrc(x: string) =
+  when defined(gcArc) or defined(gcOrc):
+    when nimvm:
+      discard
+    else:
+      prepareMutation(x)
+
+proc test15939() = # bug #15939 (v2)
+  template fn(a) =
+    when typeof(a) is string:
+      prepareMutationForOrc(a)
+    let pa = a[0].addr
+    doAssert pa != nil
+    doAssert pa[] == 'a'
+    pa[] = 'x'
+    doAssert pa[] == 'x'
+    doAssert a == "xbc"
+    when not defined js: # otherwise overflows
+      let pa2 = cast[ptr char](cast[int](pa) + 1)
+      doAssert pa2[] == 'b'
+      pa2[] = 'B'
+      doAssert a == "xBc"
+
+  # mystring[ind].addr
+  var a = "abc"
+  fn(a)
+
+  # mycstring[ind].addr
+  template cstringTest =
+    var a2 = "abc"
+    prepareMutationForOrc(a2)
+    var b2 = a2.cstring
+    fn(b2)
+  when nimvm: cstringTest()
+  else: # can't take address of cstring element in js
+    when not defined(js): cstringTest()
+
+block: # bug #23499
+  template volatileStore[T](dest: ptr T, val: T) =
+    dest[] = val
+
+  proc foo =
+    var ctr = 0
+    volatileStore(addr ctr, 0)
+
+  foo()
+
+template main =
+  # xxx wrap all other tests here like that so they're also tested in VM
+  test14420()
+  test14339()
+  test15464()
+  test15939()
+
+testStatic15464()
+static: main()
+main()
diff --git a/tests/misc/tapp_lib_staticlib.nim b/tests/misc/tapp_lib_staticlib.nim
new file mode 100644
index 000000000..92c9acbc3
--- /dev/null
+++ b/tests/misc/tapp_lib_staticlib.nim
@@ -0,0 +1,27 @@
+discard """
+joinable: false
+"""
+
+# bug #16949
+
+when defined case1:
+  proc foo(): int {.exportc.} = 10
+elif defined case2:
+  proc foo(): int {.exportc, dynlib.} = 10
+elif defined caseMain:
+  proc foo(): int {.importc.}
+  doAssert foo() == 10
+else:
+  import stdtest/specialpaths
+  import std/[os, strformat, strutils, compilesettings]
+  proc runCmd(cmd: string) =
+    doAssert execShellCmd(cmd) == 0, $cmd
+  const
+    file = currentSourcePath
+    nim = getCurrentCompilerExe()
+    mode = querySetting(backend)
+  proc test(lib, options: string) =
+    runCmd fmt"{nim} {mode} -o:{lib} --nomain {options} -f {file}"
+    # runCmd fmt"{nim} r -b:{mode} --passl:{lib} -d:caseMain -f {file}" # pending https://github.com/nim-lang/Nim/pull/16945
+  test(buildDir / "libD20210205T172314.a", "--app:staticlib -d:nimLinkerWeakSymbols -d:case1")
+  test(buildDir / DynlibFormat % "D20210205T172720", "--app:lib -d:case2")
diff --git a/tests/misc/tbug1217bracketquotes.nim b/tests/misc/tbug1217bracketquotes.nim
new file mode 100644
index 000000000..90e67d45b
--- /dev/null
+++ b/tests/misc/tbug1217bracketquotes.nim
@@ -0,0 +1,14 @@
+discard """
+  output: "13{(.{}}{*4&*$**()&*@1235"
+"""
+
+type
+  Test = enum
+    `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`
+
+let `.}` = 1
+let `(}` = 2
+let `[` = 3
+let `]` = 5
+
+echo `1`, `3`, `{`, `(.`, `{}}{`, `*4&*$**()&*@`, `.}`, `(}`, `[`, `]`
diff --git a/tests/misc/tbug511622.nim b/tests/misc/tbug511622.nim
new file mode 100644
index 000000000..1af6380ed
--- /dev/null
+++ b/tests/misc/tbug511622.nim
@@ -0,0 +1,12 @@
+discard """
+  output: "3"
+"""
+import math
+
+proc FibonacciA(n: int): int64 =
+  var fn = float64(n)
+  var p: float64 = (1.0 + sqrt(5.0)) / 2.0
+  var q: float64 = 1.0 / p
+  return int64((pow(p, fn) + pow(q, fn)) / sqrt(5.0))
+
+echo FibonacciA(4) #OUT 3
diff --git a/tests/misc/tcast.nim b/tests/misc/tcast.nim
new file mode 100644
index 000000000..73196e76c
--- /dev/null
+++ b/tests/misc/tcast.nim
@@ -0,0 +1,108 @@
+discard """
+  output: '''
+Hello World
+Hello World
+Hello World'''
+  joinable: false
+"""
+type MyProc = proc() {.cdecl.}
+type MyProc2 = proc() {.nimcall.}
+type MyProc3 = proc() #{.closure.} is implicit
+
+proc testProc() {.exportc:"foo".} = echo "Hello World"
+
+template reject(x) = doAssert(not compiles(x))
+
+proc callPointer(p: pointer) =
+  # can cast to proc(){.cdecl.}
+  let ffunc0 = cast[MyProc](p)
+  # can cast to proc(){.nimcall.}
+  let ffunc1 = cast[MyProc2](p)
+  # cannot cast to proc(){.closure.}
+  reject: cast[MyProc3](p)
+
+  ffunc0()
+  ffunc1()
+
+    # bug #5901
+  proc foo() {.importc.}
+  (cast[proc(a: int) {.cdecl.}](foo))(5)
+
+callPointer(cast[pointer](testProc))
+
+reject: discard cast[enum](0)
+proc a = echo "hi"
+
+reject: discard cast[ptr](a)
+
+# bug #15623
+block:
+  if false:
+    let x = cast[ptr int](nil)
+    echo x[]
+
+block:
+  if false:
+    var x: ref int = nil
+    echo cast[ptr int](x)[]
+
+block:
+  doAssert cast[int](cast[ptr int](nil)) == 0
+
+block:
+  var x: ref int = nil
+  doAssert cast[int](cast[ptr int](x)) == 0
+
+block: # cast of nil
+  block:
+    static:
+      let a = cast[pointer](nil)
+      doAssert a.repr == "nil"
+
+  block:
+    static:
+      doAssert cast[ptr int](nil).repr == "nil"
+
+  block:
+    const str = cast[ptr int](nil)
+    static:
+      doAssert str.repr == "nil"
+
+  block:
+    static:
+      doAssert cast[ptr int](nil).repr == "nil"
+
+  block:
+    static:
+      doAssert cast[RootRef](nil).repr == "nil"
+
+  when false: # xxx bug #15730, not fixed yet
+    block:
+      static:
+        doAssert cast[cstring](nil).repr == "nil"
+
+template main() =
+  # xxx move all under here to get tested in VM
+  block: # cast of enum
+    type Koo = enum k1, k2
+    type Goo = enum g1, g2
+    type Boo = enum b1 = -1, b2, b3, b4
+    type Coo = enum c1 = -1i8, c2, c3, c4
+    when nimvm:
+      # xxx: Error: VM does not support 'cast' from tyEnum to tyEnum
+      discard
+    else:
+      doAssert cast[Koo](k2) == k2
+      doAssert cast[Goo](k2) == g2
+      doAssert cast[Goo](k2.ord) == g2
+
+      doAssert b3.ord == 1
+      doAssert cast[Koo](b3) == k2
+      doAssert cast[Boo](k2) == b3
+
+      doAssert c3.ord == 1
+      doAssert cast[Koo](c3) == k2
+      doAssert cast[Coo](k2) == c3
+
+static: main()
+main()
diff --git a/tests/misc/tcharinc.nim b/tests/misc/tcharinc.nim
new file mode 100644
index 000000000..1b5d19c18
--- /dev/null
+++ b/tests/misc/tcharinc.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "1"
+"""
+
+var c = '\0'
+while true:
+  if c == '\xFF': break
+  inc c
+
+echo "1"
diff --git a/tests/misc/tcmdline.nim b/tests/misc/tcmdline.nim
new file mode 100644
index 000000000..71e1301ca
--- /dev/null
+++ b/tests/misc/tcmdline.nim
@@ -0,0 +1,18 @@
+discard """
+outputsub: "Number of parameters: 0"
+joinable: false
+"""
+# Test the command line
+
+import
+  os, strutils
+
+var
+  i: int
+  params = paramCount()
+i = 0
+writeLine(stdout, "This exe: " & getAppFilename())
+writeLine(stdout, "Number of parameters: " & $params)
+while i <= params:
+  writeLine(stdout, paramStr(i))
+  i = i + 1
diff --git a/tests/misc/tconv.nim b/tests/misc/tconv.nim
new file mode 100644
index 000000000..90fae868b
--- /dev/null
+++ b/tests/misc/tconv.nim
@@ -0,0 +1,143 @@
+discard """
+  matrix: "--warningAsError:EnumConv --warningAsError:CStringConv"
+"""
+
+from std/enumutils import items  # missing from the example code
+from std/sequtils import toSeq
+
+template reject(x) =
+  static: doAssert(not compiles(x))
+template accept(x) =
+  static: doAssert(compiles(x))
+
+reject:
+    const x = int8(300)
+
+reject:
+    const x = int64(NaN)
+
+type
+    R = range[0..10]
+
+reject:
+    const x = R(11)
+
+reject:
+    const x = R(11.0)
+
+reject:
+    const x = R(NaN)
+
+reject:
+    const x = R(Inf)
+
+type
+    FloatRange = range[0'f..10'f]
+
+reject:
+    const x = FloatRange(-1'f)
+
+reject:
+    const x = FloatRange(-1)
+
+reject:
+    const x = FloatRange(NaN)
+
+block:
+    const x = float32(NaN)
+
+type E = enum a, b, c
+
+reject:
+    const e = E(4)
+
+block: # issue 3766
+
+  type R = range[0..2]
+
+  reject:
+    type
+      T[n: static[R]] = object
+      V = T[3.R]
+
+  reject:
+    proc r(x: static[R]) =
+      echo x
+    r 3.R
+
+
+block: # https://github.com/nim-lang/RFCs/issues/294
+  type Koo = enum k1, k2
+  type Goo = enum g1, g2
+
+  accept: Koo(k2)
+  accept: k2.Koo
+  accept: k2.int.Goo
+
+  reject: Goo(k2)
+  reject: k2.Goo
+  reject: k2.string
+
+  {.push warningAsError[EnumConv]:off.}
+  discard Goo(k2)
+  accept: Goo(k2)
+  accept: k2.Goo
+  reject: k2.string
+  {.pop.}
+
+  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 =
+    var x = newString(109*1024*1024)
+    x[0] = c
+    x
+
+{.push warning[AnyEnumConv]:on, warningAsError[AnyEnumConv]:on.}
+
+reject:
+  type
+    Foo = enum
+      one
+      three
+
+  var va = 2
+  var vb = va.Foo
+
+{.pop.}
+
+{.push warningAsError[HoleEnumConv]:on.}
+
+reject:
+  # bug #12815
+  type
+    Hole = enum
+      one = 1
+      three = 3
+
+  var va = 2
+  var vb = va.Hole
+
+block: # bug #22844
+  type
+    A = enum
+      a0 = 2
+      a1 = 4
+      a2
+    B[T] = enum
+      b0 = 2
+      b1 = 4
+
+  doAssert A.toSeq == [a0, a1, a2]
+  doAssert B[float].toSeq == [B[float].b0, B[float].b1]
+
+{.pop.}
diff --git a/tests/misc/tcsharpusingstatement.nim b/tests/misc/tcsharpusingstatement.nim
new file mode 100644
index 000000000..1ce553895
--- /dev/null
+++ b/tests/misc/tcsharpusingstatement.nim
@@ -0,0 +1,76 @@
+discard """
+  output: "Using test.Closing test."
+"""
+
+import
+  macros
+
+# This macro mimics the using statement from C#
+#
+# It's kept only as a test for the macro system
+# Nim's destructors offer a mechanism for automatic
+# disposal of resources.
+#
+macro autoClose(args: varargs[untyped]): untyped =
+  let e = callsite()
+  if e.len != 3:
+    error "Using statement: unexpected number of arguments. Got " &
+      $e.len & ", expected: 1 or more variable assignments and a block"
+
+  var args = e
+  var body = e[2]
+
+  var
+    variables : seq[NimNode]
+    closingCalls : seq[NimNode]
+
+  newSeq(variables, 0)
+  newSeq(closingCalls, 0)
+
+  for i in countup(1, args.len-2):
+    if args[i].kind == nnkExprEqExpr:
+      var varName = args[i][0]
+      var varValue = args[i][1]
+
+      var varAssignment = newNimNode(nnkIdentDefs)
+      varAssignment.add(varName)
+      varAssignment.add(newNimNode(nnkEmpty)) # empty means no type
+      varAssignment.add(varValue)
+      variables.add(varAssignment)
+
+      closingCalls.add(newCall(newIdentNode("close"), varName))
+    else:
+      error "Using statement: Unexpected expression. Got " &
+        $args[i].kind & " instead of assignment."
+
+  var varSection = newNimNode(nnkVarSection)
+  varSection.add(variables)
+
+  var finallyBlock = newNimNode(nnkStmtList)
+  finallyBlock.add(closingCalls)
+
+  result = quote do:
+    block:
+      `varSection`
+      try:
+        `body`
+      finally:
+        `finallyBlock`
+
+type
+  TResource* = object
+    field*: string
+
+proc openResource(param: string): TResource =
+  result.field = param
+
+proc close(r: var TResource) =
+  write(stdout, "Closing " & r.field & ".")
+
+proc use(r: var TResource) =
+  write(stdout, "Using " & r.field & ".")
+
+autoClose(r = openResource("test")):
+  use r
+
+write stdout, "\n"
diff --git a/tests/misc/tdangerisrelease.nim b/tests/misc/tdangerisrelease.nim
new file mode 100644
index 000000000..e1854dca5
--- /dev/null
+++ b/tests/misc/tdangerisrelease.nim
@@ -0,0 +1,14 @@
+discard """
+  cmd: "nim c $options -r $file"
+  matrix: "-d:danger; -d:release"
+  output: '''
+a
+b
+c
+'''
+"""
+
+echo "a"
+when defined(release):
+  echo "b"
+echo "c"
diff --git a/tests/misc/tdefine.nim b/tests/misc/tdefine.nim
new file mode 100644
index 000000000..f3fa4711f
--- /dev/null
+++ b/tests/misc/tdefine.nim
@@ -0,0 +1,77 @@
+discard """
+joinable: false
+cmd: "nim c $options -d:booldef -d:booldef2=false -d:intdef=2 -d:strdef=foobar -d:namespaced.define=false -d:double.namespaced.define -r $file"
+matrix: "; -d:useGenericDefine"
+"""
+
+when defined(useGenericDefine):
+  {.pragma: booldefine2, define.}
+  {.pragma: intdefine2, define.}
+  {.pragma: strdefine2, define.}
+else:
+  
+  {.pragma: booldefine2, booldefine.}
+  {.pragma: intdefine2, intdefine.}
+  {.pragma: strdefine2, strdefine.}
+
+const booldef {.booldefine2.} = false
+const booldef2 {.booldefine2.} = true
+const intdef {.intdefine2.} = 0
+const strdef {.strdefine2.} = ""
+
+doAssert defined(booldef)
+doAssert defined(booldef2)
+doAssert defined(intdef)
+doAssert defined(strdef)
+doAssert booldef
+doAssert not booldef2
+doAssert intdef == 2
+doAssert strdef == "foobar"
+
+when defined(useGenericDefine):
+  block:
+    const uintdef {.define: "intdef".}: uint = 17
+    doAssert intdef == int(uintdef)
+    const cstrdef {.define: "strdef".}: cstring = "not strdef"
+    doAssert $cstrdef == strdef
+    type FooBar = enum foo, bar, foobar
+    const enumdef {.define: "strdef".} = foo
+    doAssert $enumdef == strdef
+    doAssert enumdef == foobar
+
+# Intentionally not defined from command line
+const booldef3 {.booldefine2.} = true
+const intdef2 {.intdefine2.} = 1
+const strdef2 {.strdefine2.} = "abc"
+type T = object
+  when booldef3:
+    field1: int
+  when intdef2 == 1:
+    field2: int
+  when strdef2 == "abc":
+    field3: int
+
+doAssert not defined(booldef3)
+doAssert not defined(intdef2)
+doAssert not defined(strdef2)
+discard T(field1: 1, field2: 2, field3: 3)
+
+doAssert defined(namespaced.define)
+const `namespaced.define` {.booldefine2.} = true
+doAssert not `namespaced.define`
+when defined(useGenericDefine):
+  const aliasToNamespacedDefine {.define: "namespaced.define".} = not `namespaced.define`
+else:
+  const aliasToNamespacedDefine {.booldefine: "namespaced.define".} = not `namespaced.define`
+doAssert aliasToNamespacedDefine == `namespaced.define`
+
+doAssert defined(double.namespaced.define)
+const `double.namespaced.define` {.booldefine2.} = false
+doAssert `double.namespaced.define`
+when defined(useGenericDefine):
+  const aliasToDoubleNamespacedDefine {.define: "double.namespaced.define".} = not `double.namespaced.define`
+else:
+  const aliasToDoubleNamespacedDefine {.booldefine: "double.namespaced.define".} = not `double.namespaced.define`
+doAssert aliasToDoubleNamespacedDefine == `double.namespaced.define`
+
+doAssert not defined(namespaced.butnotdefined)
diff --git a/tests/misc/tdllvar.nim b/tests/misc/tdllvar.nim
new file mode 100644
index 000000000..68029ddf4
--- /dev/null
+++ b/tests/misc/tdllvar.nim
@@ -0,0 +1,18 @@
+discard """
+disabled: true
+"""
+
+import os
+
+proc getDllName: string =
+  result = "mylib.dll"
+  if fileExists(result): return
+  result = "mylib2.dll"
+  if fileExists(result): return
+  quit("could not load dynamic library")
+
+proc myImport(s: cstring) {.cdecl, importc, dynlib: getDllName().}
+proc myImport2(s: int) {.cdecl, importc, dynlib: getDllName().}
+
+myImport("test2")
+myImport2(12)
diff --git a/tests/misc/teventemitter.nim b/tests/misc/teventemitter.nim
new file mode 100644
index 000000000..7da1a2522
--- /dev/null
+++ b/tests/misc/teventemitter.nim
@@ -0,0 +1,32 @@
+discard """
+  output: "pie"
+"""
+
+import tables, lists
+
+type
+  EventArgs = object of RootObj
+  EventEmitter = object of RootObj
+    events*: Table[string, DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]
+
+proc emit*(emitter: EventEmitter, event: string, args: EventArgs) =
+  for fn in nodes(emitter.events[event]):
+    fn.value(args) #call function with args.
+
+proc on*(emitter: var EventEmitter, event: string,
+         fn: proc(e: EventArgs) {.nimcall.}) =
+  if not hasKey(emitter.events, event):
+    var list: DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]
+    add(emitter.events, event, list) #if not, add it.
+  append(emitter.events[event], fn)
+
+proc initEmitter(emitter: var EventEmitter) =
+  emitter.events = initTable[string,
+    DoublyLinkedList[proc(e: EventArgs) {.nimcall.}]]()
+
+var
+  ee: EventEmitter
+  args: EventArgs
+initEmitter(ee)
+ee.on("print", proc(e: EventArgs) = echo("pie"))
+ee.emit("print", args)
diff --git a/tests/misc/tfib.nim b/tests/misc/tfib.nim
new file mode 100644
index 000000000..34fe0dcf9
--- /dev/null
+++ b/tests/misc/tfib.nim
@@ -0,0 +1,11 @@
+
+iterator fibonacci(): int =
+  var a = 0
+  var b = 1
+  while true:
+    yield a
+    var c = b
+    b = a
+    a = a + c
+
+
diff --git a/tests/misc/tfilter.nim b/tests/misc/tfilter.nim
new file mode 100644
index 000000000..5846d0efb
--- /dev/null
+++ b/tests/misc/tfilter.nim
@@ -0,0 +1,41 @@
+discard """
+  output: "02468101214161820\n15"
+"""
+
+proc filter[T](list: seq[T], f: proc (item: T): bool {.closure.}): seq[T] =
+  result = @[]
+  for i in items(list):
+    if f(i):
+      result.add(i)
+
+let nums = @[0, 1, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
+
+when true:
+  let nums2 = filter(nums,
+               (proc (item: int): bool =
+                 result = (item mod 2) == 0)
+               )
+
+proc outer =
+  # lets use a proper closure this time:
+  var modulo = 2
+  let nums2 = filter(nums,
+               (proc (item: int): bool = result = (item mod modulo) == 0)
+               )
+
+  for n in nums2: stdout.write(n)
+  stdout.write("\n")
+
+outer()
+
+import math
+proc compose[T](f1, f2: proc (x: T): T {.closure.}): proc (x: T): T {.closure.} =
+  result = (proc (x: T): T =
+             result = f1(f2(x)))
+
+
+proc add5(x: int): int = result = x + 5
+
+var test = compose(add5, add5)
+echo test(5)
+
diff --git a/tests/thallo.nim b/tests/misc/thallo.nim
index 86aa89f0a..8dac56023 100755..100644
--- a/tests/thallo.nim
+++ b/tests/misc/thallo.nim
@@ -1,4 +1,8 @@
-# Hallo
+discard """
+action: compile
+"""
+
+# noted this seems to be an old test file designed for manual testing.
 
 import
   os, strutils, macros
@@ -7,7 +11,7 @@ type
   TMyEnum = enum
     meA, meB, meC, meD
 
-when isMainModule:
+when true:
   {.hint: "this is the main file".}
 
 proc fac[T](x: T): T =
@@ -15,34 +19,35 @@ proc fac[T](x: T): T =
   if x <= 1: return 1
   else: return x.`*`(fac(x-1))
 
-macro macrotest(n: expr): stmt =
+macro macrotest(n: varargs[untyped]): untyped =
+  let n = callsite()
   expectKind(n, nnkCall)
   expectMinLen(n, 2)
   result = newNimNode(nnkStmtList, n)
   for i in 2..n.len-1:
     result.add(newCall("write", n[1], n[i]))
-  result.add(newCall("writeln", n[1], newStrLitNode("")))
+  result.add(newCall("writeLine", n[1], newStrLitNode("")))
 
-macro debug(n: expr): stmt =
+macro debug(n: untyped): untyped =
+  let n = callsite()
   result = newNimNode(nnkStmtList, n)
   for i in 1..n.len-1:
     result.add(newCall("write", newIdentNode("stdout"), toStrLit(n[i])))
     result.add(newCall("write", newIdentNode("stdout"), newStrLitNode(": ")))
-    result.add(newCall("writeln", newIdentNode("stdout"), n[i]))
+    result.add(newCall("writeLine", newIdentNode("stdout"), n[i]))
 
 macrotest(stdout, "finally", 4, 5, "variable", "argument lists")
 macrotest(stdout)
 
 #GC_disable()
 
-echo("This was compiled by Nimrod version " & system.nimrodVersion)
-writeln(stdout, "Hallo", " World", "!")
+echo("This was compiled by Nim version " & system.NimVersion)
+writeLine(stdout, "Hello", " World", "!")
 
 echo(["a", "b", "c", "d"].len)
 for x in items(["What's", "your", "name", "?", ]):
   echo(x)
 var `name` = readLine(stdin)
-{.breakpoint.}
 echo("Hi " & thallo.name & "!\n")
 debug(name)
 
@@ -51,8 +56,8 @@ var testseq: seq[string] = @[
 ]
 echo(repr(testseq))
 
-var dummy = "hallo"
-echo(copy(dummy, 2, 3))
+var dummy = "hello"
+echo(substr(dummy, 2, 3))
 
 echo($meC)
 
@@ -60,12 +65,16 @@ echo($meC)
 for x, y in items([(1, 2), (3, 4), (6, 1), (5, 2)]):
   echo x
   echo y
-  
-# test constant evaluation: 
-const 
+
+proc simpleConst(): int = return 34
+
+# test constant evaluation:
+const
+  constEval3 = simpleConst()
   constEval = "abc".contains('b')
   constEval2 = fac(7)
 
+echo(constEval3)
 echo(constEval)
 echo(constEval2)
 echo(1.`+`(2))
@@ -74,6 +83,5 @@ for i in 2..6:
   for j in countdown(i+4, 2):
     echo(fac(i * j))
 
-when isMainModule:
+when true:
   {.hint: "this is the main file".}
-
diff --git a/tests/misc/theaproots.nim b/tests/misc/theaproots.nim
new file mode 100644
index 000000000..2dd345254
--- /dev/null
+++ b/tests/misc/theaproots.nim
@@ -0,0 +1,75 @@
+discard """
+action: compile
+"""
+
+type
+  Bar = object
+    x: int
+
+  Foo = object
+    rheap: ref Bar
+    rmaybe: ref Bar
+    rstack: ref Bar
+    list: seq[ref Bar]
+    listarr: array[0..5, ref Bar]
+    nestedtup: Tup
+    inner: TInner
+    inref: ref TInner
+
+  TInner = object
+    inref: ref Bar
+
+  Tup = tuple
+    tupbar: ref Bar
+    inner: TInner
+
+proc acc(x: var Foo): var ref Bar =
+  result = x.rheap
+
+proc test(maybeFoo: var Foo,
+          maybeSeq: var seq[ref Bar],
+          bars: var openArray[ref Bar],
+          maybeTup: var Tup) =
+  var bb: ref Bar
+  maybeFoo.rmaybe = bb
+  maybeFoo.list[3] = bb
+  maybeFoo.listarr[3] = bb
+  acc(maybeFoo) = bb
+
+  var localFoo: Foo
+  localFoo.rstack = bb
+  localFoo.list[3] = bb
+  localFoo.listarr[3] = bb
+  acc(localFoo) = bb
+
+  var heapFoo: ref Foo
+  heapFoo.rheap = bb
+  heapFoo.list[3] = bb
+  heapFoo.listarr[3] = bb
+  acc(heapFoo[]) = bb
+
+  heapFoo.nestedtup.tupbar = bb
+  heapFoo.nestedtup.inner.inref = bb
+  heapFoo.inner.inref = bb
+  heapFoo.inref.inref = bb
+
+  var locseq: seq[ref Bar]
+  locseq[3] = bb
+
+  var locarr: array[0..4, ref Bar]
+  locarr[3] = bb
+
+  maybeSeq[3] = bb
+
+  bars[3] = bb
+
+  maybeTup[0] = bb
+
+var
+  ff: ref Foo
+  tt: Tup
+  gseq: seq[ref Bar]
+
+new(ff)
+
+test(ff[], gseq, gseq, tt)
diff --git a/tests/misc/tinit.nim b/tests/misc/tinit.nim
new file mode 100644
index 000000000..207cb17e8
--- /dev/null
+++ b/tests/misc/tinit.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "Hello from module! Hello from main module!"
+"""
+# Test the new init section in modules
+
+import minit
+
+write(stdout, "Hello from main module!\n")
+#OUT Hello from module! Hello from main module!
diff --git a/tests/tinout.nim b/tests/misc/tinout.nim
index b4fe2fb10..bae0fb185 100755..100644
--- a/tests/tinout.nim
+++ b/tests/misc/tinout.nim
@@ -1,9 +1,14 @@
-# Test in out checking for parameters

-

-proc abc(x: var int) =

-    x = 0

-

-proc b() =

-    abc(3) #ERROR

-

-b()

+discard """
+  errormsg: "type mismatch: got <int literal(3)>"
+  file: "tinout.nim"
+  line: 12
+"""
+# Test in out checking for parameters
+
+proc abc(x: var int) =
+    x = 0
+
+proc b() =
+    abc(3) #ERROR
+
+b()
diff --git a/tests/misc/tinvalidnewseq.nim b/tests/misc/tinvalidnewseq.nim
new file mode 100644
index 000000000..7a95db020
--- /dev/null
+++ b/tests/misc/tinvalidnewseq.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "type mismatch: got <array[0..6, string], int literal(7)>"
+  file: "tinvalidnewseq.nim"
+  line: 15
+"""
+import re, strutils
+
+type
+  TURL = tuple[protocol, subdomain, domain, port: string, path: seq[string]]
+
+proc parseURL(url: string): TURL =
+  #([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?
+  var pattern: string = r"([a-zA-Z]+://)?(\w+?\.)?(\w+)(\.\w+)(:[0-9]+)?(/.+)?"
+  var m: array[0..6, string] #Array with the matches
+  newSeq(m, 7) #ERROR
+  discard re.match(url, re(pattern), m)
+
+  result = (protocol: m[1], subdomain: m[2], domain: m[3] & m[4],
+            port: m[5], path: m[6].split('/'))
+
+var r: TUrl
+
+r = parseUrl(r"http://google.com/search?var=bleahdhsad")
+echo(r.domain)
diff --git a/tests/misc/tissue710.nim b/tests/misc/tissue710.nim
new file mode 100644
index 000000000..ec125b840
--- /dev/null
+++ b/tests/misc/tissue710.nim
@@ -0,0 +1,10 @@
+discard """
+  errorMsg: "attempting to call routine: '||'"
+  file: "tissue710.nim"
+  line: 8
+"""
+var sum = 0
+for x in 3..1000:
+  if (x mod 3 == 0) || (x mod 5 == 0):
+    sum += x
+echo(sum)
diff --git a/tests/misc/tjoinable.nim b/tests/misc/tjoinable.nim
new file mode 100644
index 000000000..f23fca0d4
--- /dev/null
+++ b/tests/misc/tjoinable.nim
@@ -0,0 +1,3 @@
+# checks that megatest allows duplicate names, see also `tests/testament/tjoinable.nim`
+doAssert defined(testing)
+doAssert defined(nimMegatest)
diff --git a/tests/misc/tlastmod.nim b/tests/misc/tlastmod.nim
new file mode 100644
index 000000000..1cc1d4bd9
--- /dev/null
+++ b/tests/misc/tlastmod.nim
@@ -0,0 +1,25 @@
+discard """
+outputsub: "is newer than"
+"""
+# test the new LastModificationTime() proc
+
+let
+  file1 = "tests/testdata/data.csv"
+  file2 = "tests/testdata/doc1.xml"
+
+import
+  os, times, strutils
+
+proc main() =
+  var
+    a, b: Time
+  a = getLastModificationTime(file1)
+  b = getLastModificationTime(file2)
+  writeLine(stdout, $a)
+  writeLine(stdout, $b)
+  if a < b:
+    write(stdout, "$2 is newer than $1\n" % [file1, file2])
+  else:
+    write(stdout, "$1 is newer than $2\n" % [file1, file2])
+
+main()
diff --git a/tests/tloops.nim b/tests/misc/tloops.nim
index 3d03256ad..61e0baf10 100755..100644
--- a/tests/tloops.nim
+++ b/tests/misc/tloops.nim
@@ -1,64 +1,93 @@
-# Test nested loops and some other things

-

-proc andTest() =

-  var a = 0 == 5 and 6 == 6

-

-proc incx(x: var int) = # is built-in proc

-  x = x + 1

-

-proc decx(x: var int) =

-  x = x - 1

-

-proc First(y: var int) =

-  var x: int

-  i_ncx(x)

-  if x == 10:

-    y = 0

-  else:

-    if x == 0:

-      incx(x)

-    else:

-      x=11

-

-proc TestLoops() =

-  var i, j: int

-  while i >= 0:

-    if i mod 3 == 0:

-      break

-    i = i + 1

-    while j == 13:

-      j = 13

-      break

-    break

-

-  while True:

-    break

-

-

-proc Foo(n: int): int =

-    var

-        a, old: int

-        b, c: bool

-    F_irst(a)

-    if a == 10:

-        a = 30

-    elif a == 11:

-        a = 22

-    elif a == 12:

-        a = 23

-    elif b:

-        old = 12

-    else:

-        a = 40

-

-    #

-    b = false or 2 == 0 and 3 == 9

-    a = 0 + 3 * 5 + 6 + 7 + +8 # 36

-    while b:

-        a = a + 3

-    a = a + 5

-    write(stdout, "Hallo!")

-

-

-# We should come till here :-)

-discard Foo(345)

+discard """
+output: '''
+Hello!(x: 1, y: 2, z: 3)
+(x: 1.0, y: 2.0)
+'''
+"""
+
+# Test nested loops and some other things
+
+proc andTest() =
+  var a = 0 == 5 and 6 == 6
+
+proc incx(x: var int) = # is built-in proc
+  x = x + 1
+
+proc decx(x: var int) =
+  x = x - 1
+
+proc First(y: var int) =
+  var x: int
+  i_ncx(x)
+  if x == 10:
+    y = 0
+  else:
+    if x == 0:
+      incx(x)
+    else:
+      x=11
+
+proc TestLoops() =
+  var i, j: int
+  while i >= 0:
+    if i mod 3 == 0:
+      break
+    i = i + 1
+    while j == 13:
+      j = 13
+      break
+    break
+
+  while true:
+    break
+
+
+proc Foo(n: int): int =
+    var
+        a, old: int
+        b, c: bool
+    F_irst(a)
+    if a == 10:
+        a = 30
+    elif a == 11:
+        a = 22
+    elif a == 12:
+        a = 23
+    elif b:
+        old = 12
+    else:
+        a = 40
+
+    #
+    b = false or 2 == 0 and 3 == 9
+    a = 0 + 3 * 5 + 6 + 7 + +8 # 36
+    while b:
+        a = a + 3
+    a = a + 5
+    write(stdout, "Hello!")
+
+
+# We should come till here :-)
+discard Foo(345)
+
+# test the new type symbol lookup feature:
+
+type
+  MyType[T] = tuple[
+    x, y, z: T]
+  MyType2 = tuple[x, y: float]
+
+proc main[T]() =
+  var myType: MyType[T]
+  var b: MyType[T]
+  b = (1, 2, 3)
+  myType = b
+  echo myType
+
+  var myType2: MyType2
+  var c: MyType2
+  c = (1.0, 2.0)
+  myType2 = c
+  echo myType2
+
+main[int]()
diff --git a/tests/misc/tmemoization.nim b/tests/misc/tmemoization.nim
new file mode 100644
index 000000000..c65692608
--- /dev/null
+++ b/tests/misc/tmemoization.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout:    "test 1\ntest 2\ntest 3"
+  output: "TEST 1\nTEST 2\nTEST 3"
+"""
+
+import strutils
+
+proc foo(s: static[string]): string =
+  static: echo s
+
+  const R = s.toUpperAscii
+  return R
+
+echo foo("test 1")
+echo foo("test 2")
+echo foo("test " & $3)
+
diff --git a/tests/misc/tmissingnilcheck.nim b/tests/misc/tmissingnilcheck.nim
new file mode 100644
index 000000000..461fb18f4
--- /dev/null
+++ b/tests/misc/tmissingnilcheck.nim
@@ -0,0 +1,20 @@
+discard """
+  disabled: true
+"""
+
+type
+  PFutureBase = ref object
+    callback: proc () {.closure.}
+
+proc newConnection =
+  iterator newConnectionIter(): PFutureBase {.closure.} =
+    discard
+  var newConnectionIterVar = newConnectionIter
+  var first = newConnectionIterVar()
+
+  proc cb {.closure.} =
+    discard
+
+  first.callback = cb
+
+newConnection()
diff --git a/tests/misc/tmodulea.nim b/tests/misc/tmodulea.nim
new file mode 100644
index 000000000..5aeb1824b
--- /dev/null
+++ b/tests/misc/tmodulea.nim
@@ -0,0 +1,3 @@
+from modulea import modulea
+
+#bug #6731
diff --git a/tests/misc/tnoforward.nim b/tests/misc/tnoforward.nim
new file mode 100644
index 000000000..b6a71897a
--- /dev/null
+++ b/tests/misc/tnoforward.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "10"
+"""
+
+# {. noforward: on .}
+{.experimental: "codeReordering".}
+
+proc foo(x: int) =
+  bar x
+
+proc bar(x: int) =
+  echo x
+
+foo(10)
+
diff --git a/tests/misc/tnolen.nim b/tests/misc/tnolen.nim
new file mode 100644
index 000000000..e0e8025d4
--- /dev/null
+++ b/tests/misc/tnolen.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <int literal(3)>"
+  line: 8
+"""
+
+# please finally disallow Len(3)
+
+echo len(3)
diff --git a/tests/tparedef.nim b/tests/misc/tparedef.nim
index dedebf6b7..83c2651ff 100755..100644
--- a/tests/tparedef.nim
+++ b/tests/misc/tparedef.nim
@@ -1,4 +1,4 @@
-# This test is now superfluous:

-

-proc a(a: int) = 

-  return

+# This test is now superfluous:
+
+proc a(a: int) =
+  return
diff --git a/tests/misc/tparsecombnum.nim b/tests/misc/tparsecombnum.nim
new file mode 100644
index 000000000..6fe539813
--- /dev/null
+++ b/tests/misc/tparsecombnum.nim
@@ -0,0 +1,55 @@
+import parsecomb
+
+discard """
+  output: "-289096"
+"""
+
+type Num = int
+
+# forward stuff
+var exp3: Parser[string, Num]
+var exp = lazy(proc(): Parser[string, Num] = exp3)
+
+var digit = (proc(): Parser[string, Num] =
+  result = tok("0").then(unit[string, Num](Num(0)))
+  for n in 1..9:
+    result = result + tok($n).then(unit[string, Num](Num(n)))
+)()
+
+var num = repeat1(digit).map(proc(ds: seq[Num]): Num =
+  result = 0
+  for d in ds:
+    result = result*10 + d)
+
+type Op = proc(a, b: Num): Num
+
+var plusOp = tok("+").then(unit[string, Op](proc(a, b: Num): Num = a + b))
+var minusOp = tok("-").then(unit[string, Op](proc(a, b: Num): Num = a - b))
+var timesOp = tok("*").then(unit[string, Op](proc(a, b: Num): Num = a*b))
+var divideOp = tok("/").then(unit[string, Op](proc(a, b: Num): Num = a div b))
+
+var paren = (tok("(") * exp * tok(")")).map(proc(ler: ((string, Num), string)): Num =
+  var (le, r) = ler
+  var (l, e) = le
+  e)
+
+proc foldOp(a: Num, ob: (Op, Num)): Num =
+  var (o, b) = ob
+  o(a, b)
+
+var exp0 = paren + num
+var exp1 = exp0.leftRec((timesOp + divideOp)*exp0, foldOp)
+var exp2 = exp1.leftRec((plusOp + minusOp)*exp1, foldOp)
+exp3 = exp2
+
+proc strsplit(s: string): seq[string] =
+  result = @[]
+  for i in 0 .. s.len - 1:
+    result.add($s[i])
+
+var r = exp.run("523-(1243+411/744*1642/1323)*233".strsplit)
+case r.kind:
+of rkSuccess:
+  echo r.output
+of rkFailure:
+  echo "failed"
diff --git a/tests/misc/tparseopt.nim b/tests/misc/tparseopt.nim
new file mode 100644
index 000000000..47be05bac
--- /dev/null
+++ b/tests/misc/tparseopt.nim
@@ -0,0 +1,156 @@
+discard """
+  output: '''
+parseopt
+first round
+kind: cmdLongOption	key:val  --  left:
+second round
+kind: cmdLongOption	key:val  --  left:
+kind: cmdLongOption	key:val  --  debug:3
+kind: cmdShortOption	key:val  --  l:4
+kind: cmdShortOption	key:val  --  r:2
+cmdLongOption foo
+cmdLongOption path
+parseoptNoVal
+kind: cmdLongOption	key:val  --  left:
+kind: cmdLongOption	key:val  --  debug:3
+kind: cmdShortOption	key:val  --  l:
+kind: cmdShortOption	key:val  --  r:2
+kind: cmdLongOption	key:val  --  debug:2
+kind: cmdLongOption	key:val  --  debug:1
+kind: cmdShortOption	key:val  --  r:1
+kind: cmdShortOption	key:val  --  r:0
+kind: cmdShortOption	key:val  --  l:
+kind: cmdShortOption	key:val  --  r:4
+kind: cmdLongOption	key:val  --  debug:
+cmdShortOption key: v value: ''
+cmdArgument key: ABC value: ''
+cmdShortOption key: v value: 'ABC'
+cmdShortOption key: v value: ''
+cmdArgument key: ABC value: ''
+cmdShortOption key: v value: ''
+cmdArgument key: ABC value: ''
+cmdShortOption key: j value: '4'
+cmdArgument key: ok value: ''
+'''
+joinable: false
+"""
+
+when defined(testament_tparseopt):
+  import os
+  proc main() =
+    let args = commandLineParams()
+    echo args
+    for i, ai in args:
+      echo "arg ", i, " ai.len:", ai.len, " :{", ai, "}"
+  main()
+else:
+  from parseopt import nil
+
+  block:
+    echo "parseopt"
+    for kind, key, val in parseopt.getopt():
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+    # pass custom cmdline arguments
+    echo "first round"
+    var argv = "--left --debug:3 -l=4 -r:2"
+    var p = parseopt.initOptParser(argv)
+    for kind, key, val in parseopt.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+      break
+    # reset getopt iterator and check arguments are returned correctly.
+    echo "second round"
+    for kind, key, val in parseopt.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+    # bug #9619
+    var x = parseopt.initOptParser(@["--foo:", "--path"],
+        allowWhitespaceAfterColon = false)
+    for kind, key, val in parseopt.getopt(x):
+      echo kind, " ", key
+
+  block:
+    echo "parseoptNoVal"
+    # test NoVal mode with custom cmdline arguments
+    var argv = "--left --debug:3 -l -r:2 --debug 2 --debug=1 -r1 -r=0 -lr4 --debug:"
+    var p = parseopt.initOptParser(argv,
+                                    shortNoVal = {'l'}, longNoVal = @["left"])
+    for kind, key, val in parseopt.getopt(p):
+      echo "kind: ", kind, "\tkey:val  --  ", key, ":", val
+
+  import osproc, os, strutils
+  from stdtest/specialpaths import buildDir
+  import stdtest/unittest_light
+
+  block: # fix #9951
+    template runTest(parseoptCustom) =
+      var p = parseoptCustom.initOptParser(@["echo \"quoted\""])
+      let expected = when defined(windows):
+        """"echo \"quoted\"""""
+      else:
+        """'echo "quoted"'"""
+      assertEquals parseoptCustom.cmdLineRest(p), expected
+
+      doAssert "a5'b" == "a5\'b"
+
+      let args = @["a1b", "a2 b", "", "a4\"b", "a5'b", r"a6\b", "a7\'b"]
+      var p2 = parseoptCustom.initOptParser(args)
+      let expected2 = when defined(windows):
+        """a1b "a2 b" "" a4\"b a5'b a6\b a7'b"""
+      else:
+        """a1b 'a2 b' '' 'a4"b' 'a5'"'"'b' 'a6\b' 'a7'"'"'b'"""
+      doAssert "a5'b" == "a5\'b"
+      assertEquals parseoptCustom.cmdLineRest(p2), expected2
+    runTest(parseopt)
+
+  block: # fix #9842
+    let exe = buildDir / "D20190112T145450".addFileExt(ExeExt)
+    defer:
+      when not defined(windows):
+        # workaround #10359 ; innocuous to skip since we're saving under `buildDir`
+        removeFile exe
+    let args = @["a1b", "a2 b", "", "a4\"b", "a5'b", r"a6\b", "a7\'b"]
+    let cmd = "$# c -r --verbosity:0 -o:$# -d:testament_tparseopt $# $#" %
+      [getCurrentCompilerExe(), exe, currentSourcePath(),
+          args.quoteShellCommand]
+    var ret = execCmdEx(cmd, options = {})
+    if ret.exitCode != 0:
+      # before bug fix, running cmd would show:
+      # sh: -c: line 0: unexpected EOF while looking for matching `"'\n
+      echo "exitCode: ", ret.exitCode, " cmd:", cmd
+      doAssert false
+    stripLineEnd(ret.output)
+    assertEquals ret.output,
+      """
+@["a1b", "a2 b", "", "a4\"b", "a5\'b", "a6\\b", "a7\'b"]
+arg 0 ai.len:3 :{a1b}
+arg 1 ai.len:4 :{a2 b}
+arg 2 ai.len:0 :{}
+arg 3 ai.len:4 :{a4"b}
+arg 4 ai.len:4 :{a5'b}
+arg 5 ai.len:4 :{a6\b}
+arg 6 ai.len:4 :{a7'b}"""
+
+
+
+  block:
+    let args = @["-v", "ABC"]
+    var p = parseopt.initOptParser(args, shortnoVal = {'n'}, longnoVal = @["novalue"])
+    for kind, key, val in parseopt.getopt(p):
+      echo kind," key: ", key, " value: '", val, "'"
+
+    var r = parseopt.initOptParser(@["-v ABC"], shortnoVal = {'n'}, longnoVal = @["novalue"])
+    for kind, key, val in parseopt.getopt(r):
+      echo kind," key: ", key, " value: '", val, "'"
+
+    var s = parseopt.initOptParser("-v ABC", shortnoVal = {'v'}, longnoVal = @["novalue"])
+    for kind, key, val in parseopt.getopt(s):
+      echo kind," key: ", key, " value: '", val, "'"
+
+    var m = parseopt.initOptParser("-v ABC", shortnoVal = {'n'}, longnoVal = @["novalue"])
+    for kind, key, val in parseopt.getopt(m):
+      echo kind," key: ", key, " value: '", val, "'"
+
+    var n = parseopt.initOptParser("-j4 ok", shortnoVal = {'n'}, longnoVal = @["novalue"])
+    for kind, key, val in parseopt.getopt(n):
+      echo kind," key: ", key, " value: '", val, "'"
diff --git a/tests/tpos.nim b/tests/misc/tpos.nim
index 114d39c05..f7607d643 100755..100644
--- a/tests/tpos.nim
+++ b/tests/misc/tpos.nim
@@ -1,29 +1,33 @@
-# test this particular function

-

-proc mypos(sub, s: string, start: int = 0): int =

-  var

-    i, j, M, N: int

-  M = sub.len

-  N = s.len

-  i = start

-  j = 0

-  if i >= N:

-    result = -1

-  else:

-    while True:

-      if s[i] == sub[j]:

-        Inc(i)

-        Inc(j)

-      else:

-        i = i - j + 1

-        j = 0

-      if (j >= M) or (i >= N): break

-    if j >= M:

-      result = i - M

-    else:

-      result = -1

-

-var sub = "hallo"

-var s = "world hallo"

-write(stdout, mypos(sub, s))

-#OUT 6

+discard """
+  output: "6"
+"""
+# test this particular function
+
+proc mypos(sub, s: string, start: int = 0): int =
+  var
+    i, j, M, N: int
+  M = sub.len
+  N = s.len
+  i = start
+  j = 0
+  if i >= N:
+    result = -1
+  else:
+    while true:
+      if s[i] == sub[j]:
+        inc(i)
+        inc(j)
+      else:
+        i = i - j + 1
+        j = 0
+      if (j >= M) or (i >= N): break
+    if j >= M:
+      result = i - M
+    else:
+      result = -1
+
+var sub = "hello"
+var s = "world hello"
+write(stdout, mypos(sub, s))
+write stdout, "\n"
+#OUT 6
diff --git a/tests/misc/tprep.nim b/tests/misc/tprep.nim
new file mode 100644
index 000000000..45f25b790
--- /dev/null
+++ b/tests/misc/tprep.nim
@@ -0,0 +1,38 @@
+discard """
+nimout: '''
+tprep.nim(25, 9) Hint: Case 2 [User]
+tprep.nim(27, 11) Hint: Case 2.3 [User]
+'''
+outputsub: ""
+"""
+
+# Test the features that used to belong to the preprocessor
+
+import
+  times
+
+#{.warning: "This is only a test warning!".}
+
+const
+  case2 = true
+  case3 = true
+
+when defined(case1):
+  {.hint: "Case 1".}
+  when case3:
+    {.hint: "Case 1.3".}
+elif case2:
+  {.hint: "Case 2".}
+  when case3:
+    {.hint: "Case 2.3".}
+elif case3:
+  {.hint: "Case 3".}
+else:
+  {.hint: "unknown case".}
+
+var
+  s: string
+write(stdout, "compiled at " & system.CompileDate &
+              " " & CompileTime & "\n")
+echo getDateStr()
+echo getClockStr()
diff --git a/tests/misc/tquicksort.nim b/tests/misc/tquicksort.nim
new file mode 100644
index 000000000..017c73fbc
--- /dev/null
+++ b/tests/misc/tquicksort.nim
@@ -0,0 +1,23 @@
+proc QuickSort(list: seq[int]): seq[int] =
+    if len(list) == 0:
+        return @[]
+    var pivot = list[0]
+    var left: seq[int] = @[]
+    var right: seq[int] = @[]
+    for i in low(list)..high(list):
+        if list[i] < pivot:
+            left.add(list[i])
+        elif list[i] > pivot:
+            right.add(list[i])
+    result = QuickSort(left) &
+      pivot &
+      QuickSort(right)
+
+proc echoSeq(a: seq[int]) =
+    for i in low(a)..high(a):
+        echo(a[i])
+
+let list = QuickSort(@[89,23,15,23,56,123,356,12,7,1,6,2,9,4,3])
+let expected = @[1, 2, 3, 4, 6, 7, 9, 12, 15, 23, 56, 89, 123, 356]
+
+doAssert list == expected
diff --git a/tests/misc/tradix.nim b/tests/misc/tradix.nim
new file mode 100644
index 000000000..f4fb56849
--- /dev/null
+++ b/tests/misc/tradix.nim
@@ -0,0 +1,254 @@
+discard """
+output: '''
+start tradix.nim
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+128
+1
+2
+3
+4
+255
+17
+45
+19000
+4294967288
+'''
+"""
+
+# implements and tests an efficient radix tree
+
+## another method to store an efficient array of pointers:
+## We use a radix tree with node compression.
+## There are two node kinds:
+
+echo "start tradix.nim"
+
+const BitsPerUnit = 8*sizeof(int)
+
+type
+  TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear
+  PRadixNode = ptr TRadixNode
+  TRadixNode {.pure, inheritable.} = object
+    kind: TRadixNodeKind
+  TRadixNodeLinear = object of TRadixNode
+    len: uint8
+    keys: array[0..31, uint8]
+    vals: array[0..31, PRadixNode]
+
+  TRadixNodeFull = object of TRadixNode
+    b: array[0..255, PRadixNode]
+  TRadixNodeLeafBits = object of TRadixNode
+    b: array[0..7, int]
+  TRadixNodeLeafLinear = object of TRadixNode
+    len: uint8
+    keys: array[0..31, uint8]
+
+var
+  root: PRadixNode
+
+proc searchInner(r: PRadixNode, a: int): PRadixNode =
+  case r.kind
+  of rnLinear:
+    var x = cast[ptr TRadixNodeLinear](r)
+    for i in 0..int(x.len)-1:
+      if int(x.keys[i]) == a: return x.vals[i]
+  of rnFull:
+    var x = cast[ptr TRadixNodeFull](r)
+    return x.b[a]
+  else: assert(false)
+
+proc testBit(w, i: int): bool {.inline.} =
+  result = (w and (1 shl (i %% BitsPerUnit))) != 0
+
+proc setBit(w: var int, i: int) {.inline.} =
+  w = w or (1 shl (i %% BitsPerUnit))
+
+proc resetBit(w: var int, i: int) {.inline.} =
+  w = w and not (1 shl (i %% BitsPerUnit))
+
+proc testOrSetBit(w: var int, i: int): bool {.inline.} =
+  var x = (1 shl (i %% BitsPerUnit))
+  if (w and x) != 0: return true
+  w = w or x
+
+proc searchLeaf(r: PRadixNode, a: int): bool =
+  case r.kind
+  of rnLeafBits:
+    var x = cast[ptr TRadixNodeLeafBits](r)
+    return testBit(x.b[a /% BitsPerUnit], a)
+  of rnLeafLinear:
+    var x = cast[ptr TRadixNodeLeafLinear](r)
+    for i in 0..int(x.len)-1:
+      if int(x.keys[i]) == a: return true
+  else: assert(false)
+
+proc exclLeaf(r: PRadixNode, a: int) =
+  case r.kind
+  of rnLeafBits:
+    var x = cast[ptr TRadixNodeLeafBits](r)
+    resetBit(x.b[a /% BitsPerUnit], a)
+  of rnLeafLinear:
+    var x = cast[ptr TRadixNodeLeafLinear](r)
+    var L = int(x.len)
+    for i in 0..L-1:
+      if int(x.keys[i]) == a:
+        x.keys[i] = x.keys[L-1]
+        dec(x.len)
+        return
+  else: assert(false)
+
+proc contains*(r: PRadixNode, a: ByteAddress): bool =
+  if r == nil: return false
+  var x = searchInner(r, a shr 24 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 16 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 8 and 0xff)
+  if x == nil: return false
+  return searchLeaf(x, a and 0xff)
+
+proc excl*(r: PRadixNode, a: ByteAddress): bool =
+  if r == nil: return false
+  var x = searchInner(r, a shr 24 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 16 and 0xff)
+  if x == nil: return false
+  x = searchInner(x, a shr 8 and 0xff)
+  if x == nil: return false
+  exclLeaf(x, a and 0xff)
+
+proc addLeaf(r: var PRadixNode, a: int): bool =
+  if r == nil:
+    # a linear node:
+    var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear)))
+    x.kind = rnLeafLinear
+    x.len = 1'u8
+    x.keys[0] = uint8(a)
+    r = x
+    return false # not already in set
+  case r.kind
+  of rnLeafBits:
+    var x = cast[ptr TRadixNodeLeafBits](r)
+    return testOrSetBit(x.b[a /% BitsPerUnit], a)
+  of rnLeafLinear:
+    var x = cast[ptr TRadixNodeLeafLinear](r)
+    var L = int(x.len)
+    for i in 0..L-1:
+      if int(x.keys[i]) == a: return true
+    if L <= high(x.keys):
+      x.keys[L] = uint8(a)
+      inc(x.len)
+    else:
+      # transform into a full node:
+      var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits)))
+      y.kind = rnLeafBits
+      for i in 0..int(x.len)-1:
+        var u = int(x.keys[i])
+        setBit(y.b[u /% BitsPerUnit], u)
+      setBit(y.b[a /% BitsPerUnit], a)
+      dealloc(r)
+      r = y
+  else: assert(false)
+
+proc addInner(r: var PRadixNode, a: int, d: int): bool =
+  if d == 0:
+    return addLeaf(r, a and 0xff)
+  var k = a shr d and 0xff
+  if r == nil:
+    # a linear node:
+    var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear)))
+    x.kind = rnLinear
+    x.len = 1'u8
+    x.keys[0] = uint8(k)
+    r = x
+    return addInner(x.vals[0], a, d-8)
+  case r.kind
+  of rnLinear:
+    var x = cast[ptr TRadixNodeLinear](r)
+    var L = int(x.len)
+    for i in 0..L-1:
+      if int(x.keys[i]) == k: # already exists
+        return addInner(x.vals[i], a, d-8)
+    if L <= high(x.keys):
+      x.keys[L] = uint8(k)
+      inc(x.len)
+      return addInner(x.vals[L], a, d-8)
+    else:
+      # transform into a full node:
+      var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull)))
+      y.kind = rnFull
+      for i in 0..L-1: y.b[int(x.keys[i])] = x.vals[i]
+      dealloc(r)
+      r = y
+      return addInner(y.b[k], a, d-8)
+  of rnFull:
+    var x = cast[ptr TRadixNodeFull](r)
+    return addInner(x.b[k], a, d-8)
+  else: assert(false)
+
+proc incl*(r: var PRadixNode, a: ByteAddress) {.inline.} =
+  discard addInner(r, a, 24)
+
+proc testOrIncl*(r: var PRadixNode, a: ByteAddress): bool {.inline.} =
+  return addInner(r, a, 24)
+
+iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] =
+  if r != nil:
+    case r.kind
+    of rnFull:
+      var r = cast[ptr TRadixNodeFull](r)
+      for i in 0..high(r.b):
+        if r.b[i] != nil:
+          yield (i, r.b[i])
+    of rnLinear:
+      var r = cast[ptr TRadixNodeLinear](r)
+      for i in 0..int(r.len)-1:
+        yield (int(r.keys[i]), r.vals[i])
+    else: assert(false)
+
+iterator leafElements(r: PRadixNode): int =
+  if r != nil:
+    case r.kind
+    of rnLeafBits:
+      var r = cast[ptr TRadixNodeLeafBits](r)
+      # iterate over any bit:
+      for i in 0..high(r.b):
+        if r.b[i] != 0: # test all bits for zero
+          for j in 0..BitsPerUnit-1:
+            if testBit(r.b[i], j):
+              yield i*BitsPerUnit+j
+    of rnLeafLinear:
+      var r = cast[ptr TRadixNodeLeafLinear](r)
+      for i in 0..int(r.len)-1:
+        yield int(r.keys[i])
+    else: assert(false)
+
+iterator elements*(r: PRadixNode): ByteAddress {.inline.} =
+  for p1, n1 in innerElements(r):
+    for p2, n2 in innerElements(n1):
+      for p3, n3 in innerElements(n2):
+        for p4 in leafElements(n3):
+          yield p1 shl 24 or p2 shl 16 or p3 shl 8 or p4
+
+proc main() =
+  const
+    numbers = [128, 1, 2, 3, 4, 255, 17, -8, 45, 19_000]
+  var
+    r: PRadixNode = nil
+  for x in items(numbers):
+    echo testOrIncl(r, x)
+  for x in elements(r):
+    # ByteAddress being defined as a signed integer cases trouble
+    # exactly here
+    echo(cast[uint](x))
+
+main()
diff --git a/tests/misc/trfc405.nim b/tests/misc/trfc405.nim
new file mode 100644
index 000000000..0828879ee
--- /dev/null
+++ b/tests/misc/trfc405.nim
@@ -0,0 +1,112 @@
+
+{.experimental: "flexibleOptionalParams".}
+
+# https://github.com/nim-lang/RFCs/issues/405
+
+template main =
+  template fn1(a = 1, b = 2, body): auto = (a, b, astToStr(body))
+  let a1 = fn1(10, 20):
+    foo
+  doAssert a1 == (10, 20, "\nfoo")
+
+  template fn2(a = 1, b = 2, body): auto = (a, b, astToStr(body))
+  let a2 = fn2(a = 10): foo
+  doAssert a2 == (10, 2, "\nfoo")
+  let a2b = fn2(b = 20): foo
+  doAssert a2b == (1, 20, "\nfoo")
+
+  template fn3(x: int, a = 1, b = 2, body): auto = (a, b, astToStr(body))
+  let a3 = fn3(3, 10, 20): foo
+  doAssert a3 == (10, 20, "\nfoo")
+  let a3b = fn3(3, a = 10): foo
+  doAssert a3b == (10, 2, "\nfoo")
+
+  template fn4(x: int, y: int, body): auto = (x, y, astToStr(body))
+  let a4 = fn4(1, 2): foo
+  doAssert a4 == (1, 2, "\nfoo")
+
+  template fn5(x = 1, y = 2, body: untyped = 3): auto = (x, y, astToStr(body))
+  doAssert compiles(fn5(1, 2, foo))
+  doAssert not compiles(fn5(1, foo))
+
+  block:
+    # with an overload
+    var witness = 0
+    template fn6() = discard
+    template fn6(procname: string, body: untyped): untyped = witness.inc
+    fn6("abc"): discard
+    assert witness == 1
+
+  block:
+    # with overloads
+    var witness = 0
+    template fn6() = discard
+    template fn6(a: int) = discard
+    template fn6(procname: string, body: untyped): untyped = witness.inc
+    fn6("abc"): discard
+    assert witness == 1
+
+    template fn6(b = 1.5, body: untyped): untyped = witness.inc
+    fn6(1.3): discard
+    assert witness == 2
+
+  block:
+    var witness = 0
+    template fn6(a: int) = discard
+    template fn6(a: string) = discard
+    template fn6(ignore: string, b = 1.5, body: untyped): untyped = witness.inc
+    fn6(""):
+      foobar1
+      foobar2
+    doAssert witness == 1
+    fn6(""): discard
+    doAssert witness == 2
+
+  block: # multi block args
+    template fn8(a = 1, b = 2, body1: untyped, body2: untyped): auto = (a, b, astToStr(body1), astToStr(body2))
+    let a1 = fn8():
+      foobar1
+      foobar2
+    do:
+      foobar3
+      foobar4
+    doAssert a1 == (1, 2, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4")
+
+    let a2 = fn8(b = 20):
+      foobar1
+      foobar2
+    do:
+      foobar3
+      foobar4
+    doAssert a2 == (1, 20, "\nfoobar1\nfoobar2", "\nfoobar3\nfoobar4")
+  
+  block: # issue #19015
+    template hi(a: untyped, b: varargs[untyped]): untyped =
+      a
+
+    var worked = false
+    hi:
+      worked = true
+    doAssert worked
+    worked = false
+    hi(doAssert(not worked)):
+      doesntCompile
+    hi(doAssert(not worked), doesntCompile, againDoesntCompile):
+      definitelyDoesntCompile
+
+    template hi2(a: bool, b: untyped, c: varargs[untyped]): untyped =
+      b
+      doAssert a
+
+    hi2 worked:
+      worked = true
+    doAssert worked
+    hi2 worked, doAssert(worked):
+      doesntCompile
+    hi2 worked, doAssert(worked), doesntCompile, againDoesntCompile:
+      definitelyDoesntCompile
+    hi2 worked, doAssert(worked), againDoesntCompile:
+      definitelyDoesntCompile
+
+static: main()
+main()
diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim
new file mode 100644
index 000000000..6e5487d1b
--- /dev/null
+++ b/tests/misc/trunner.nim
@@ -0,0 +1,444 @@
+discard """
+  targets: "c cpp"
+  joinable: false
+"""
+
+## tests that don't quite fit the mold and are easier to handle via `execCmdEx`
+## A few others could be added to here to simplify code.
+## Note: this test is a bit slow but tests a lot of things; please don't disable.
+## Note: if needed, we could use `matrix: "-d:case1; -d:case2"` to split this
+## into several independent tests while retaining the common test helpers.
+
+import std/[strformat,os,osproc,unittest,compilesettings]
+from std/sequtils import toSeq,mapIt
+from std/algorithm import sorted
+import stdtest/[specialpaths, unittest_light]
+from std/private/globs import nativeToUnixPath
+from strutils import startsWith, strip, removePrefix
+from std/sugar import dup
+import "$lib/../compiler/nimpaths"
+
+proc isDots(a: string): bool =
+  ## test for `hintProcessing` dots
+  a.startsWith(".") and a.strip(chars = {'.'}) == ""
+
+const
+  nim = getCurrentCompilerExe()
+  mode = querySetting(backend)
+  nimcache = buildDir / "nimcacheTrunner"
+    # instead of `querySetting(nimcacheDir)`, avoids stomping on other parallel tests
+
+proc runNimCmd(file, options = "", rtarg = ""): auto =
+  let fileabs = testsDir / file.unixToNativePath
+  # doAssert fileabs.fileExists, fileabs # disabled because this allows passing `nim r --eval:code fakefile`
+  let cmd = fmt"{nim} {mode} --hint:all:off {options} {fileabs} {rtarg}"
+  result = execCmdEx(cmd)
+  when false: # for debugging
+    echo cmd
+    echo result[0] & "\n" & $result[1]
+
+proc runNimCmdChk(file, options = "", rtarg = "", status = 0): string =
+  let (ret, status2) = runNimCmd(file, options, rtarg = rtarg)
+  doAssert status2 == status, $(file, options, status, status2) & "\n" & ret
+  ret
+
+proc genShellCmd(filename: string): string =
+  let filename = filename.quoteShell
+  when defined(windows): "cmd /c " & filename # or "cmd /c " ?
+  else: "sh " & filename
+
+when defined(nimTrunnerFfi):
+  block: # mevalffi
+    when defined(openbsd):
+      #[
+      openbsd defines `#define stderr (&__sF[2])` which makes it cumbersome
+      for dlopen'ing inside `importcSymbol`. Instead of adding special rules
+      inside `importcSymbol` to handle this, we disable just the part that's
+      not working and will provide a more general, clean fix in future PR.
+      ]#
+      var opt = "-d:nimEvalffiStderrWorkaround"
+      let prefix = ""
+    else:
+      var opt = ""
+      let prefix = """
+hello world stderr
+hi stderr
+"""
+    let output = runNimCmdChk("vm/mevalffi.nim", fmt"{opt} --warnings:off --experimental:compiletimeFFI")
+    doAssert output == fmt"""
+{prefix}foo
+foo:100
+foo:101
+foo:102:103
+foo:102:103:104
+foo:0.03:asdf:103:105
+ret=[s1:foobar s2:foobar age:25 pi:3.14]
+""", output
+
+elif not defined(nimTestsTrunnerDebugging):
+  # don't run twice the same test with `nimTrunnerFfi`
+  # use `-d:nimTestsTrunnerDebugging` for debugging convenience when you want to just run 1 test
+  import std/strutils
+  import std/json
+  template check2(msg) = doAssert msg in output, output
+
+  block: # tests with various options `nim doc --project --index --docroot`
+    # regression tests for issues and PRS: #14376 #13223 #6583 ##13647
+    let file = testsDir / "nimdoc/sub/mmain.nim"
+    let mainFname = "mmain.html"
+    let htmldocsDirCustom = nimcache / "htmldocsCustom"
+    let docroot = testsDir / "nimdoc"
+    let options = [
+      0: "--project",
+      1: "--project --docroot",
+      2: "",
+      3: fmt"--outDir:{htmldocsDirCustom}",
+      4: fmt"--docroot:{docroot}",
+      5: "--project --useNimcache",
+      6: "--index:off",
+    ]
+
+    for i in 0..<options.len:
+      let htmldocsDir = case i
+      of 3: htmldocsDirCustom
+      of 5: nimcache / htmldocsDirname
+      else: file.parentDir / htmldocsDirname
+
+      var cmd = fmt"{nim} doc --index:on --filenames:abs --hint:successX:on --nimcache:{nimcache} {options[i]} {file}"
+      removeDir(htmldocsDir)
+      let (outp, exitCode) = execCmdEx(cmd)
+      check exitCode == 0
+      let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPath).sorted.join("\n")
+      let context = $(i, ret, cmd)
+      case i
+      of 0,5:
+        let htmlFile = htmldocsDir/mainFname
+        check htmlFile in outp # sanity check for `hintSuccessX`
+        assertEquals ret, fmt"""
+{dotdotMangle}/imp.html
+{dotdotMangle}/imp.idx
+{docHackJsFname}
+imp.html
+imp.idx
+imp2.html
+imp2.idx
+{mainFname}
+mmain.idx
+{nimdocOutCss}
+{theindexFname}""", context
+      of 1: assertEquals ret, fmt"""
+{docHackJsFname}
+{nimdocOutCss}
+tests/nimdoc/imp.html
+tests/nimdoc/imp.idx
+tests/nimdoc/sub/imp.html
+tests/nimdoc/sub/imp.idx
+tests/nimdoc/sub/imp2.html
+tests/nimdoc/sub/imp2.idx
+tests/nimdoc/sub/{mainFname}
+tests/nimdoc/sub/mmain.idx
+{theindexFname}"""
+      of 2, 3: assertEquals ret, fmt"""
+{docHackJsFname}
+{mainFname}
+mmain.idx
+{nimdocOutCss}""", context
+      of 4: assertEquals ret, fmt"""
+{docHackJsFname}
+{nimdocOutCss}
+sub/{mainFname}
+sub/mmain.idx""", context
+      of 6: assertEquals ret, fmt"""
+{mainFname}
+{nimdocOutCss}""", context
+      else: doAssert false
+
+  block: # mstatic_assert
+    let (output, exitCode) = runNimCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad")
+    check2 "sizeof(bool) == 2"
+    check exitCode != 0
+
+  block: # ABI checks
+    let file = "misc/msizeof5.nim"
+    block:
+      discard runNimCmdChk(file, "-d:checkAbi")
+    block:
+      let (output, exitCode) = runNimCmd(file, "-d:checkAbi -d:caseBad")
+      # on platforms that support _StaticAssert natively, errors will show full context, e.g.:
+      # error: static_assert failed due to requirement 'sizeof(unsigned char) == 8'
+      # "backend & Nim disagree on size for: BadImportcType{int64} [declared in mabi_check.nim(1, 6)]"
+      check2 "sizeof(unsigned char) == 8"
+      check2 "sizeof(struct Foo2) == 1"
+      check2 "sizeof(Foo5) == 16"
+      check2 "sizeof(Foo5) == 3"
+      check2 "sizeof(struct Foo6) == "
+      check exitCode != 0
+
+  import streams
+  block: # stdin input
+    let nimcmd = fmt"""{nim} r --hints:off - -firstparam "-second param" """
+    let expected = """@["-firstparam", "-second param"]"""
+    block:
+      let p = startProcess(nimcmd, options = {poEvalCommand})
+      p.inputStream.write("import os; echo commandLineParams()")
+      p.inputStream.close
+      var output = p.outputStream.readAll
+      let error = p.errorStream.readAll
+      doAssert p.waitForExit == 0
+      doAssert error.len == 0, $error
+      output.stripLineEnd
+      check output == expected
+      p.errorStream.close
+      p.outputStream.close
+
+    block:
+      when defined posix:
+        # xxx on windows, `poEvalCommand` should imply `/cmd`, (which should
+        # make this work), but currently doesn't
+        let cmd = fmt"""echo "import os; echo commandLineParams()" | {nimcmd}"""
+        var (output, exitCode) = execCmdEx(cmd)
+        output.stripLineEnd
+        check output == expected
+        doAssert exitCode == 0
+
+  block: # nim doc --backend:$backend --doccmd:$cmd
+    # test for https://github.com/nim-lang/Nim/issues/13129
+    # test for https://github.com/nim-lang/Nim/issues/13891
+    let file = testsDir / "nimdoc/m13129.nim"
+    for backend in fmt"{mode} js".split:
+      # pending #14343 this fails on windows: --doccmd:"-d:m13129Foo2 --hints:off"
+      let cmd = fmt"""{nim} doc -b:{backend} --nimcache:{nimcache} -d:m13129Foo1 "--doccmd:-d:m13129Foo2 --hints:off" --usenimcache --hints:off {file}"""
+      check execCmdEx(cmd) == (&"ok1:{backend}\nok2: backend: {backend}\n", 0)
+    # checks that --usenimcache works with `nim doc`
+    check fileExists(nimcache / "htmldocs/m13129.html")
+
+    block: # mak sure --backend works with `nim r`
+      let cmd = fmt"{nim} r --backend:{mode} --hints:off --nimcache:{nimcache} {file}"
+      check execCmdEx(cmd) == ("ok3\n", 0)
+
+  block: # nim jsondoc # bug #20132
+    let file = testsDir / "misc/mjsondoc.nim"
+    let output = "nimcache_tjsondoc.json"
+    defer: removeFile(output)
+    let (msg, exitCode) = execCmdEx(fmt"{nim} jsondoc -o:{output} {file}")
+    doAssert exitCode == 0, msg
+
+    let data = parseJson(readFile(output))["entries"]
+    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"
+    let destDir = testsDir / "misc/htmldocs"
+    removeDir(destDir)
+    defer: removeDir(destDir)
+    let (msg, exitCode) = execCmdEx(fmt"{nim} jsondoc {file}")
+    doAssert exitCode == 0, msg
+
+    let data = parseJson(readFile(destDir / "mjsondoc.json"))["entries"]
+    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: [].}"
+
+  block: # further issues with `--backend`
+    let file = testsDir / "misc/mbackend.nim"
+    var cmd = fmt"{nim} doc -b:cpp --hints:off --nimcache:{nimcache} {file}"
+    check execCmdEx(cmd) == ("", 0)
+    cmd = fmt"{nim} check -b:c -b:cpp --hints:off --nimcache:{nimcache} {file}"
+    check execCmdEx(cmd) == ("", 0)
+    # issue https://github.com/timotheecour/Nim/issues/175
+    cmd = fmt"{nim} c -b:js -b:cpp --hints:off --nimcache:{nimcache} {file}"
+    check execCmdEx(cmd) == ("", 0)
+
+  block: # some importc tests
+    # issue #14314
+    let file = testsDir / "misc/mimportc.nim"
+    let cmd = fmt"{nim} r -b:cpp --hints:off --nimcache:{nimcache} --warningAsError:ProveInit {file}"
+    check execCmdEx(cmd) == ("witness\n", 0)
+
+  block: # bug #20149
+    let file = testsDir / "misc/m20149.nim"
+    let cmd = fmt"{nim} r --hints:off --nimcache:{nimcache} --hintAsError:XDeclaredButNotUsed {file}"
+    check execCmdEx(cmd) == ("12\n", 0)
+
+  block: # bug #15316
+    when not defined(windows):
+      # This never worked reliably on Windows. Needs further investigation but it is hard to reproduce.
+      # Looks like a mild stack corruption when bailing out of nested exception handling.
+      let file = testsDir / "misc/m15316.nim"
+      let cmd = fmt"{nim} check --hints:off --nimcache:{nimcache} {file}"
+      check execCmdEx(cmd) == ("m15316.nim(1, 15) Error: expression expected, but found \')\'\nm15316.nim(2, 1) Error: expected: \':\', but got: \'[EOF]\'\nm15316.nim(2, 1) Error: expression expected, but found \'[EOF]\'\nm15316.nim(2, 1) " &
+            "Error: expected: \')\', but got: \'[EOF]\'\nError: illformed AST: \n", 1)
+
+
+  block: # config.nims, nim.cfg, hintConf, bug #16557
+    let cmd = fmt"{nim} r --hint:all:off --hint:conf tests/newconfig/bar/mfoo.nim"
+    let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut})
+    doAssert exitCode == 0
+    let dir = getCurrentDir()
+    let files = """
+tests/config.nims
+tests/newconfig/bar/nim.cfg
+tests/newconfig/bar/config.nims
+tests/newconfig/bar/mfoo.nim.cfg
+tests/newconfig/bar/mfoo.nims""".splitLines
+    var expected = ""
+    for a in files:
+      let b = dir / a
+      expected.add &"Hint: used config file '{b}' [Conf]\n"
+    doAssert outp.endsWith expected, outp & "\n" & expected
+
+  block: # bug #8219
+    let file = "tests/newconfig/mconfigcheck.nims"
+    let cmd = fmt"{nim} check --hints:off {file}"
+    check execCmdEx(cmd) == ("", 0)
+
+  block: # mfoo2.customext
+    let filename = testsDir / "newconfig/foo2/mfoo2.customext"
+    let cmd = fmt"{nim} e --hint:conf {filename}"
+    let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut})
+    doAssert exitCode == 0
+    var expected = &"Hint: used config file '{filename}' [Conf]\n"
+    doAssert outp.endsWith "123" & "\n" & expected
+
+
+  block: # nim --eval
+    let opt = "--hints:off"
+    check fmt"""{nim} {opt} --eval:"echo defined(nimscript)"""".execCmdEx == ("true\n", 0)
+    check fmt"""{nim} r {opt} --eval:"echo defined(c)"""".execCmdEx == ("true\n", 0)
+    check fmt"""{nim} r -b:js {opt} --eval:"echo defined(js)"""".execCmdEx == ("true\n", 0)
+
+  block: # `hintProcessing` dots should not interfere with `static: echo` + friends
+    let cmd = fmt"""{nim} r --hint:all:off --hint:processing -f --eval:"static: echo 1+1""""
+    let (outp, exitCode) = execCmdEx(cmd, options = {poStdErrToStdOut})
+    template check3(cond) = doAssert cond, $(outp,)
+    doAssert exitCode == 0
+    let lines = outp.splitLines
+    check3 lines.len == 3
+    when not defined(windows): # xxx: on windows, dots not properly handled, gives: `....2\n\n`
+      check3 lines[0].isDots
+      check3 lines[1] == "2"
+      check3 lines[2] == ""
+    else:
+      check3 "2" in outp
+
+  block: # nim secret
+    let opt = "--hint:all:off --hint:processing"
+    template check3(cond) = doAssert cond, $(outp,)
+    for extra in ["", "--stdout"]:
+      let cmd = fmt"""{nim} secret {opt} {extra}"""
+      # xxx minor bug: `nim --hint:QuitCalled:off secret` ignores the hint cmdline flag
+      template run(input2): untyped =
+        execCmdEx(cmd, options = {poStdErrToStdOut}, input = input2)
+      block:
+        let (outp, exitCode) = run """echo 1+2; import strutils; echo strip(" ab "); quit()"""
+        let lines = outp.splitLines
+        when not defined(windows):
+          check3 lines.len == 5
+          check3 lines[0].isDots
+          # check3 lines[1].isDots # todo nim secret might use parsing pipeline
+          check3 lines[2].dup(removePrefix(">>> ")) == "3" # prompt depends on `nimUseLinenoise`
+          check3 lines[3] == "ab"
+          check3 lines[4] == ""
+        else:
+          check3 "3" in outp
+          check3 "ab" in outp
+        doAssert exitCode == 0
+      block:
+        let (outp, exitCode) = run "echo 1+2; quit(2)"
+        check3 "3" in outp
+        doAssert exitCode == 2
+
+  block: # nimBetterRun
+    let file = "misc/mbetterrun.nim"
+    const nimcache2 = buildDir / "D20210423T185116"
+    removeDir nimcache2
+    # related to `-d:nimBetterRun`
+    let opt = fmt"-r --usenimcache --nimcache:{nimcache2}"
+    var ret = ""
+    for a in @["v1", "v2", "v1", "v3"]:
+      ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:{a}")
+    ret.add runNimCmdChk(file, fmt"{opt} -d:mbetterrunVal:v2", rtarg = "arg1 arg2")
+      # rt arguments should not cause a recompilation
+    doAssert ret == """
+compiling: v1
+running: v1
+compiling: v2
+running: v2
+running: v1
+compiling: v3
+running: v3
+running: v2
+""", ret
+
+  block: # nim dump
+    let cmd = fmt"{nim} dump --dump.format:json -d:D20210428T161003 --hints:off ."
+    let (ret, status) = execCmdEx(cmd)
+    doAssert status == 0
+    let j = ret.parseJson
+    # sanity checks
+    doAssert "D20210428T161003" in j["defined_symbols"].to(seq[string])
+    doAssert j["version"].to(string) == NimVersion
+    doAssert j["nimExe"].to(string) == getCurrentCompilerExe()
+
+  block: # genscript
+    const nimcache2 = buildDir / "D20210524T212851"
+    removeDir(nimcache2)
+    let input = "tgenscript_fakefile" # no need for a real file, --eval is good enough
+    let output = runNimCmdChk(input, fmt"""--genscript --nimcache:{nimcache2.quoteShell} --eval:"echo(12345)" """)
+    doAssert output.len == 0, output
+    let ext = when defined(windows): ".bat" else: ".sh"
+    let filename = fmt"compile_{input}{ext}" # synchronize with `generateScript`
+    doAssert fileExists(nimcache2/filename), nimcache2/filename
+    let (outp, status) = execCmdEx(genShellCmd(filename), options = {poStdErrToStdOut}, workingDir = nimcache2)
+    doAssert status == 0, outp
+    let (outp2, status2) = execCmdEx(nimcache2 / input, options = {poStdErrToStdOut})
+    doAssert outp2 == "12345\n", outp2
+    doAssert status2 == 0
+
+  block: # UnusedImport
+    proc fn(opt: string, expected: string) =
+      let output = runNimCmdChk("msgs/mused3.nim", fmt"--warning:all:off --warning:UnusedImport --hint:DuplicateModuleImport {opt}")
+      doAssert output == expected, opt & "\noutput:\n" & output & "expected:\n" & expected
+    fn("-d:case1"): """
+mused3.nim(13, 8) Warning: imported and not used: 'mused3b' [UnusedImport]
+"""
+    fn("-d:case2"): ""
+    fn("-d:case3"): ""
+    fn("-d:case4"): ""
+    fn("-d:case5"): ""
+    fn("-d:case6"): ""
+    fn("-d:case7"): ""
+    fn("-d:case8"): ""
+    fn("-d:case9"): ""
+    fn("-d:case10"): ""
+    when false:
+      fn("-d:case11"): """
+  Warning: imported and not used: 'm2' [UnusedImport]
+  """
+    fn("-d:case12"): """
+mused3.nim(75, 10) Hint: duplicate import of 'mused3a'; previous import here: mused3.nim(74, 10) [DuplicateModuleImport]
+"""
+
+  block: # FieldDefect
+    proc fn(opt: string, expected: string) =
+      let output = runNimCmdChk("misc/mfield_defect.nim", fmt"-r --warning:all:off --declaredlocs {opt}", status = 1)
+      doAssert expected in output, opt & "\noutput:\n" & output & "expected:\n" & expected
+    fn("-d:case1"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
+    fn("-d:case2 --gc:refc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
+    fn("-d:case1 -b:js"): """mfield_defect.nim(25, 15) Error: field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
+    fn("-d:case2 -b:js"): """field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
+    fn("-d:case2 --gc:arc"): """mfield_defect.nim(25, 15) field 'f2' is not accessible for type 'Foo' [discriminant declared in mfield_defect.nim(14, 8)] using 'kind = k3'"""
+else:
+  discard # only during debugging, tests added here will run with `-d:nimTestsTrunnerDebugging` enabled
diff --git a/tests/misc/trunner_special.nim b/tests/misc/trunner_special.nim
new file mode 100644
index 000000000..e08b419b0
--- /dev/null
+++ b/tests/misc/trunner_special.nim
@@ -0,0 +1,37 @@
+discard """
+  targets: "c cpp"
+  joinable: false
+  disabled: osx
+"""
+
+#[
+Runs tests that require special treatment, e.g. because they rely on 3rd party code
+or require external networking.
+
+xxx test all tests/untestable/* here, possibly with adjustments to make running times reasonable
+]#
+
+import std/[strformat,os,unittest,compilesettings]
+import stdtest/specialpaths
+
+
+from stdtest/testutils import disableSSLTesting
+
+
+const
+  nim = getCurrentCompilerExe()
+  mode = querySetting(backend)
+
+proc runCmd(cmd: string) =
+  let ret = execShellCmd(cmd)
+  check ret == 0 # allows more than 1 failure
+
+proc main =
+  let options = fmt"-b:{mode} --hints:off"
+  block: # SSL nimDisableCertificateValidation integration tests
+    runCmd fmt"{nim} r {options} -d:nimDisableCertificateValidation -d:ssl {testsDir}/untestable/thttpclient_ssl_disabled.nim"
+  block: # SSL certificate check integration tests
+    runCmd fmt"{nim} r {options} -d:ssl --threads:on --mm:refc {testsDir}/untestable/thttpclient_ssl_remotenetwork.nim"
+
+when not disableSSLTesting():
+  main()
diff --git a/tests/misc/tsamename.nim b/tests/misc/tsamename.nim
new file mode 100644
index 000000000..b2d17a506
--- /dev/null
+++ b/tests/misc/tsamename.nim
@@ -0,0 +1,15 @@
+# bug #9891
+
+import "."/tsamename2
+
+# this works
+callFun(fooBar2)
+
+when true:
+  # Error: attempting to call routine: 'processPattern'
+  callFun(fooBar)
+
+when true:
+  # BUG: Error: internal error: expr(skModule); unknown symbol
+  proc processPattern() = discard
+  callFun(fooBar)
diff --git a/tests/misc/tsamename2.nim b/tests/misc/tsamename2.nim
new file mode 100644
index 000000000..d2272f557
--- /dev/null
+++ b/tests/misc/tsamename2.nim
@@ -0,0 +1,4 @@
+proc fooBar*()=discard
+proc fooBar2*()=discard
+proc callFun*[Fun](processPattern: Fun) =
+  processPattern()
diff --git a/tests/misc/tsemfold.nim b/tests/misc/tsemfold.nim
new file mode 100644
index 000000000..2ce8d9560
--- /dev/null
+++ b/tests/misc/tsemfold.nim
@@ -0,0 +1,27 @@
+discard """
+  action: run
+"""
+
+doAssertRaises(OverflowDefect): discard low(int8) - 1'i8
+doAssertRaises(OverflowDefect): discard high(int8) + 1'i8
+doAssertRaises(OverflowDefect): discard abs(low(int8))
+doAssertRaises(DivByZeroDefect): discard 1 mod 0
+doAssertRaises(DivByZeroDefect): discard 1 div 0
+doAssertRaises(OverflowDefect): discard low(int8) div -1'i8
+
+doAssertRaises(OverflowDefect): discard -low(int64)
+doAssertRaises(OverflowDefect): discard low(int64) - 1'i64
+doAssertRaises(OverflowDefect): discard high(int64) + 1'i64
+
+type E = enum eA, eB
+doAssertRaises(OverflowDefect): discard eA.pred
+doAssertRaises(OverflowDefect): discard eB.succ
+
+doAssertRaises(OverflowDefect): discard low(int8) * -1
+doAssertRaises(OverflowDefect): discard low(int64) * -1
+doAssertRaises(OverflowDefect): discard high(int8) * 2
+doAssertRaises(OverflowDefect): discard high(int64) * 2
+
+doAssert abs(-1) == 1
+doAssert 2 div 2 == 1
+doAssert 2 * 3 == 6
diff --git a/tests/misc/tshadow_magic_type.nim b/tests/misc/tshadow_magic_type.nim
new file mode 100644
index 000000000..8b2d26133
--- /dev/null
+++ b/tests/misc/tshadow_magic_type.nim
@@ -0,0 +1,29 @@
+discard """
+output: '''
+mylist
+'''
+"""
+
+
+type
+  TListItemType* = enum
+    RedisNil, RedisString
+
+  TListItem* = object
+    case kind*: TListItemType
+    of RedisString:
+      str*: string
+    else: nil
+  TRedisList* = seq[TListItem]
+
+# Caused by this.
+proc seq*() =
+  discard
+
+proc lrange*(key: string): TRedisList =
+  var foo = TListItem(kind: RedisString, str: key)
+  result = @[foo]
+
+var p = lrange("mylist")
+for i in items(p):
+  echo(i.str)
diff --git a/tests/misc/tsimplesort.nim b/tests/misc/tsimplesort.nim
new file mode 100644
index 000000000..395db55e6
--- /dev/null
+++ b/tests/misc/tsimplesort.nim
@@ -0,0 +1,306 @@
+discard """
+  output: '''true'''
+"""
+
+import hashes, math
+
+{.pragma: myShallow.}
+
+type
+  TSlotEnum = enum seEmpty, seFilled, seDeleted
+  TKeyValuePair[A, B] = tuple[slot: TSlotEnum, key: A, val: B]
+  TKeyValuePairSeq[A, B] = seq[TKeyValuePair[A, B]]
+  TTable*[A, B] {.final, myShallow.} = object
+    data: TKeyValuePairSeq[A, B]
+    counter: int
+
+proc len*[A, B](t: TTable[A, B]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A, B](t: TTable[A, B]): tuple[key: A, val: B] =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A, B](t: TTable[A, B]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield t.data[h].key
+
+iterator values*[A, B](t: TTable[A, B]): B =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].slot == seFilled: yield t.data[h].val
+
+const
+  growthFactor = 2
+
+proc mustRehash(length, counter: int): bool {.inline.} =
+  assert(length > counter)
+  result = (length * 2 < counter * 3) or (length - counter < 4)
+
+proc nextTry(h, maxHash: Hash): Hash {.inline.} =
+  result = ((5 * h) + 1) and maxHash
+
+template rawGetImpl() =
+  var h: Hash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].slot != seEmpty:
+    if t.data[h].key == key and t.data[h].slot == seFilled:
+      return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+template rawInsertImpl() =
+  var h: Hash = hash(key) and high(data)
+  while data[h].slot == seFilled:
+    h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+  data[h].slot = seFilled
+
+proc rawGet[A, B](t: TTable[A, B], key: A): int =
+  rawGetImpl()
+
+proc `[]`*[A, B](t: TTable[A, B], key: A): B =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## default empty value for the type `B` is returned
+  ## and no exception is raised. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = rawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
+                     key: A, val: B) =
+  rawInsertImpl()
+
+proc enlarge[A, B](t: var TTable[A, B]) =
+  var n: TKeyValuePairSeq[A, B]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+template putImpl() =
+  var index = rawGet(t, key)
+  if index >= 0:
+    t.data[index].val = val
+  else:
+    if mustRehash(len(t.data), t.counter): enlarge(t)
+    rawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) =
+  ## puts a (key, value)-pair into `t`.
+  putImpl()
+
+proc del*[A, B](t: var TTable[A, B], key: A) =
+  ## deletes `key` from hash table `t`.
+  var index = rawGet(t, key)
+  if index >= 0:
+    t.data[index].slot = seDeleted
+    dec(t.counter)
+
+proc initTable*[A, B](initialSize=64): TTable[A, B] =
+  ## creates a new hash table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toTable*[A, B](pairs: openArray[tuple[key: A,
+                    val: B]]): TTable[A, B] =
+  ## creates a new hash table that contains the given `pairs`.
+  result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
+  for key, val in items(pairs): result[key] = val
+
+template dollarImpl(): typed =
+  if t.len == 0:
+    result = "{:}"
+  else:
+    result = "{"
+    for key, val in pairs(t):
+      if result.len > 1: result.add(", ")
+      result.add($key)
+      result.add(": ")
+      result.add($val)
+    result.add("}")
+
+proc `$`*[A, B](t: TTable[A, B]): string =
+  ## The `$` operator for hash tables.
+  dollarImpl()
+
+# ------------------------------ count tables -------------------------------
+
+type
+  TCountTable*[A] {.final, myShallow.} = object ## table that counts the number of each key
+    data: seq[tuple[key: A, val: int]]
+    counter: int
+
+proc len*[A](t: TCountTable[A]): int =
+  ## returns the number of keys in `t`.
+  result = t.counter
+
+iterator pairs*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## iterates over any (key, value) pair in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield (t.data[h].key, t.data[h].val)
+
+iterator keys*[A](t: TCountTable[A]): A =
+  ## iterates over any key in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].key
+
+iterator values*[A](t: TCountTable[A]): int =
+  ## iterates over any value in the table `t`.
+  for h in 0..high(t.data):
+    if t.data[h].val != 0: yield t.data[h].val
+
+proc RawGet[A](t: TCountTable[A], key: A): int =
+  var h: Hash = hash(key) and high(t.data) # start with real hash value
+  while t.data[h].val != 0:
+    if t.data[h].key == key: return h
+    h = nextTry(h, high(t.data))
+  result = -1
+
+proc `[]`*[A](t: TCountTable[A], key: A): int =
+  ## retrieves the value at ``t[key]``. If `key` is not in `t`,
+  ## 0 is returned. One can check with ``hasKey`` whether the key
+  ## exists.
+  var index = RawGet(t, key)
+  if index >= 0: result = t.data[index].val
+
+proc hasKey*[A](t: TCountTable[A], key: A): bool =
+  ## returns true iff `key` is in the table `t`.
+  result = rawGet(t, key) >= 0
+
+proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
+                  key: A, val: int) =
+  var h: Hash = hash(key) and high(data)
+  while data[h].val != 0: h = nextTry(h, high(data))
+  data[h].key = key
+  data[h].val = val
+
+proc enlarge[A](t: var TCountTable[A]) =
+  var n: seq[tuple[key: A, val: int]]
+  newSeq(n, len(t.data) * growthFactor)
+  for i in countup(0, high(t.data)):
+    if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
+  swap(t.data, n)
+
+proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) =
+  ## puts a (key, value)-pair into `t`. `val` has to be positive.
+  assert val > 0
+  putImpl()
+
+proc initCountTable*[A](initialSize=64): TCountTable[A] =
+  ## creates a new count table that is empty. `initialSize` needs to be
+  ## a power of two.
+  assert isPowerOfTwo(initialSize)
+  result.counter = 0
+  newSeq(result.data, initialSize)
+
+proc toCountTable*[A](keys: openArray[A]): TCountTable[A] =
+  ## creates a new count table with every key in `keys` having a count of 1.
+  result = initCountTable[A](nextPowerOfTwo(keys.len+10))
+  for key in items(keys): result[key] = 1
+
+proc `$`*[A](t: TCountTable[A]): string =
+  ## The `$` operator for count tables.
+  dollarImpl()
+
+proc inc*[A](t: var TCountTable[A], key: A, val = 1) =
+  ## increments `t[key]` by `val`.
+  var index = RawGet(t, key)
+  if index >= 0:
+    inc(t.data[index].val, val)
+  else:
+    if mustRehash(len(t.data), t.counter): enlarge(t)
+    rawInsert(t, t.data, key, val)
+    inc(t.counter)
+
+proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## returns the largest (key,val)-pair. Efficiency: O(n)
+  assert t.len > 0
+  var minIdx = 0
+  for h in 1..high(t.data):
+    if t.data[h].val > 0 and t.data[minIdx].val > t.data[h].val: minIdx = h
+  result.key = t.data[minIdx].key
+  result.val = t.data[minIdx].val
+
+proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
+  ## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
+  assert t.len > 0
+  var maxIdx = 0
+  for h in 1..high(t.data):
+    if t.data[maxIdx].val < t.data[h].val: maxIdx = h
+  result.key = t.data[maxIdx].key
+  result.val = t.data[maxIdx].val
+
+proc sort*[A](t: var TCountTable[A]) =
+  ## sorts the count table so that the entry with the highest counter comes
+  ## first. This is destructive! You must not modify `t` afterwards!
+  ## You can use the iterators `pairs`,  `keys`, and `values` to iterate over
+  ## `t` in the sorted order.
+
+  # we use shellsort here; fast enough and simple
+  var h = 1
+  while true:
+    h = 3 * h + 1
+    if h >= high(t.data): break
+  while true:
+    h = h div 3
+    for i in countup(h, high(t.data)):
+      var j = i
+      while t.data[j-h].val <= t.data[j].val:
+        var xyz = t.data[j]
+        t.data[j] = t.data[j-h]
+        t.data[j-h] = xyz
+        j = j-h
+        if j < h: break
+    if h == 1: break
+
+
+const
+  data = {
+    "34": 123456, "12": 789,
+    "90": 343, "0": 34404,
+    "1": 344004, "2": 344774,
+    "3": 342244, "4": 3412344,
+    "5": 341232144, "6": 34214544,
+    "7": 3434544, "8": 344544,
+    "9": 34435644, "---00": 346677844,
+    "10": 34484, "11": 34474, "19": 34464,
+    "20": 34454, "30": 34141244, "40": 344114,
+    "50": 344490, "60": 344491, "70": 344492,
+    "80": 344497}
+
+proc countTableTest1 =
+  var s = initTable[string, int](64)
+  for key, val in items(data): s[key] = val
+  var w: tuple[key: string, val: int] #type(otherCountTable.data[0])
+
+  var t = initCountTable[string]()
+  for k, v in items(data): t.inc(k)
+  for k in t.keys: assert t[k] == 1
+  t.inc("90", 3)
+  t.inc("12", 2)
+  t.inc("34", 1)
+  assert t.largest()[0] == "90"
+  t.sort()
+
+  var i = 0
+  for k, v in t.pairs:
+    case i
+    of 0: assert k == "90" and v == 4
+    of 1: assert k == "12" and v == 3
+    of 2: assert k == "34" and v == 2
+    else: break
+    inc i
+
+countTableTest1()
+echo true
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
new file mode 100644
index 000000000..ce5334664
--- /dev/null
+++ b/tests/misc/tsizeof.nim
@@ -0,0 +1,742 @@
+discard """
+  targets: "c cpp"
+  output: '''
+body executed
+body executed
+OK
+macros api OK
+'''
+"""
+
+# This is for Azure. The keyword ``alignof`` only exists in ``c++11``
+# and newer. On Azure gcc does not default to c++11 yet.
+when defined(cpp) and not defined(windows):
+  {.passC: "-std=c++11".}
+
+# Object offsets are different for inheritance objects when compiling
+# to c++.
+
+type
+  TMyEnum = enum
+    tmOne, tmTwo, tmThree, tmFour
+
+  TMyArray1 = array[3, uint8]
+  TMyArray2 = array[1..3, int32]
+  TMyArray3 = array[TMyEnum, float64]
+
+var failed = false
+
+const
+  mysize1 = sizeof(TMyArray1)
+  mysize2 = sizeof(TMyArray2)
+  mysize3 = sizeof(TMyArray3)
+
+doAssert mysize1 == 3
+doAssert mysize2 == 12
+doAssert mysize3 == 32
+
+import macros, typetraits
+
+macro testSizeAlignOf(args: varargs[untyped]): untyped =
+  result = newStmtList()
+  for arg in args:
+    result.add quote do:
+      let
+        c_size = c_sizeof(`arg`)
+        nim_size = sizeof(`arg`)
+        c_align = c_alignof(type(`arg`))
+        nim_align = alignof(`arg`)
+
+      if nim_size != c_size or nim_align != c_align:
+        var msg = strAlign(`arg`.type.name & ": ")
+        if nim_size != c_size:
+          msg.add  " size(got, expected):  " & $nim_size & " != " & $c_size
+        if nim_align != c_align:
+          msg.add  " align(get, expected): " & $nim_align & " != " & $c_align
+        echo msg
+        failed = true
+
+
+macro testOffsetOf(a, b: untyped): untyped =
+  let typeName = newLit(a.repr)
+  let member   = newLit(b.repr)
+  result = quote do:
+    let
+      c_offset   = c_offsetof(`a`,`b`)
+      nim_offset = offsetof(`a`,`b`)
+    if c_offset != nim_offset:
+      echo `typeName`, ".", `member`, " offsetError, C: ", c_offset, " nim: ", nim_offset
+      failed = true
+
+proc strAlign(arg: string): string =
+  const minLen = 22
+  result = arg
+  for i in 0 ..< minLen - arg.len:
+    result &= ' '
+
+macro c_offsetof(fieldAccess: typed): int32 =
+  ## Bullet proof implementation that works on actual offsetof operator
+  ## in the c backend. Assuming of course this implementation is
+  ## correct.
+  let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0]
+          else: fieldAccess
+  let a = s[0].getTypeInst
+  let b = s[1]
+  result = quote do:
+    var res: int32
+    {.emit: [res, " = offsetof(", `a`, ", ", `b`, ");"] .}
+    res
+
+template c_offsetof(t: typedesc, a: untyped): int32 =
+  var x: ptr t
+  c_offsetof(x[].a)
+
+macro c_sizeof(a: typed): int32 =
+  ## Bullet proof implementation that works using the sizeof operator
+  ## in the c backend. Assuming of course this implementation is
+  ## correct.
+  result = quote do:
+    var res: int32
+    {.emit: [res, " = sizeof(", `a`, ");"] .}
+    res
+
+macro c_alignof(arg: untyped): untyped =
+  ## Bullet proof implementation that works on actual alignment
+  ## behavior measured at runtime.
+  let typeSym = genSym(nskType, "AlignTestType"&arg.repr)
+  result = quote do:
+    type
+      `typeSym` = object
+        causeAlign: byte
+        member: `arg`
+    c_offsetof(`typeSym`, member)
+
+macro testAlign(arg:untyped):untyped =
+  let prefix = newLit(arg.lineinfo & "  alignof " & arg.repr & " ")
+  result = quote do:
+    let cAlign = c_alignof(`arg`)
+    let nimAlign = alignof(`arg`)
+    if cAlign != nimAlign:
+      echo `prefix`, cAlign, " != ", nimAlign
+      failed = true
+
+macro testSize(arg:untyped):untyped =
+  let prefix = newLit(arg.lineinfo & "  sizeof " & arg.repr & " ")
+  result = quote do:
+    let cSize = c_sizeof(`arg`)
+    let nimSize = sizeof(`arg`)
+    if cSize != nimSize:
+      echo `prefix`, cSize, " != ", nimSize
+      failed = true
+
+type
+  MyEnum {.pure.} = enum
+    ValueA
+    ValueB
+    ValueC
+
+  OtherEnum {.pure, size: 8.} = enum
+    ValueA
+    ValueB
+
+  Enum1 {.pure, size: 1.} = enum
+    ValueA
+    ValueB
+
+  Enum2 {.pure, size: 2.} = enum
+    ValueA
+    ValueB
+
+  Enum4 {.pure, size: 4.} = enum
+    ValueA
+    ValueB
+
+  Enum8 {.pure, size: 8.} = enum
+    ValueA
+    ValueB
+
+  # Must have more than 32 elements so that set[MyEnum33] will become compile to an int64.
+  MyEnum33 {.pure.} = enum
+    Value1, Value2, Value3, Value4, Value5, Value6,
+    Value7, Value8, Value9, Value10, Value11, Value12,
+    Value13, Value14, Value15, Value16, Value17, Value18,
+    Value19, Value20, Value21, Value22, Value23, Value24,
+    Value25, Value26, Value27, Value28, Value29, Value30,
+    Value31, Value32, Value33
+
+proc transformObjectconfigPacked(arg: NimNode): NimNode =
+  let debug = arg.kind == nnkPragmaExpr
+
+  if arg.eqIdent("objectconfig"):
+    result = ident"packed"
+  else:
+    result = copyNimNode(arg)
+    for child in arg:
+      result.add transformObjectconfigPacked(child)
+
+proc removeObjectconfig(arg: NimNode): NimNode =
+  if arg.kind == nnkPragmaExpr and arg[1][0].eqIdent "objectconfig":
+    result = arg[0]
+  else:
+    result = copyNimNode(arg)
+    for child in arg:
+      result.add removeObjectconfig(child)
+
+macro testinstance(body: untyped): untyped =
+  let bodyPure = removeObjectconfig(body)
+  let bodyPacked = transformObjectconfigPacked(body)
+
+  result = quote do:
+    proc pureblock(): void =
+      const usePacked {.inject.} = false
+      `bodyPure`
+
+    pureblock()
+
+    proc packedblock(): void =
+      const usePacked {.inject.} = true
+      `bodyPacked`
+
+    packedblock()
+
+proc testPrimitiveTypes(): void =
+  testAlign(pointer)
+  testAlign(int)
+  testAlign(uint)
+  testAlign(int8)
+  testAlign(int16)
+  testAlign(int32)
+  testAlign(int64)
+  testAlign(uint8)
+  testAlign(uint16)
+  testAlign(uint32)
+  testAlign(uint64)
+  testAlign(float)
+  testAlign(float32)
+  testAlign(float64)
+
+  testAlign(MyEnum)
+  testAlign(OtherEnum)
+  testAlign(Enum1)
+  testAlign(Enum2)
+  testAlign(Enum4)
+  testAlign(Enum8)
+
+testPrimitiveTypes()
+
+testinstance:
+  type
+
+    EnumObjectA  {.objectconfig.} = object
+      a : Enum1
+      b : Enum2
+      c : Enum4
+      d : Enum8
+
+    EnumObjectB  {.objectconfig.} = object
+      a : Enum8
+      b : Enum4
+      c : Enum2
+      d : Enum1
+
+    TrivialType  {.objectconfig.} = object
+      x,y,z: int8
+
+    SimpleAlignment {.objectconfig.} = object
+      # behaves differently on 32bit Windows and 32bit Linux
+      a,b: int8
+      c: int64
+
+    AlignAtEnd {.objectconfig.} = object
+      a: int64
+      b,c: int8
+
+    SimpleBranch {.objectconfig.} = object
+      case kind: MyEnum
+      of MyEnum.ValueA:
+        a: int16
+      of MyEnum.ValueB:
+        b: int32
+      of MyEnum.ValueC:
+        c: int64
+
+    PaddingBeforeBranchA {.objectconfig.} = object
+      cause: int8
+      case kind: MyEnum
+      of MyEnum.ValueA:
+        a: int16
+      of MyEnum.ValueB:
+        b: int32
+      of MyEnum.ValueC:
+        c: int64
+
+    PaddingBeforeBranchB {.objectconfig.} = object
+      cause: int8
+      case kind: MyEnum
+      of MyEnum.ValueA:
+        a: int8
+      of MyEnum.ValueB:
+        b: int16
+      of MyEnum.ValueC:
+        c: int32
+
+    PaddingAfterBranch {.objectconfig.} = object
+      case kind: MyEnum
+      of MyEnum.ValueA:
+        a: int8
+      of MyEnum.ValueB:
+        b: int16
+      of MyEnum.ValueC:
+        c: int32
+      cause: int64
+
+    RecursiveStuff {.objectconfig.} = object
+      case kind: MyEnum    # packedOffset:    0
+      of MyEnum.ValueA:    # packedOffset:
+        a: int16           # packedOffset:    1
+      of MyEnum.ValueB:    # packedOffset:
+        b: int32           # packedOffset:    1
+      of MyEnum.ValueC:    # packedOffset:
+        case kind2: MyEnum # packedOffset:    1
+        of MyEnum.ValueA:  # packedOffset:
+          ca1: int8
+          ca2: int32
+        of MyEnum.ValueB:  # packedOffset:
+          cb: int32        # packedOffset:    2
+        of MyEnum.ValueC:  # packedOffset:
+          cc: int64        # packedOffset:    2
+        d1: int8
+        d2: int64
+
+    Foobar {.objectconfig.} = object
+      case kind: OtherEnum
+      of OtherEnum.ValueA:
+        a: uint8
+      of OtherEnum.ValueB:
+        b: int8
+      c: int8
+
+    PaddingOfSetEnum33 {.objectconfig.} = object
+      cause: int8
+      theSet: set[MyEnum33]
+
+    Bazing {.objectconfig.} = object of RootObj
+      a: int64
+      # TODO test on 32 bit system
+      # only there the object header is smaller than the first member
+
+    InheritanceA {.objectconfig.} = object of RootObj
+      a: char
+
+    InheritanceB {.objectconfig.} = object of InheritanceA
+      b: char
+
+    InheritanceC {.objectconfig.} = object of InheritanceB
+      c: char
+
+    # from issue 4763
+    GenericObject[T] {.objectconfig.} = object
+      a: int32
+      b: T
+
+    # this type mixes `packed` with `align`.
+    MyCustomAlignPackedObject {.objectconfig.} = object
+      a: char
+      b {.align: 32.}: int32 # align overrides `packed` for this field.
+      c: char
+      d: int32  # unaligned
+
+    Kind = enum
+      K1, K2
+  
+    AnotherEnum = enum
+      X1, X2, X3
+
+    MyObject = object
+      s: string
+      case k: Kind
+      of K1: nil
+      of K2:
+          x: float
+          y: int32
+      z: AnotherEnum
+
+    Stack[N: static int, T: object] = object
+      pad: array[128 - sizeof(array[N, ptr T]) - sizeof(int) - sizeof(pointer), byte]
+      stack: array[N, ptr T]
+      len*: int
+      rawMem: ptr array[N, T]
+
+    Stack2[T: object] = object
+      pad: array[128 - sizeof(array[sizeof(T), ptr T]), byte]
+    
+
+  const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time
+
+  proc main(): void =
+    var t : TrivialType
+    var a : SimpleAlignment
+    var b : AlignAtEnd
+    var c : SimpleBranch
+    var d : PaddingBeforeBranchA
+    var e : PaddingBeforeBranchB
+    var f : PaddingAfterBranch
+    var g : RecursiveStuff
+    var ro : RootObj
+    var go : GenericObject[int64]
+    var po : PaddingOfSetEnum33
+    var capo: MyCustomAlignPackedObject
+    var issue15516: MyObject
+    var issue12636_1: Stack[5, MyObject]
+    var issue12636_2: Stack2[MyObject]
+
+    var
+      e1: Enum1
+      e2: Enum2
+      e4: Enum4
+      e8: Enum8
+    var
+      eoa: EnumObjectA
+      eob: EnumObjectB
+
+    testAlign(SimpleAlignment)
+
+    # sanity check to ensure both branches are actually executed
+    when usePacked:
+      doAssert sizeof(SimpleAlignment) == 10
+    else:
+      doAssert sizeof(SimpleAlignment) > 10
+
+    testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob, capo, issue15516, issue12636_1, issue12636_2)
+
+    type
+      WithBitsize {.objectconfig.} = object
+        bitfieldA {.bitsize: 16.}: uint32
+        bitfieldB {.bitsize: 16.}: uint32
+
+    var wbs: WithBitsize
+    testSize(wbs)
+
+    testOffsetOf(TrivialType, x)
+    testOffsetOf(TrivialType, y)
+    testOffsetOf(TrivialType, z)
+
+    testOffsetOf(SimpleAlignment, a)
+    testOffsetOf(SimpleAlignment, b)
+    testOffsetOf(SimpleAlignment, c)
+
+    testOffsetOf(AlignAtEnd, a)
+    testOffsetOf(AlignAtEnd, b)
+    testOffsetOf(AlignAtEnd, c)
+
+    testOffsetOf(SimpleBranch, a)
+    testOffsetOf(SimpleBranch, b)
+    testOffsetOf(SimpleBranch, c)
+
+    testOffsetOf(PaddingBeforeBranchA, cause)
+    testOffsetOf(PaddingBeforeBranchA, a)
+    testOffsetOf(PaddingBeforeBranchB, cause)
+    testOffsetOf(PaddingBeforeBranchB, a)
+
+    testOffsetOf(PaddingAfterBranch, a)
+    testOffsetOf(PaddingAfterBranch, cause)
+
+    testOffsetOf(Foobar, c)
+
+    testOffsetOf(PaddingOfSetEnum33, cause)
+    testOffsetOf(PaddingOfSetEnum33, theSet)
+
+    testOffsetOf(Bazing, a)
+    testOffsetOf(InheritanceA, a)
+    testOffsetOf(InheritanceB, b)
+    testOffsetOf(InheritanceC, c)
+
+    testOffsetOf(EnumObjectA, a)
+    testOffsetOf(EnumObjectA, b)
+    testOffsetOf(EnumObjectA, c)
+    testOffsetOf(EnumObjectA, d)
+    testOffsetOf(EnumObjectB, a)
+    testOffsetOf(EnumObjectB, b)
+    testOffsetOf(EnumObjectB, c)
+    testOffsetOf(EnumObjectB, d)
+
+    testOffsetOf(RecursiveStuff, kind)
+    testOffsetOf(RecursiveStuff, a)
+    testOffsetOf(RecursiveStuff, b)
+    testOffsetOf(RecursiveStuff, kind2)
+    testOffsetOf(RecursiveStuff, ca1)
+    testOffsetOf(RecursiveStuff, ca2)
+    testOffsetOf(RecursiveStuff, cb)
+    testOffsetOf(RecursiveStuff, cc)
+    testOffsetOf(RecursiveStuff, d1)
+    testOffsetOf(RecursiveStuff, d2)
+
+    testOffsetOf(MyCustomAlignPackedObject, a)
+    testOffsetOf(MyCustomAlignPackedObject, b)
+    testOffsetOf(MyCustomAlignPackedObject, c)
+    testOffsetOf(MyCustomAlignPackedObject, d)
+
+    echo "body executed" # sanity check to ensure this logic isn't skipped entirely
+
+
+  main()
+
+{.emit: """/*TYPESECTION*/
+typedef struct{
+  float a; float b;
+} Foo;
+""".}
+
+type
+  Foo {.importc.} = object
+
+  Bar = object
+    b: byte
+    foo: Foo
+
+assert sizeof(Bar) == 12
+
+# bug #10082
+type
+  A = int8        # change to int16 and get sizeof(C)==6
+  B = int16
+  C {.packed.} = object
+    d {.bitsize:  1.}: A
+    e {.bitsize:  7.}: A
+    f {.bitsize: 16.}: B
+
+assert sizeof(C) == 3
+
+
+type
+  MixedBitsize {.packed.} = object
+    a: uint32
+    b {.bitsize:  8.}: uint8
+    c {.bitsize:  1.}: uint8
+    d {.bitsize:  7.}: uint8
+    e {.bitsize: 16.}: uint16
+    f: uint32
+
+doAssert sizeof(MixedBitsize) == 12
+
+
+type
+  MyUnionType {.union.} = object
+    a: int32
+    b: float32
+
+  MyCustomAlignUnion {.union.} = object
+    c: char
+    a {.align: 32.}: int
+
+  MyCustomAlignObject = object
+    c: char
+    a {.align: 32.}: int
+
+doAssert sizeof(MyUnionType) == 4
+doAssert sizeof(MyCustomAlignUnion) == 32
+doAssert alignof(MyCustomAlignUnion) == 32
+doAssert sizeof(MyCustomAlignObject) == 64
+doAssert alignof(MyCustomAlignObject) == 32
+
+
+
+
+
+
+##########################################
+# bug #9794
+##########################################
+
+type
+  imported_double {.importc: "double".} = object
+
+  Pod = object
+    v* : imported_double
+    seed*: int32
+
+  Pod2 = tuple[v: imported_double, seed: int32]
+
+proc foobar() =
+  testAlign(Pod)
+  testSize(Pod)
+  testAlign(Pod2)
+  testSize(Pod2)
+  doAssert sizeof(Pod) == sizeof(Pod2)
+  doAssert alignof(Pod) == alignof(Pod2)
+foobar()
+
+if failed:
+  quit("FAIL")
+else:
+  echo "OK"
+
+##########################################
+# sizeof macros API
+##########################################
+
+import macros
+
+type
+  Vec2f = object
+    x,y: float32
+
+  Vec4f = object
+    x,y,z,w: float32
+
+  # this type is constructed to have no platform depended alignment.
+  ParticleDataA = object
+    pos, vel: Vec2f
+    birthday: float32
+    padding: float32
+    moreStuff: Vec4f
+
+const expected = [
+  # name size align offset
+  ("pos", 8, 4, 0),
+  ("vel", 8, 4, 8),
+  ("birthday", 4, 4, 16),
+  ("padding", 4, 4, 20),
+  ("moreStuff", 16, 4, 24)
+]
+
+macro typeProcessing(arg: typed): untyped =
+  let recList = arg.getTypeImpl[2]
+  recList.expectKind nnkRecList
+  for i, identDefs in recList:
+    identDefs.expectKind nnkIdentDefs
+    identDefs.expectLen 3
+    let sym = identDefs[0]
+    sym.expectKind nnkSym
+    doAssert expected[i][0] == sym.strVal
+    doAssert expected[i][1] == getSize(sym)
+    doAssert expected[i][2] == getAlign(sym)
+    doAssert expected[i][3] == getOffset(sym)
+
+  result = newCall(bindSym"echo", newLit("macros api OK"))
+
+proc main() =
+  var mylocal: ParticleDataA
+  typeProcessing(mylocal)
+
+main()
+
+# issue #11320 use UncheckedArray
+
+type
+  Payload = object
+    something: int8
+    vals: UncheckedArray[int32]
+
+proc payloadCheck() =
+  doAssert offsetOf(Payload, vals) == 4
+  doAssert sizeof(Payload) == 4
+
+payloadCheck()
+
+# offsetof tuple types
+
+type
+  MyTupleType = tuple
+    a: float64
+    b: float64
+    c: float64
+
+  MyOtherTupleType = tuple
+    a: float64
+    b: imported_double
+    c: float64
+
+  MyCaseObject = object
+    val1: imported_double
+    case kind: bool
+    of true:
+      val2,val3: float32
+    else:
+      val4,val5: int32
+
+doAssert offsetof(MyTupleType, a) == 0
+doAssert offsetof(MyTupleType, b) == 8
+doAssert offsetof(MyTupleType, c) == 16
+
+doAssert offsetof(MyOtherTupleType, a) == 0
+doAssert offsetof(MyOtherTupleType, b) == 8
+
+# The following expression can only work if the offsetof expression is
+# properly forwarded for the C code generator.
+doAssert offsetof(MyOtherTupleType, c) == 16
+doAssert offsetof(Bar, foo) == 4
+doAssert offsetof(MyCaseObject, val1) == 0
+doAssert offsetof(MyCaseObject, kind) == 8
+doAssert offsetof(MyCaseObject, val2) == 12
+doAssert offsetof(MyCaseObject, val3) == 16
+doAssert offsetof(MyCaseObject, val4) == 12
+doAssert offsetof(MyCaseObject, val5) == 16
+
+template reject(e) =
+  static: assert(not compiles(e))
+
+reject:
+  const off1 = offsetof(MyOtherTupleType, c)
+
+reject:
+  const off2 = offsetof(MyOtherTupleType, b)
+
+reject:
+  const off3 = offsetof(MyCaseObject, kind)
+
+
+type
+  MyPackedCaseObject {.packed.} = object
+    val1: imported_double
+    case kind: bool
+    of true:
+      val2,val3: float32
+    else:
+      val4,val5: int32
+
+# packed case object
+
+doAssert offsetof(MyPackedCaseObject, val1) == 0
+doAssert offsetof(MyPackedCaseObject, val2) == 9
+doAssert offsetof(MyPackedCaseObject, val3) == 13
+doAssert offsetof(MyPackedCaseObject, val4) == 9
+doAssert offsetof(MyPackedCaseObject, val5) == 13
+
+reject:
+  const off5 = offsetof(MyPackedCaseObject, val2)
+
+reject:
+  const off6 = offsetof(MyPackedCaseObject, val3)
+
+reject:
+  const off7 = offsetof(MyPackedCaseObject, val4)
+
+reject:
+  const off8 = offsetof(MyPackedCaseObject, val5)
+
+
+type
+  O0 = object
+  T0 = tuple[]
+
+doAssert sizeof(O0) == 1
+doAssert sizeof(T0) == 1
+
+
+type
+  # this thing may not have padding bytes at the end
+  PackedUnion* {.union, packed.} = object
+    a*: array[11, byte]
+    b*: int64
+
+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/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim
new file mode 100644
index 000000000..da28de508
--- /dev/null
+++ b/tests/misc/tsizeof2.nim
@@ -0,0 +1,17 @@
+discard """
+errormsg: "'sizeof' requires '.importc' types to be '.completeStruct'"
+line: 9
+"""
+
+type
+  MyStruct {.importc: "MyStruct".} = object
+
+const i = sizeof(MyStruct)
+
+echo i
+
+# bug #9868
+proc foo(a: SomeInteger): array[sizeof(a), byte] =
+  discard
+
+discard foo(1)
diff --git a/tests/misc/tsizeof3.nim b/tests/misc/tsizeof3.nim
new file mode 100644
index 000000000..f0ba8c4d0
--- /dev/null
+++ b/tests/misc/tsizeof3.nim
@@ -0,0 +1,58 @@
+discard """
+output: '''
+@[48, 57]
+'''
+"""
+# bug #7238
+
+type ByteArrayBE*[N: static[int]] = array[N, byte]
+  ## A byte array that stores bytes in big-endian order
+
+proc toByteArrayBE*[T: SomeInteger](num: T): ByteArrayBE[sizeof(T)]=
+  ## Convert an integer (in native host endianness) to a big-endian byte array
+  ## Notice the result type
+  const N = T.sizeof
+  for i in 0 ..< N:
+    result[i] = byte((num shr ((N-1-i) * 8)) and high(int8))
+
+let a = 12345.toByteArrayBE
+echo a[^2 .. ^1] # to make it work on both 32-bit and 64-bit
+
+#---------------------------------------------------------------------
+
+type
+  Payload = object
+    something: int
+    vals: UncheckedArray[int]
+
+static:
+  doAssert(compiles(offsetOf(Payload, vals)))
+
+
+type
+  GoodboySave* {.bycopy.} = object
+    saveCount: uint8
+    savePoint: uint16
+    shards: uint32
+    friendCount: uint8
+    friendCards: set[0..255]
+    locationsKnown: set[0..127]
+    locationsUnlocked: set[0..127]
+    pickupsObtained: set[0..127]
+    pickupsUsed: set[0..127]
+    pickupCount: uint8
+
+block: # bug #20914
+  block:
+    proc csizeof[T](a: T): int {.importc:"sizeof", nodecl.}
+
+    var s: GoodboySave
+    doAssert sizeof(s) == 108
+    doAssert csizeof(s) == static(sizeof(s))
+
+  block:
+    proc calignof[T](a: T): int {.importc:"alignof", header: "<stdalign.h>".}
+
+    var s: set[0..256]
+    doAssert alignof(s) == 1
+    doAssert calignof(s) == static(alignof(s))
diff --git a/tests/misc/tsizeof4.nim b/tests/misc/tsizeof4.nim
new file mode 100644
index 000000000..94c08ba39
--- /dev/null
+++ b/tests/misc/tsizeof4.nim
@@ -0,0 +1,20 @@
+discard """
+disabled: "arm64"
+"""
+
+# bug #11792
+type
+  m256d {.importc: "__m256d", header: "immintrin.h".} = object
+
+  MyKind = enum
+    k1, k2, k3
+
+  MyTypeObj = object
+    kind: MyKind
+    x: int
+    amount: UncheckedArray[m256d]
+
+
+# The sizeof(MyTypeObj) is not equal to (sizeof(int) + sizeof(MyKind)) due to
+# alignment requirement of m256d, make sure Nim understands that
+doAssert(sizeof(MyTypeObj) > sizeof(int) + sizeof(MyKind))
diff --git a/tests/misc/tsortdev.nim b/tests/misc/tsortdev.nim
new file mode 100644
index 000000000..6a290577b
--- /dev/null
+++ b/tests/misc/tsortdev.nim
@@ -0,0 +1,58 @@
+discard """
+  output: "done tsortdev"
+"""
+
+import algorithm, strutils
+
+proc cmpPlatforms(a, b: string): int =
+  if a == b: return 0
+  var dashes = a.split('-')
+  var dashes2 = b.split('-')
+  if dashes[0] == dashes2[0]:
+    if dashes[1] == dashes2[1]: return system.cmp(a,b)
+    case dashes[1]
+    of "x86":
+      return 1
+    of "x86_64":
+      if dashes2[1] == "x86": return -1
+      else: return 1
+    of "ppc64":
+      if dashes2[1] == "x86" or dashes2[1] == "x86_64": return -1
+      else: return 1
+    else:
+      return system.cmp(dashes[1], dashes2[1])
+  else:
+    case dashes[0]
+    of "linux":
+      return 1
+    of "windows":
+      if dashes2[0] == "linux": return -1
+      else: return 1
+    of "macosx":
+      if dashes2[0] == "linux" or dashes2[0] == "windows": return -1
+      else: return 1
+    else:
+      if dashes2[0] == "linux" or dashes2[0] == "windows" or
+         dashes2[0] == "macosx": return -1
+      else:
+        return system.cmp(a, b)
+
+proc sorted[T](a: openArray[T]): bool =
+  result = true
+  for i in 0 ..< a.high:
+    if cmpPlatforms(a[i], a[i+1]) > 0:
+      echo "Out of order: ", a[i], " ", a[i+1]
+      result = false
+
+proc main() =
+  var testData = @["netbsd-x86_64", "windows-x86", "linux-x86_64", "linux-x86",
+    "linux-ppc64", "macosx-x86-1058", "macosx-x86-1068"]
+
+  sort(testData, cmpPlatforms)
+
+  doAssert sorted(testData)
+
+for i in 0..1_000:
+  main()
+
+echo "done tsortdev"
diff --git a/tests/misc/tstrace.nim b/tests/misc/tstrace.nim
new file mode 100644
index 000000000..00af0af69
--- /dev/null
+++ b/tests/misc/tstrace.nim
@@ -0,0 +1,36 @@
+discard """
+exitcode: 1
+output: '''
+Traceback (most recent call last)
+tstrace.nim(36)          tstrace
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(28)          recTest
+tstrace.nim(31)          recTest
+SIGSEGV: Illegal storage access. (Attempt to read from nil?)
+'''
+"""
+
+# Test the new stacktraces (great for debugging!)
+
+{.push stack_trace: on.}
+
+proc recTest(i: int) =
+  # enter
+  if i < 10:
+    recTest(i+1)
+  else: # should printStackTrace()
+    var p: ptr int = nil
+    p[] = 12
+  # leave
+
+{.pop.}
+
+recTest(0)
diff --git a/tests/tstrange.nim b/tests/misc/tstrange.nim
index 13aab2302..f8c063240 100755..100644
--- a/tests/tstrange.nim
+++ b/tests/misc/tstrange.nim
@@ -1,17 +1,28 @@
-# test for extremely strange bug

-

-proc ack(x: int, y: int): int =

-  if x != 0:

-    if y != 5:

-      return y

-    return x

-  return x+y

-

-proc gen[T](a: T) =

-  write(stdout, a)

-

-

-gen("hallo")

-write(stdout, ack(5, 4))

-#OUT hallo4

-

+discard """
+output: '''
+hallo40
+1
+2
+'''
+"""
+# test for extremely strange bug
+
+proc ack(x: int, y: int): int =
+  if x != 0:
+    if y != 5:
+      return y
+    return x
+  return x+y
+
+proc gen[T](a: T) =
+  write(stdout, a)
+
+
+gen("hallo")
+write(stdout, ack(5, 4))
+#OUT hallo4
+
+# bug #1442
+let h=3
+for x in 0 ..< h.int:
+  echo x
diff --git a/tests/misc/tstrdesc.nim b/tests/misc/tstrdesc.nim
new file mode 100644
index 000000000..1479fcda8
--- /dev/null
+++ b/tests/misc/tstrdesc.nim
@@ -0,0 +1,14 @@
+var
+  x: array[0..2, int]
+
+x = [0, 1, 2]
+
+type
+  TStringDesc {.final.} = object
+    len, space: int # len and space without counting the terminating zero
+    data: array[0..0, char] # for the '\0' character
+
+var
+  emptyString {.exportc: "emptyString".}: TStringDesc
+
+
diff --git a/tests/tstrdist.nim b/tests/misc/tstrdist.nim
index 3e1939e73..53ace2fae 100755..100644
--- a/tests/tstrdist.nim
+++ b/tests/misc/tstrdist.nim
@@ -23,4 +23,4 @@ proc editDistance(a, b: string): int =
       c[(i-1)*n + (j-1)] = min(x,min(y,z))
   return c[n*m]
 
-write(stdout, editDistance("abc", "abd"))
+doAssert editDistance("abc", "abd") == 3
diff --git a/tests/misc/ttlsemulation.nim b/tests/misc/ttlsemulation.nim
new file mode 100644
index 000000000..767a9bd4e
--- /dev/null
+++ b/tests/misc/ttlsemulation.nim
@@ -0,0 +1,76 @@
+discard """
+  disabled: i386
+  matrix: "-d:nimTtlsemulationCase1 --threads --tlsEmulation:on; -d:nimTtlsemulationCase2 --threads --tlsEmulation:off; -d:nimTtlsemulationCase3 --threads"
+  targets: "c cpp"
+"""
+
+#[
+tests for: `.cppNonPod`, `--tlsEmulation`
+]#
+
+import std/sugar
+
+block:
+  # makes sure the logic in config/nim.cfg or testament doesn't interfere with `--tlsEmulation` so we test the right thing.
+  when defined(nimTtlsemulationCase1):
+    doAssert compileOption("tlsEmulation")
+  elif defined(nimTtlsemulationCase2):
+    doAssert not compileOption("tlsEmulation")
+  elif defined(nimTtlsemulationCase3):
+    when defined(osx):
+      doAssert not compileOption("tlsEmulation")
+  else:
+    doAssert false
+
+block:
+  proc main1(): int =
+    var g0 {.threadvar.}: int
+    g0.inc
+    g0
+  let s = collect:
+    for i in 0..<3: main1()
+  doAssert s == @[1,2,3]
+
+when defined(cpp): # bug #16752
+  when defined(windows) and defined(nimTtlsemulationCase2):
+    discard # xxx this failed with exitCode 1
+  else:
+    type Foo1 {.importcpp: "Foo1", header: "mtlsemulation.h".} = object
+      x: cint
+    type Foo2 {.cppNonPod, importcpp: "Foo2", header: "mtlsemulation.h".} = object
+      x: cint
+
+    var ctorCalls {.importcpp.}: cint
+    var dtorCalls {.importcpp.}: cint
+    type Foo3 {.cppNonPod, importcpp: "Foo3", header: "mtlsemulation.h".} = object
+      x: cint
+
+    proc sub(i: int) =
+      var g1 {.threadvar.}: Foo1
+      var g2 {.threadvar.}: Foo2
+      var g3 {.threadvar.}: Foo3
+      discard g1
+      discard g2
+
+      # echo (g3.x, ctorCalls, dtorCalls)
+      when compileOption("tlsEmulation"):
+        # xxx bug
+        discard
+      else:
+        doAssert g3.x.int == 10 + i
+        doAssert ctorCalls == 2
+      doAssert dtorCalls == 1
+      g3.x.inc
+
+    proc main() =
+      doAssert ctorCalls == 0
+      doAssert dtorCalls == 0
+      block:
+        var f3: Foo3
+        doAssert f3.x == 10
+      doAssert ctorCalls == 1
+      doAssert dtorCalls == 1
+
+      for i in 0..<3:
+        sub(i)
+    main()
diff --git a/tests/misc/tvarious.nim b/tests/misc/tvarious.nim
new file mode 100644
index 000000000..191107a87
--- /dev/null
+++ b/tests/misc/tvarious.nim
@@ -0,0 +1,72 @@
+discard """
+action: compile
+"""
+
+# Test various aspects
+
+# bug #572
+var a=12345678901'u64
+
+var x = (x: 42, y: (a: 8, z: 10))
+echo x.y
+
+import
+  mvarious
+
+type
+  PA = ref TA
+  PB = ref TB
+
+  TB = object
+    a: PA
+
+  TA = object
+    b: TB
+    x: int
+
+proc getPA(): PA =
+  var
+    b: bool
+  b = not false
+  return nil
+
+# bug #501
+proc f(): int = 54
+
+var
+  global: int
+
+var
+  s: string
+  i: int
+  r: TA
+
+r.b.a.x = 0
+global = global + 1
+exportme()
+write(stdout, "Hallo wie heißt du? ")
+write(stdout, getPA().x)
+s = readLine(stdin)
+i = 0
+while i < s.len:
+  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")
+  i = i + 1
+
+write(stdout, "Du heißt " & s)
+
+# bug #544
+
+# yay, fails again
+type Bar [T; I:range] = array[I, T]
+proc foo*[T; I:range](a, b: Bar[T, I]): Bar[T, I] =
+  when len(a) != 3:
+    # Error: constant expression expected
+    {.fatal:"Dimensions have to be 3".}
+  #...
+block:
+  var a, b: Bar[int, range[0..2]]
+  discard foo(a, b)
+
+# bug #1788
+
+echo "hello" & char(ord(' ')) & "world"
diff --git a/tests/misc/tvarious1.nim b/tests/misc/tvarious1.nim
new file mode 100644
index 000000000..9c912ee8e
--- /dev/null
+++ b/tests/misc/tvarious1.nim
@@ -0,0 +1,58 @@
+discard """
+output: '''
+1
+0
+Whopie
+12
+1.7'''
+"""
+
+echo len([1_000_000]) #OUT 1
+
+type
+  TArray = array[0..3, int]
+  TVector = distinct array[0..3, int]
+proc `[]`(v: TVector; idx: int): int = TArray(v)[idx]
+var v: TVector
+echo v[2]
+
+# bug #569
+
+import deques
+
+type
+  TWidget = object
+    names: Deque[string]
+
+var w = TWidget(names: initDeque[string]())
+
+addLast(w.names, "Whopie")
+
+for n in w.names: echo(n)
+
+# bug #681
+
+type TSomeRange = object
+  hour: range[0..23]
+
+var value: string
+var val12 = TSomeRange(hour: 12)
+
+value = $(if val12.hour > 12: val12.hour - 12 else: val12.hour)
+echo value
+
+# bug #1334
+
+var ys = @[4.1, 5.6, 7.2, 1.7, 9.3, 4.4, 3.2]
+#var x = int(ys.high / 2) #echo ys[x] # Works
+echo ys[int(ys.high / 2)] # Doesn't work
+
+
+# bug #19680
+var here = ""
+when stderr is static:
+  doAssert false
+else:
+  here = "works"
+
+doAssert here == "works"
diff --git a/tests/tvarnums.nim b/tests/misc/tvarnums.nim
index 1b683ad94..498099c49 100755..100644
--- a/tests/tvarnums.nim
+++ b/tests/misc/tvarnums.nim
@@ -1,136 +1,139 @@
-# Test variable length binary integers

-

-import

-  strutils

-

-type

-  TBuffer = array [0..10, int8]

-

-proc toVarNum(x: int32, b: var TBuffer) =

-  # encoding: first bit indicates end of number (0 if at end)

-  # second bit of the first byte denotes the sign (1 --> negative)

-  var a = x

-  if x != low(x):

-    # low(int) is a special case,

-    # because abs() does not work here!

-    # we leave x as it is and use the check >% instead of >

-    # for low(int) this is needed and positive numbers are not affected

-    # anyway

-    a = abs(x)

-  # first 6 bits:

-  b[0] = toU8(ord(a >% 63'i32) shl 7 or (ord(x < 0'i32) shl 6) or (int(a) and 63))

-  a = a shr 6'i32 # skip first 6 bits

-  var i = 1

-  while a != 0'i32:

-    b[i] = toU8(ord(a >% 127'i32) shl 7 or (int(a) and 127))

-    inc(i)

-    a = a shr 7'i32

-

-proc toVarNum64(x: int64, b: var TBuffer) =

-  # encoding: first bit indicates end of number (0 if at end)

-  # second bit of the first byte denotes the sign (1 --> negative)

-  var a = x

-  if x != low(x):

-    # low(int) is a special case,

-    # because abs() does not work here!

-    # we leave x as it is and use the check >% instead of >

-    # for low(int) this is needed and positive numbers are not affected

-    # anyway

-    a = abs(x)

-  # first 6 bits:

-  b[0] = toU8(ord(a >% 63'i64) shl 7 or (ord(x < 0'i64) shl 6) or int(a and 63))

-  a = a shr 6 # skip first 6 bits

-  var i = 1

-  while a != 0'i64:

-    b[i] = toU8(ord(a >% 127'i64) shl 7 or int(a and 127))

-    inc(i)

-    a = a shr 7

-

-proc toNum64(b: TBuffer): int64 =

-  # treat first byte different:

-  result = ze64(b[0]) and 63

-  var

-    i = 0

-    Shift = 6'i64

-  while (ze(b[i]) and 128) != 0:

-    inc(i)

-    result = result or ((ze64(b[i]) and 127) shl Shift)

-    inc(Shift, 7)

-  if (ze(b[0]) and 64) != 0: # sign bit set?

-    result = not result +% 1

-    # this is the same as ``- result``

-    # but gives no overflow error for low(int)

-

-proc toNum(b: TBuffer): int32 =

-  # treat first byte different:

-  result = ze(b[0]) and 63

-  var

-    i = 0

-    Shift = 6'i32

-  while (ze(b[i]) and 128) != 0:

-    inc(i)

-    result = result or ((int32(ze(b[i])) and 127'i32) shl Shift)

-    Shift = shift + 7'i32

-  if (ze(b[0]) and (1 shl 6)) != 0: # sign bit set?

-    result = (not result) +% 1'i32

-    # this is the same as ``- result``

-    # but gives no overflow error for low(int)

-

-proc toBinary(x: int64): string =

-  result = newString(64)

-  for i in 0..63:

-    result[63-i] = chr((int(x shr i) and 1) + ord('0'))

-

-proc t64(i: int64) =

-  var

-    b: TBuffer

-  toVarNum64(i, b)

-  var x = toNum64(b)

-  if x != i:

-    writeln(stdout, $i)

-    writeln(stdout, toBinary(i))

-    writeln(stdout, toBinary(x))

-

-proc t32(i: int32) =

-  var

-    b: TBuffer

-  toVarNum(i, b)

-  var x = toNum(b)

-  if x != i:

-    writeln(stdout, toBinary(i))

-    writeln(stdout, toBinary(x))

-

-proc tm(i: int32) =

-  var

-    b: TBuffer

-  toVarNum64(i, b)

-  var x = toNum(b)

-  if x != i:

-    writeln(stdout, toBinary(i))

-    writeln(stdout, toBinary(x))

-

-t32(0)

-t32(1)

-t32(-1)

-t32(-100_000)

-t32(100_000)

-t32(low(int32))

-t32(high(int32))

-

-t64(low(int64))

-t64(high(int64))

-t64(0)

-t64(-1)

-t64(1)

-t64(1000_000)

-t64(-1000_000)

-

-tm(0)

-tm(1)

-tm(-1)

-tm(-100_000)

-tm(100_000)

-tm(low(int32))

-tm(high(int32))

-

-writeln(stdout, "Success!") #OUT Success!

+discard """
+  output: "Success!"
+"""
+# Test variable length binary integers
+
+import
+  strutils
+
+type
+  TBuffer = array[0..10, uint8]
+
+proc toVarNum(x: int32, b: var TBuffer) =
+  # encoding: first bit indicates end of number (0 if at end)
+  # second bit of the first byte denotes the sign (1 --> negative)
+  var a = x
+  if x != low(x):
+    # low(int) is a special case,
+    # because abs() does not work here!
+    # we leave x as it is and use the check >% instead of >
+    # for low(int) this is needed and positive numbers are not affected
+    # anyway
+    a = abs(x)
+  # first 6 bits:
+  b[0] = uint8(ord(a >% 63'i32) shl 7 or (ord(x < 0'i32) shl 6) or (int(a) and 63))
+  a = (a shr 6'i32) and 0x03ffffff # skip first 6 bits
+  var i = 1
+  while a != 0'i32:
+    b[i] = uint8(ord(a >% 127'i32) shl 7 or (int(a) and 127))
+    inc(i)
+    a = a shr 7'i32
+
+proc toVarNum64(x: int64, b: var TBuffer) =
+  # encoding: first bit indicates end of number (0 if at end)
+  # second bit of the first byte denotes the sign (1 --> negative)
+  var a = x
+  if x != low(x):
+    # low(int) is a special case,
+    # because abs() does not work here!
+    # we leave x as it is and use the check >% instead of >
+    # for low(int) this is needed and positive numbers are not affected
+    # anyway
+    a = abs(x)
+  # first 6 bits:
+  b[0] = uint8(ord(a >% 63'i64) shl 7 or (ord(x < 0'i64) shl 6) or int(a and 63))
+  a = (a shr 6) and 0x03ffffffffffffff # skip first 6 bits
+  var i = 1
+  while a != 0'i64:
+    b[i] = uint8(ord(a >% 127'i64) shl 7 or int(a and 127))
+    inc(i)
+    a = a shr 7
+
+proc toNum64(b: TBuffer): int64 =
+  # treat first byte different:
+  result = int64(b[0]) and 63
+  var
+    i = 0
+    Shift = 6'i64
+  while (int(b[i]) and 128) != 0:
+    inc(i)
+    result = result or ((int64(b[i]) and 127) shl Shift)
+    inc(Shift, 7)
+  if (int(b[0]) and 64) != 0: # sign bit set?
+    result = not result +% 1
+    # this is the same as ``- result``
+    # but gives no overflow error for low(int)
+
+proc toNum(b: TBuffer): int32 =
+  # treat first byte different:
+  result = int32(b[0]) and 63
+  var
+    i = 0
+    Shift = 6'i32
+  while (int(b[i]) and 128) != 0:
+    inc(i)
+    result = result or ((int32(b[i]) and 127'i32) shl Shift)
+    Shift = Shift + 7'i32
+  if (int(b[0]) and (1 shl 6)) != 0: # sign bit set?
+    result = (not result) +% 1'i32
+    # this is the same as ``- result``
+    # but gives no overflow error for low(int)
+
+proc toBinary(x: int64): string =
+  result = newString(64)
+  for i in 0..63:
+    result[63-i] = chr((int(x shr i) and 1) + ord('0'))
+
+proc t64(i: int64) =
+  var
+    b: TBuffer
+  toVarNum64(i, b)
+  var x = toNum64(b)
+  if x != i:
+    writeLine(stdout, $i)
+    writeLine(stdout, toBinary(i))
+    writeLine(stdout, toBinary(x))
+
+proc t32(i: int32) =
+  var
+    b: TBuffer
+  toVarNum(i, b)
+  var x = toNum(b)
+  if x != i:
+    writeLine(stdout, toBinary(i))
+    writeLine(stdout, toBinary(x))
+
+proc tm(i: int32) =
+  var
+    b: TBuffer
+  toVarNum64(i, b)
+  var x = toNum(b)
+  if x != i:
+    writeLine(stdout, toBinary(i))
+    writeLine(stdout, toBinary(x))
+
+t32(0)
+t32(1)
+t32(-1)
+t32(-100_000)
+t32(100_000)
+t32(low(int32))
+t32(high(int32))
+
+t64(low(int64))
+t64(high(int64))
+t64(0)
+t64(-1)
+t64(1)
+t64(1000_000)
+t64(-1000_000)
+
+tm(0)
+tm(1)
+tm(-1)
+tm(-100_000)
+tm(100_000)
+tm(low(int32))
+tm(high(int32))
+
+writeLine(stdout, "Success!") #OUT Success!
diff --git a/tests/misc/tvcc.nim b/tests/misc/tvcc.nim
new file mode 100644
index 000000000..10533729c
--- /dev/null
+++ b/tests/misc/tvcc.nim
@@ -0,0 +1,9 @@
+discard """
+  matrix: "--cc:vcc"
+  disabled: "linux"
+  disabled: "bsd"
+  disabled: "osx"
+  disabled: "unix"
+  disabled: "posix"
+"""
+doAssert true
diff --git a/tests/misc/åäö.nim b/tests/misc/åäö.nim
new file mode 100644
index 000000000..b3caa9861
--- /dev/null
+++ b/tests/misc/åäö.nim
@@ -0,0 +1,11 @@
+discard """
+    action: run
+"""
+
+# Tests that module names can contain multi byte characters
+
+let a = 1
+doAssert åäö.a == 1
+
+proc inlined() {.inline.} = discard
+inlined()
\ No newline at end of file
diff --git a/tests/mmaptest.nim b/tests/mmaptest.nim
new file mode 100644
index 000000000..33010606f
--- /dev/null
+++ b/tests/mmaptest.nim
@@ -0,0 +1,36 @@
+# Small test program to test for mmap() weirdnesses
+
+import system/ansi_c
+import posix
+
+proc osAllocPages(size: int): pointer {.inline.} =
+  result = mmap(nil, size, PROT_READ or PROT_WRITE,
+                         MAP_PRIVATE or MAP_ANONYMOUS, -1, 0)
+  if result == nil or result == cast[pointer](-1):
+    quit 1
+  cfprintf(c_stdout, "allocated pages %p..%p\n", result,
+                     cast[int](result) + size)
+
+proc osDeallocPages(p: pointer, size: int) {.inline} =
+  cfprintf(c_stdout, "freed pages %p..%p\n", p, cast[int](p) + size)
+  discard munmap(p, size-1)
+
+proc `+!!`(p: pointer, size: int): pointer {.inline.} =
+  result = cast[pointer](cast[int](p) + size)
+
+const
+  PageShift = when defined(nimPage256) or defined(cpu16): 8
+              elif defined(nimPage512): 9
+              elif defined(nimPage1k): 10
+              else: 12 # \ # my tests showed no improvements for using larger page sizes.
+
+  PageSize = 1 shl PageShift
+
+var p = osAllocPages(3 * PageSize)
+
+osDeallocPages(p, PageSize)
+# If this fails the OS has freed the whole block starting at 'p':
+echo(cast[ptr int](p +!! (PageSize*2))[])
+
+osDeallocPages(p +!! PageSize*2, PageSize)
+osDeallocPages(p +!! PageSize, PageSize)
diff --git a/tests/modules/UpperCased.nim b/tests/modules/UpperCased.nim
new file mode 100644
index 000000000..7beffcc5f
--- /dev/null
+++ b/tests/modules/UpperCased.nim
@@ -0,0 +1,6 @@
+
+# bug #5076
+
+var str*: string
+
+UpperCased.str = "hello"
diff --git a/tests/modules/a/module_name_clashes.nim b/tests/modules/a/module_name_clashes.nim
new file mode 100644
index 000000000..209526e22
--- /dev/null
+++ b/tests/modules/a/module_name_clashes.nim
@@ -0,0 +1,8 @@
+# See `tmodule_name_clashes`
+
+import ../b/module_name_clashes
+type A* = object
+  b*: B
+
+proc print*(a: A) =
+  echo repr a
diff --git a/tests/modules/a/utils.nim b/tests/modules/a/utils.nim
new file mode 100644
index 000000000..f37abfb93
--- /dev/null
+++ b/tests/modules/a/utils.nim
@@ -0,0 +1,2 @@
+proc burnMem*(a: int) =
+  discard
diff --git a/tests/modules/b/module_name_clashes.nim b/tests/modules/b/module_name_clashes.nim
new file mode 100644
index 000000000..6a10cac33
--- /dev/null
+++ b/tests/modules/b/module_name_clashes.nim
@@ -0,0 +1,3 @@
+# See `tmodule_name_clashes`
+
+type B* = object
diff --git a/tests/modules/b/utils.nim b/tests/modules/b/utils.nim
new file mode 100644
index 000000000..e343385f5
--- /dev/null
+++ b/tests/modules/b/utils.nim
@@ -0,0 +1,2 @@
+# module b/utils.nim
+let x* = 10
diff --git a/tests/modules/definitions.nim b/tests/modules/definitions.nim
new file mode 100644
index 000000000..edc6eaa6d
--- /dev/null
+++ b/tests/modules/definitions.nim
@@ -0,0 +1,4 @@
+var v*: int
+proc p* = echo "proc p called"
+template t* = echo "template t expanded"
+
diff --git a/tests/modules/m9627/a.nim b/tests/modules/m9627/a.nim
new file mode 100644
index 000000000..0dd32430e
--- /dev/null
+++ b/tests/modules/m9627/a.nim
@@ -0,0 +1 @@
+var a = 10
diff --git a/tests/modules/m9627/b.nim b/tests/modules/m9627/b.nim
new file mode 100644
index 000000000..2806a78ed
--- /dev/null
+++ b/tests/modules/m9627/b.nim
@@ -0,0 +1 @@
+var b = 9
diff --git a/tests/modules/mexport2a.nim b/tests/modules/mexport2a.nim
new file mode 100644
index 000000000..3cf84337e
--- /dev/null
+++ b/tests/modules/mexport2a.nim
@@ -0,0 +1,7 @@
+
+import mexport2b
+export mexport2b
+proc printAbc*() = echo "abc"
+
+proc foo*() = echo "A.foo"
+
diff --git a/tests/modules/mexport2b.nim b/tests/modules/mexport2b.nim
new file mode 100644
index 000000000..1af034133
--- /dev/null
+++ b/tests/modules/mexport2b.nim
@@ -0,0 +1,3 @@
+proc printXyz*() = echo "xyz"
+
+proc foo*(x: int) = echo "B.foo"
diff --git a/tests/modules/mexporta.nim b/tests/modules/mexporta.nim
new file mode 100644
index 000000000..b7d4ddec9
--- /dev/null
+++ b/tests/modules/mexporta.nim
@@ -0,0 +1,8 @@
+# module A
+import mexportb
+export mexportb.TMyObject, mexportb.xyz
+
+export mexportb.q
+
+proc `$`*(x: TMyObject): string = "my object"
+
diff --git a/tests/modules/mexportb.nim b/tests/modules/mexportb.nim
new file mode 100644
index 000000000..10d89f388
--- /dev/null
+++ b/tests/modules/mexportb.nim
@@ -0,0 +1,7 @@
+# module B
+type TMyObject* = object
+
+const xyz* = 13
+
+proc q*(x: int): int = 6
+proc q*(x: string): string = "8"
diff --git a/tests/modules/mforwarded_pure_enum.nim b/tests/modules/mforwarded_pure_enum.nim
new file mode 100644
index 000000000..3f03390a5
--- /dev/null
+++ b/tests/modules/mforwarded_pure_enum.nim
@@ -0,0 +1,3 @@
+
+import mforwarded_pure_enum2
+export mforwarded_pure_enum2.PureEnum
diff --git a/tests/modules/mforwarded_pure_enum2.nim b/tests/modules/mforwarded_pure_enum2.nim
new file mode 100644
index 000000000..e5d5d2a71
--- /dev/null
+++ b/tests/modules/mforwarded_pure_enum2.nim
@@ -0,0 +1,4 @@
+
+type
+  PureEnum* {.pure.} = enum
+    x, y, z
diff --git a/tests/modules/mimport_in_config.nim b/tests/modules/mimport_in_config.nim
new file mode 100644
index 000000000..555b6074d
--- /dev/null
+++ b/tests/modules/mimport_in_config.nim
@@ -0,0 +1,2 @@
+type
+  DefinedInB* = int
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/mmodule_same_proc.nim b/tests/modules/mmodule_same_proc.nim
new file mode 100644
index 000000000..5ce56ec11
--- /dev/null
+++ b/tests/modules/mmodule_same_proc.nim
@@ -0,0 +1,6 @@
+
+# the module being the same name as the proc
+# is a requirement to trigger the error
+import mmodule_same_proc_client
+
+proc bar*[T](foo: T): bool = foo.mmodule_same_proc_client()
diff --git a/tests/modules/mmodule_same_proc_client.nim b/tests/modules/mmodule_same_proc_client.nim
new file mode 100644
index 000000000..e36ec42cf
--- /dev/null
+++ b/tests/modules/mmodule_same_proc_client.nim
@@ -0,0 +1,2 @@
+
+proc mmodule_same_proc_client*(x: string): bool = x.len > 0
diff --git a/tests/mnamspc1.nim b/tests/modules/mnamspc1.nim
index da13c5f24..91f4d1566 100755..100644
--- a/tests/mnamspc1.nim
+++ b/tests/modules/mnamspc1.nim
@@ -1,2 +1,2 @@
-import mnamspc2

-

+import mnamspc2
+
diff --git a/tests/mnamspc2.nim b/tests/modules/mnamspc2.nim
index 84ef8533e..899ef27ea 100755..100644
--- a/tests/mnamspc2.nim
+++ b/tests/modules/mnamspc2.nim
@@ -1,3 +1,3 @@
-# export an identifier:

-var

-  global*: int

+# export an identifier:
+var
+  global*: int
diff --git a/tests/modules/mnotuniquename.nim b/tests/modules/mnotuniquename.nim
new file mode 100644
index 000000000..54d5883cd
--- /dev/null
+++ b/tests/modules/mnotuniquename.nim
@@ -0,0 +1 @@
+proc flat*() = echo "flat"
diff --git a/tests/mopaque.nim b/tests/modules/mopaque.nim
index b7c5180fd..2129bdaf2 100755..100644
--- a/tests/mopaque.nim
+++ b/tests/modules/mopaque.nim
@@ -1,5 +1,7 @@
-type

-  TLexer* {.final.} = object

-    line*: int

-    filename*: string

-    buffer: cstring

+type
+  TLexer* {.final.} = object
+    line*: int
+    filename*: string
+    buffer: cstring
+
+proc noProcVar*(): int = 18
diff --git a/tests/modules/morder_depa.nim b/tests/modules/morder_depa.nim
new file mode 100644
index 000000000..846fb1441
--- /dev/null
+++ b/tests/modules/morder_depa.nim
@@ -0,0 +1,5 @@
+
+import morder_depb
+
+proc Foo*(x: int): Foo = discard
+
diff --git a/tests/modules/morder_depb.nim b/tests/modules/morder_depb.nim
new file mode 100644
index 000000000..b77bc5acb
--- /dev/null
+++ b/tests/modules/morder_depb.nim
@@ -0,0 +1 @@
+type Foo* = array[2, byte]
diff --git a/tests/modules/mrange.nim b/tests/modules/mrange.nim
new file mode 100644
index 000000000..20c424a8c
--- /dev/null
+++ b/tests/modules/mrange.nim
@@ -0,0 +1,5 @@
+
+proc range*() = echo "yo"
+
+proc set*(a: int) =
+  discard
diff --git a/tests/mrecmod.nim b/tests/modules/mrecmod.nim
index fab9654d5..ce8fa3d64 100755..100644
--- a/tests/mrecmod.nim
+++ b/tests/modules/mrecmod.nim
@@ -1 +1 @@
-import trecmod

+import trecmod
diff --git a/tests/mrecmod2.nim b/tests/modules/mrecmod2.nim
index 9557ce729..31fac6e4d 100755..100644
--- a/tests/mrecmod2.nim
+++ b/tests/modules/mrecmod2.nim
@@ -1,9 +1,9 @@
 # Module B
-import trecmod2  
+import trecmod2
 
 proc p*(x: trecmod2.T1): trecmod2.T1 =
   # this works because the compiler has already
   # added T1 to trecmod2's interface symbol table
   return x + 1
-  
+
 
diff --git a/tests/modules/proxy_module.nim b/tests/modules/proxy_module.nim
new file mode 100644
index 000000000..c244688cd
--- /dev/null
+++ b/tests/modules/proxy_module.nim
@@ -0,0 +1,3 @@
+import definitions
+export definitions except p
+
diff --git a/tests/modules/seq.nim b/tests/modules/seq.nim
new file mode 100644
index 000000000..176e44025
--- /dev/null
+++ b/tests/modules/seq.nim
@@ -0,0 +1,5 @@
+var seq: seq[int]
+var b: seq[float]
+
+echo seq
+echo b
diff --git a/tests/modules/t8665.nim b/tests/modules/t8665.nim
new file mode 100644
index 000000000..74d31452f
--- /dev/null
+++ b/tests/modules/t8665.nim
@@ -0,0 +1,5 @@
+discard """
+  action: compile
+"""
+
+import treorder
diff --git a/tests/modules/t9627.nim b/tests/modules/t9627.nim
new file mode 100644
index 000000000..daba46374
--- /dev/null
+++ b/tests/modules/t9627.nim
@@ -0,0 +1,7 @@
+discard """
+  output: "109"
+"""
+
+include m9627 / [a, b]
+
+echo a, b
diff --git a/tests/modules/tambig_range.nim b/tests/modules/tambig_range.nim
new file mode 100644
index 000000000..e1ecc0013
--- /dev/null
+++ b/tests/modules/tambig_range.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "ambiguous identifier: 'range' -- use one of the following:"
+  line: "13"
+"""
+
+import mrange
+
+# bug #6965
+type SomeObj = object
+  s: set[int8]
+
+# bug #6726
+range()
diff --git a/tests/modules/tcanimport.nim b/tests/modules/tcanimport.nim
new file mode 100644
index 000000000..bc4e2e53f
--- /dev/null
+++ b/tests/modules/tcanimport.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''ABC
+nope'''
+"""
+
+template canImport(x): bool =
+  compiles:
+    import x
+
+when canImport(strutils):
+  import strutils
+  echo "abc".toUpperAscii
+else:
+  echo "meh"
+
+when canImport(none):
+  echo "what"
+else:
+  echo "nope"
diff --git a/tests/modules/texplicit_system_import.nim b/tests/modules/texplicit_system_import.nim
new file mode 100644
index 000000000..0a4cedc71
--- /dev/null
+++ b/tests/modules/texplicit_system_import.nim
@@ -0,0 +1,9 @@
+import system except `+`
+
+discard """
+  errormsg: "undeclared identifier: '+'"
+  line: 9
+"""
+
+
+echo 4+5
diff --git a/tests/modules/texport.nim b/tests/modules/texport.nim
new file mode 100644
index 000000000..a8c217ab8
--- /dev/null
+++ b/tests/modules/texport.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "my object68"
+"""
+
+import mexporta
+
+# bug #1029:
+from nativesockets import accept
+
+# B.TMyObject has been imported implicitly here:
+var x: TMyObject
+echo($x, q(0), q"0")
+
diff --git a/tests/modules/texport2.nim b/tests/modules/texport2.nim
new file mode 100644
index 000000000..e90c58673
--- /dev/null
+++ b/tests/modules/texport2.nim
@@ -0,0 +1,18 @@
+discard """
+output: '''
+abc
+xyz
+B.foo
+'''
+"""
+
+# bug #1595, #1612
+
+import mexport2a
+
+proc main() =
+  printAbc()
+  printXyz()
+
+main()
+foo(3)
diff --git a/tests/modules/tfowarded_pure_enum.nim b/tests/modules/tfowarded_pure_enum.nim
new file mode 100644
index 000000000..1d2c4f342
--- /dev/null
+++ b/tests/modules/tfowarded_pure_enum.nim
@@ -0,0 +1,7 @@
+discard """
+  output: '''z'''
+"""
+
+import mforwarded_pure_enum as t2
+
+echo z
diff --git a/tests/modules/timport_in_config.nim b/tests/modules/timport_in_config.nim
new file mode 100644
index 000000000..847b063bd
--- /dev/null
+++ b/tests/modules/timport_in_config.nim
@@ -0,0 +1,9 @@
+discard """
+output: '''hallo'''
+joinable: false
+"""
+
+# bug #9978, #9994
+var x: DefinedInB
+
+echo "hi".replace("i", "allo")
diff --git a/tests/modules/timport_in_config.nim.cfg b/tests/modules/timport_in_config.nim.cfg
new file mode 100644
index 000000000..2633e1012
--- /dev/null
+++ b/tests/modules/timport_in_config.nim.cfg
@@ -0,0 +1,2 @@
+--import: "strutils"
+--import: "mimport_in_config"
diff --git a/tests/modules/timportas.nim b/tests/modules/timportas.nim
new file mode 100644
index 000000000..179613c6b
--- /dev/null
+++ b/tests/modules/timportas.nim
@@ -0,0 +1,21 @@
+discard """
+    action: run
+"""
+
+import .. / modules / [mexporta as a1, definitions as foo1]
+import .. / modules / definitions as foo2
+import ./[mexporta as a2, definitions as foo3]
+import std / times as bar
+from times as bar2 import nil
+import times as bar3 except convert
+import definitions as baz
+
+discard foo1.v
+discard foo2.v
+discard foo3.v
+discard bar.now()
+discard bar2.now()
+discard bar3.now()
+discard baz.v
+discard a1.xyz
+discard a2.xyz
diff --git a/tests/modules/timportexcept.nim b/tests/modules/timportexcept.nim
new file mode 100644
index 000000000..40b748088
--- /dev/null
+++ b/tests/modules/timportexcept.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "undeclared identifier: '%'"
+  line: 9
+"""
+
+import strutils except `%`
+
+# doesn't work
+echo "$1" % "abc"
diff --git a/tests/modules/tincludeas.nim b/tests/modules/tincludeas.nim
new file mode 100644
index 000000000..b82e38b14
--- /dev/null
+++ b/tests/modules/tincludeas.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "Cannot use 'as' in 'include'."
+  line: 6
+"""
+
+include foobar as foo
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/tmismatchedvisibility.nim b/tests/modules/tmismatchedvisibility.nim
new file mode 100644
index 000000000..b649a5a3e
--- /dev/null
+++ b/tests/modules/tmismatchedvisibility.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "public implementation 'tmismatchedvisibility.foo(a: int)' has non-public forward declaration at "
+  line: 8
+"""
+
+proc foo(a: int): int
+
+proc foo*(a: int): int =
+  result = a + a
diff --git a/tests/modules/tmodule_name_clashes.nim b/tests/modules/tmodule_name_clashes.nim
new file mode 100644
index 000000000..814d5d152
--- /dev/null
+++ b/tests/modules/tmodule_name_clashes.nim
@@ -0,0 +1,17 @@
+discard """
+matrix: "--mm:refc"
+targets: "c"
+ccodecheck: "\\i @('atmaatsmodule_name_clashesdotnim_DatInit000')"
+ccodecheck: "\\i @('atmbatsmodule_name_clashesdotnim_DatInit000')"
+joinable: false
+"""
+
+# Test module name clashes within same package.
+# This was created to test that module symbol mangling functioned correctly
+# for the C backend when there are one or more modules with the same name in
+# a package, and more than one of them require module initialization procs.
+# I'm not sure of the simplest method to cause the init procs to be generated.
+
+import a/module_name_clashes
+
+print A()
diff --git a/tests/modules/tmodule_same_proc.nim b/tests/modules/tmodule_same_proc.nim
new file mode 100644
index 000000000..dc4dfd3d6
--- /dev/null
+++ b/tests/modules/tmodule_same_proc.nim
@@ -0,0 +1,9 @@
+
+import mmodule_same_proc
+
+# importing baz causes the error not to trigger
+#import baz
+
+# bug #11188
+
+discard "foo".bar()
diff --git a/tests/modules/tmodulesymtype.nim b/tests/modules/tmodulesymtype.nim
new file mode 100644
index 000000000..d17c4cca4
--- /dev/null
+++ b/tests/modules/tmodulesymtype.nim
@@ -0,0 +1,22 @@
+discard """
+cmd: "nim check $file"
+"""
+
+# bug #19225
+import std/sequtils
+sequtils #[tt.Error
+^ expression has no type: sequtils]#
+proc foo() =
+  block: #[tt.Error
+  ^ expression has no type: block:
+  sequtils]#
+    sequtils
+
+foo()
+
+# issue #23399
+when isMainModule:
+  sequtils #[tt.Error
+  ^ expression has no type: sequtils]#
+
+discard
diff --git a/tests/modules/tnamspc.nim b/tests/modules/tnamspc.nim
new file mode 100644
index 000000000..93ce71568
--- /dev/null
+++ b/tests/modules/tnamspc.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "undeclared identifier: \'global\'"
+  file: "tnamspc.nim"
+  line: 10
+"""
+# Test17 - test correct handling of namespaces
+
+import mnamspc1
+
+global = 9 #ERROR
diff --git a/tests/modules/tnotuniquename.nim b/tests/modules/tnotuniquename.nim
new file mode 100644
index 000000000..bc401e662
--- /dev/null
+++ b/tests/modules/tnotuniquename.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''nested
+flat'''
+"""
+
+import mnotuniquename
+import tnotuniquename_dir/mnotuniquename as nun
+
+nested()
+flat()
diff --git a/tests/modules/tnotuniquename2.nim b/tests/modules/tnotuniquename2.nim
new file mode 100644
index 000000000..e4501bc24
--- /dev/null
+++ b/tests/modules/tnotuniquename2.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "module names need to be unique per Nimble package"
+  file: "tnotuniquename/mnotuniquename.nim"
+  disabled: "true"
+"""
+
+import mnotuniquename
+import tnotuniquename/mnotuniquename
diff --git a/tests/modules/tnotuniquename_dir/mnotuniquename.nim b/tests/modules/tnotuniquename_dir/mnotuniquename.nim
new file mode 100644
index 000000000..11e52d9d0
--- /dev/null
+++ b/tests/modules/tnotuniquename_dir/mnotuniquename.nim
@@ -0,0 +1,2 @@
+
+proc nested*() = echo "nested"
diff --git a/tests/topaque.nim b/tests/modules/topaque.nim
index 7553a749e..94ff8ff25 100755..100644
--- a/tests/topaque.nim
+++ b/tests/modules/topaque.nim
@@ -1,11 +1,16 @@
-# Test the new opaque types

-

-import 

-  mopaque

-  

-var

-  L: TLexer

-  

-L.filename = "ha"

-L.line = 34

-L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'

+discard """
+  errormsg: "undeclared field: \'buffer\'"
+  file: "topaque.nim"
+  line: 16
+"""
+# Test the new opaque types
+
+import
+  mopaque
+
+var
+  L: TLexer
+
+L.filename = "ha"
+L.line = 34
+L.buffer[0] = '\0' #ERROR_MSG undeclared field: 'buffer'
diff --git a/tests/modules/torder_dep.nim b/tests/modules/torder_dep.nim
new file mode 100644
index 000000000..85211228a
--- /dev/null
+++ b/tests/modules/torder_dep.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''[0, 0]'''
+"""
+
+import morder_depb
+import morder_depa
+
+# bug #11187
+
+echo Foo(3)
diff --git a/tests/modules/trecinca.nim b/tests/modules/trecinca.nim
new file mode 100644
index 000000000..56798dedd
--- /dev/null
+++ b/tests/modules/trecinca.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "recursive dependency: 'trecincb.nim'"
+  file: "trecincb.nim"
+  line: 9
+"""
+# Test recursive includes
+
+include trecincb
+
+echo "trecina"
diff --git a/tests/modules/trecincb.nim b/tests/modules/trecincb.nim
new file mode 100644
index 000000000..30a5d7800
--- /dev/null
+++ b/tests/modules/trecincb.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "recursive dependency: 'trecincb.nim'"
+  file: "trecincb.nim"
+  line: 9
+"""
+# Test recursive includes
+
+
+include trecincb
+
+echo "trecinb"
diff --git a/tests/modules/trecmod.nim b/tests/modules/trecmod.nim
new file mode 100644
index 000000000..43e510e87
--- /dev/null
+++ b/tests/modules/trecmod.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "recursive module dependency detected"
+  file: "mrecmod.nim"
+  line: 1
+  disabled: true
+"""
+# recursive module
+import mrecmod
diff --git a/tests/trecmod2.nim b/tests/modules/trecmod2.nim
index 85fe2215f..03c8cf70d 100755..100644
--- a/tests/trecmod2.nim
+++ b/tests/modules/trecmod2.nim
@@ -1,10 +1,13 @@
+discard """
+  output: "4"
+"""
 type
   T1* = int  # Module A exports the type ``T1``
 
 import mrecmod2   # the compiler starts parsing B
-
+# the manual says this should work
 proc main() =
-  var i = p(3) # works because B has been parsed completely here
+  echo p(3) # works because B has been parsed completely here
 
 main()
 
diff --git a/tests/modules/treorder.nim b/tests/modules/treorder.nim
new file mode 100644
index 000000000..ff0b2e071
--- /dev/null
+++ b/tests/modules/treorder.nim
@@ -0,0 +1,47 @@
+discard """
+  matrix: "-d:testdef"
+  output: '''works 34
+34
+defined
+3'''
+"""
+
+{.experimental: "codeReordering".}
+
+{.push callconv: stdcall.}
+
+proc bar(x: T)
+
+proc foo() =
+  bar(34)
+  whendep()
+
+proc foo(dummy: int) = echo dummy
+
+proc bar(x: T) =
+  echo "works ", x
+  foo(x)
+
+when defined(testdef):
+  proc whendep() = echo "defined"
+else:
+  proc whendep() = echo "undefined"
+
+foo()
+
+type
+  T = int
+
+
+when not declared(goo):
+  proc goo(my, omy) = echo my
+
+when not declared(goo):
+  proc goo(my, omy) = echo omy
+
+using
+  my, omy: int
+
+goo(3, 4)
+
+{.pop.}
diff --git a/tests/modules/tselfimport.nim b/tests/modules/tselfimport.nim
new file mode 100644
index 000000000..ba5d9b4cf
--- /dev/null
+++ b/tests/modules/tselfimport.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "module 'tselfimport' cannot import itself"
+  file: "tselfimport.nim"
+  line: 7
+"""
+import strutils as su # guard against regression
+import tselfimport #ERROR
+echo("Hello World")
diff --git a/tests/modules/tseq.nim b/tests/modules/tseq.nim
new file mode 100644
index 000000000..22ee48f42
--- /dev/null
+++ b/tests/modules/tseq.nim
@@ -0,0 +1,8 @@
+discard """
+  joinable: false
+  output: '''@[]
+@[]
+'''
+"""
+
+import seq
diff --git a/tests/modules/tstrutils_insert_sep.nim b/tests/modules/tstrutils_insert_sep.nim
new file mode 100644
index 000000000..775fe7da1
--- /dev/null
+++ b/tests/modules/tstrutils_insert_sep.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''
+-100
+-100,000
+100,000
+'''
+"""
+# test https://github.com/nim-lang/Nim/issues/11352
+
+import strutils
+echo insertSep($(-100), ',')
+echo insertSep($(-100_000), ',')
+echo insertSep($(100_000), ',')
\ No newline at end of file
diff --git a/tests/modules/tuppercased.nim b/tests/modules/tuppercased.nim
new file mode 100644
index 000000000..65f41becd
--- /dev/null
+++ b/tests/modules/tuppercased.nim
@@ -0,0 +1,8 @@
+discard """
+  output: "hello"
+"""
+
+import UpperCased
+
+# stress normalization rules:
+echo Upper_Cased.str
diff --git a/tests/modules/tutils_ab.nim b/tests/modules/tutils_ab.nim
new file mode 100644
index 000000000..25bd08f3c
--- /dev/null
+++ b/tests/modules/tutils_ab.nim
@@ -0,0 +1,5 @@
+import a/utils as autils, b/utils
+
+# bug #12420
+
+burnMem(x)
diff --git a/tests/msgs/mdeprecated3.nim b/tests/msgs/mdeprecated3.nim
new file mode 100644
index 000000000..0a9c6e37d
--- /dev/null
+++ b/tests/msgs/mdeprecated3.nim
@@ -0,0 +1,10 @@
+type
+  Ty* {.deprecated.} = uint32
+  Ty1* {.deprecated: "hello".} = uint32
+
+var aVar* {.deprecated.}: char
+
+proc aProc*() {.deprecated.} = discard
+proc aProc1*() {.deprecated: "hello".} = discard
+
+{.deprecated: "goodbye".}
diff --git a/tests/msgs/mspellsuggest.nim b/tests/msgs/mspellsuggest.nim
new file mode 100644
index 000000000..ad449554f
--- /dev/null
+++ b/tests/msgs/mspellsuggest.nim
@@ -0,0 +1,7 @@
+proc fooBar4*(a: int) = discard
+var fooBar9* = 0
+
+var fooCar* = 0
+type FooBar* = int
+type FooCar* = int
+type GooBa* = int
diff --git a/tests/msgs/mused2a.nim b/tests/msgs/mused2a.nim
new file mode 100644
index 000000000..d9b2bb9bf
--- /dev/null
+++ b/tests/msgs/mused2a.nim
@@ -0,0 +1,23 @@
+import std/strutils
+
+from std/os import fileExists
+
+import std/typetraits as typetraits2
+from std/setutils import complement
+
+
+
+
+
+proc fn1() = discard
+proc fn2*() = discard
+
+
+let fn4 = 0
+let fn5* = 0
+
+
+const fn7 = 0
+const fn8* = 0
+
+type T1 = object
diff --git a/tests/msgs/mused2b.nim b/tests/msgs/mused2b.nim
new file mode 100644
index 000000000..39c92b964
--- /dev/null
+++ b/tests/msgs/mused2b.nim
@@ -0,0 +1,3 @@
+import mused2c
+export mused2c
+
diff --git a/tests/msgs/mused2c.nim b/tests/msgs/mused2c.nim
new file mode 100644
index 000000000..a374e634e
--- /dev/null
+++ b/tests/msgs/mused2c.nim
@@ -0,0 +1 @@
+proc baz*() = discard
\ No newline at end of file
diff --git a/tests/msgs/mused3.nim b/tests/msgs/mused3.nim
new file mode 100644
index 000000000..0beec1d44
--- /dev/null
+++ b/tests/msgs/mused3.nim
@@ -0,0 +1,76 @@
+#[
+ran from trunner
+]#
+
+
+
+
+
+
+# line 10
+when defined case1:
+  from mused3a import nil
+  from mused3b import nil
+  mused3a.fn1()
+
+when defined case2:
+  from mused3a as m1 import nil
+  m1.fn1()
+
+when defined case3:
+  from mused3a import fn1
+  fn1()
+
+when defined case4:
+  from mused3a as m1 import fn1
+  m1.fn1()
+
+when defined case5:
+  import mused3a as m1
+  fn1()
+
+when defined case6:
+  import mused3a except nonexistent
+  fn1()
+
+when defined case7:
+  import mused3a
+  mused3a.fn1()
+
+when defined case8:
+  # re-export test
+  import mused3a except nonexistent
+  gn1()
+
+when defined case9:
+  # re-export test
+  import mused3a
+  gn1()
+
+when defined case10:
+  #[
+  edge case which happens a lot in compiler code:
+  don't report UnusedImport for mused3b here even though it works without `import mused3b`,
+  because `a.b0.f0` is accessible from both mused3a and mused3b (fields are given implicit access)
+  ]#
+  import mused3a
+  import mused3b
+  var a: Bar
+  discard a.b0.f0
+
+when false:
+  when defined case11:
+    #[
+    xxx minor bug: this should give:
+    Warning: imported and not used: 'm2' [UnusedImport]
+    but doesn't, because currently implementation in `markOwnerModuleAsUsed`
+    only looks at `fn1`, not fully qualified call `m1.fn1()
+    ]#
+    from mused3a as m1 import nil
+    from mused3a as m2 import nil
+    m1.fn1()
+
+when defined case12:
+  import mused3a
+  import mused3a
+  fn1()
diff --git a/tests/msgs/mused3a.nim b/tests/msgs/mused3a.nim
new file mode 100644
index 000000000..c33d1ecb3
--- /dev/null
+++ b/tests/msgs/mused3a.nim
@@ -0,0 +1,41 @@
+when defined case1:
+  proc fn1*() = discard
+
+when defined case2:
+  proc fn1*() = discard
+
+when defined case3:
+  proc fn1*() = discard
+  proc fn2*() = discard
+
+when defined case4:
+  proc fn1*() = discard
+  proc fn2*() = discard
+
+when defined case5:
+  proc fn1*() = discard
+
+when defined case6:
+  proc fn1*() = discard
+
+when defined case7:
+  proc fn1*() = discard
+
+when defined case8:
+  import mused3b
+  export mused3b
+
+when defined case9:
+  import mused3b
+  export mused3b
+
+when defined case10:
+  import mused3b
+  type Bar* = object
+    b0*: Foo
+
+when defined case11:
+  proc fn1*() = discard
+
+when defined case12:
+  proc fn1*() = discard
diff --git a/tests/msgs/mused3b.nim b/tests/msgs/mused3b.nim
new file mode 100644
index 000000000..de288bb08
--- /dev/null
+++ b/tests/msgs/mused3b.nim
@@ -0,0 +1,12 @@
+when defined case1:
+  proc gn1*()=discard
+
+when defined case8:
+  proc gn1*()=discard
+
+when defined case9:
+  proc gn1*()=discard
+
+when defined case10:
+  type Foo* = object
+    f0*: int
diff --git a/tests/msgs/tdeprecated1.nim b/tests/msgs/tdeprecated1.nim
new file mode 100644
index 000000000..f4e85da0b
--- /dev/null
+++ b/tests/msgs/tdeprecated1.nim
@@ -0,0 +1,15 @@
+let foo* {.deprecated: "abcd".} = 42
+var foo1* {.deprecated: "efgh".} = 42
+foo1 = foo #[tt.Warning
+^ efgh; foo1 is deprecated [Deprecated]; tt.Warning
+       ^ abcd; foo is deprecated [Deprecated]]#
+
+proc hello[T](a: T) {.deprecated: "Deprecated since v1.2.0, use 'HelloZ'".} =
+  discard
+
+hello[int](12) #[tt.Warning
+^ Deprecated since v1.2.0, use 'HelloZ'; hello is deprecated [Deprecated]]#
+
+const foo2* {.deprecated: "abcd".} = 42
+discard foo2 #[tt.Warning
+        ^ abcd; foo2 is deprecated [Deprecated]]#
diff --git a/tests/msgs/tdeprecated2.nim b/tests/msgs/tdeprecated2.nim
new file mode 100644
index 000000000..71d20081e
--- /dev/null
+++ b/tests/msgs/tdeprecated2.nim
@@ -0,0 +1,42 @@
+discard """
+  nimout: '''
+tdeprecated2.nim(23, 3) Warning: a is deprecated [Deprecated]
+tdeprecated2.nim(30, 11) Warning: asdf; enum 'Foo' which contains field 'a' is deprecated [Deprecated]
+tdeprecated2.nim(40, 16) Warning: use fooX instead; fooA is deprecated [Deprecated]
+end
+'''
+"""
+
+
+
+
+
+
+## line 15
+
+
+
+block:
+  var
+    a {.deprecated.}: array[0..11, int]
+
+  a[8] = 1
+
+block t10111:
+  type
+    Foo {.deprecated: "asdf" .} = enum
+      a 
+  
+  var _ = a
+  
+
+block: # issue #8063
+  type
+    Foo = enum
+      fooX
+
+  const fooA {.deprecated: "use fooX instead".} = fooX
+  let
+    foo: Foo = fooA
+  echo foo
+  static: echo "end"
diff --git a/tests/msgs/tdeprecated3.nim b/tests/msgs/tdeprecated3.nim
new file mode 100644
index 000000000..0c1b7deff
--- /dev/null
+++ b/tests/msgs/tdeprecated3.nim
@@ -0,0 +1,33 @@
+discard """
+  matrix: "--hint:all:off"
+  nimoutFull: true
+  nimout: '''
+tdeprecated3.nim(21, 8) Warning: goodbye; mdeprecated3 is deprecated [Deprecated]
+tdeprecated3.nim(24, 10) Warning: Ty is deprecated [Deprecated]
+tdeprecated3.nim(27, 10) Warning: hello; Ty1 is deprecated [Deprecated]
+tdeprecated3.nim(30, 8) Warning: aVar is deprecated [Deprecated]
+tdeprecated3.nim(32, 3) Warning: aProc is deprecated [Deprecated]
+tdeprecated3.nim(33, 3) Warning: hello; aProc1 is deprecated [Deprecated]
+'''
+"""
+
+
+
+
+
+
+
+# line 20
+import mdeprecated3
+
+block:
+  var z: Ty
+  z = 0
+block:
+  var z: Ty1
+  z = 0
+block:
+  echo aVar
+block:
+  aProc()
+  aProc1()
diff --git a/tests/msgs/tdeprecatedequalhook.nim b/tests/msgs/tdeprecatedequalhook.nim
new file mode 100644
index 000000000..79ee835f8
--- /dev/null
+++ b/tests/msgs/tdeprecatedequalhook.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "Overriding `=` hook is deprecated; Override `=copy` hook instead"
+  matrix: "--warningAsError[Deprecated]:on"
+"""
+
+type
+  SharedString = object
+    data: string
+
+proc `=`(x: var SharedString, y: SharedString) =
+  discard
\ No newline at end of file
diff --git a/tests/msgs/texpandmacro.nim b/tests/msgs/texpandmacro.nim
new file mode 100644
index 000000000..fea8b571f
--- /dev/null
+++ b/tests/msgs/texpandmacro.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim c --expandMacro:foo $file"
+  nimout: '''texpandmacro.nim(17, 1) Hint: expanded macro:
+echo ["injected echo"]
+var x = 4 [ExpandMacro]
+'''
+  output: '''injected echo'''
+"""
+
+import macros
+
+macro foo(x: untyped): untyped =
+  result = quote do:
+    echo "injected echo"
+    `x`
+
+foo:
+  var x = 4
diff --git a/tests/msgs/thints_off.nim b/tests/msgs/thints_off.nim
new file mode 100644
index 000000000..5a4cadad6
--- /dev/null
+++ b/tests/msgs/thints_off.nim
@@ -0,0 +1,4 @@
+discard """
+  matrix: "--hints:off"
+"""
+doAssert true
diff --git a/tests/msgs/tspellsuggest.nim b/tests/msgs/tspellsuggest.nim
new file mode 100644
index 000000000..ea0a98cd3
--- /dev/null
+++ b/tests/msgs/tspellsuggest.nim
@@ -0,0 +1,45 @@
+discard """
+  matrix: "--spellsuggest:15 --hints:off"
+  action: "reject"
+  nimout: '''
+tspellsuggest.nim(45, 13) Error: undeclared identifier: 'fooBar'
+candidates (edit distance, scope distance); see '--spellSuggest':
+ (1, 0): 'fooBar8'
+ (1, 1): 'fooBar7'
+ (1, 3): 'fooBar1'
+ (1, 3): 'fooBar2'
+ (1, 3): 'fooBar3'
+ (1, 3): 'fooBar4'
+ (1, 3): 'fooBar5'
+ (1, 3): 'fooBar6'
+ (1, 5): 'FooBar'
+ (1, 5): 'fooBar4'
+ (1, 5): 'fooBar9'
+ (1, 5): 'fooCar'
+ (2, 5): 'FooCar'
+ (2, 5): 'GooBa'
+ (3, 0): 'fooBarBaz'
+'''
+"""
+
+# tests `--spellsuggest:num`
+
+
+
+
+# line 30
+import ./mspellsuggest
+
+var fooBar1 = 0
+let fooBar2 = 0
+const fooBar3 = 0
+proc fooBar4() = discard
+template fooBar5() = discard
+macro fooBar6() = discard
+
+proc main =
+  var fooBar7 = 0
+  block:
+    var fooBar8 = 0
+    const fooBarBaz = 0
+    let x = fooBar
diff --git a/tests/msgs/tspellsuggest2.nim b/tests/msgs/tspellsuggest2.nim
new file mode 100644
index 000000000..4bf05799e
--- /dev/null
+++ b/tests/msgs/tspellsuggest2.nim
@@ -0,0 +1,45 @@
+discard """
+  matrix: "--spellsuggest:12 --hints:off"
+  action: "reject"
+  nimout: '''
+tspellsuggest2.nim(45, 13) Error: undeclared identifier: 'fooBar'
+candidates (edit distance, scope distance); see '--spellSuggest':
+ (1, 0): 'fooBar8'
+ (1, 1): 'fooBar7'
+ (1, 3): 'fooBar1'
+ (1, 3): 'fooBar2'
+ (1, 3): 'fooBar3'
+ (1, 3): 'fooBar4'
+ (1, 3): 'fooBar5'
+ (1, 3): 'fooBar6'
+ (1, 5): 'FooBar'
+ (1, 5): 'fooBar4'
+ (1, 5): 'fooBar9'
+ (1, 5): 'fooCar'
+'''
+"""
+
+# tests `--spellsuggest`
+
+
+
+
+
+
+
+# line 30
+import ./mspellsuggest
+
+var fooBar1 = 0
+let fooBar2 = 0
+const fooBar3 = 0
+proc fooBar4() = discard
+template fooBar5() = discard
+macro fooBar6() = discard
+
+proc main =
+  var fooBar7 = 0
+  block:
+    var fooBar8 = 0
+    const fooBarBaz = 0
+    let x = fooBar
diff --git a/tests/msgs/tspellsuggest3.nim b/tests/msgs/tspellsuggest3.nim
new file mode 100644
index 000000000..bd4d5256f
--- /dev/null
+++ b/tests/msgs/tspellsuggest3.nim
@@ -0,0 +1,21 @@
+discard """
+  matrix: "--spellsuggest:4 --hints:off"
+  action: "reject"
+  nimout: '''
+tspellsuggest3.nim(21, 1) Error: undeclared identifier: 'fooBar'
+candidates (edit distance, scope distance); see '--spellSuggest':
+ (1, 2): 'FooBar'
+ (1, 2): 'fooBar4'
+ (1, 2): 'fooBar9'
+ (1, 2): 'fooCar'
+'''
+"""
+
+
+import ./mspellsuggest
+import ./mspellsuggest
+import ./mspellsuggest
+import ./mspellsuggest
+
+
+fooBar
diff --git a/tests/msgs/tused2.nim b/tests/msgs/tused2.nim
new file mode 100644
index 000000000..5ccda7737
--- /dev/null
+++ b/tests/msgs/tused2.nim
@@ -0,0 +1,46 @@
+discard """
+  matrix: "--hint:all:off --hint:XDeclaredButNotUsed --path:."
+  joinable: false
+  nimoutFull: true
+  nimout: '''
+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, 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, 10) Warning: imported and not used: 'setutils' [UnusedImport]
+tused2.nim(42, 8) Warning: imported and not used: 'mused2a' [UnusedImport]
+tused2.nim(45, 12) Warning: imported and not used: 'strutils' [UnusedImport]
+'''
+"""
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# line 40
+
+import mused2a
+import mused2b
+
+import std/strutils
+baz()
diff --git a/tests/msgs/twarningaserror.nim b/tests/msgs/twarningaserror.nim
new file mode 100644
index 000000000..6f7b76095
--- /dev/null
+++ b/tests/msgs/twarningaserror.nim
@@ -0,0 +1,35 @@
+discard """
+  joinable: false
+"""
+
+#[
+tests: hintAsError, warningAsError
+]#
+
+template fn1 =
+  {.hintAsError[ConvFromXtoItselfNotNeeded]:on.}
+  proc fn(a: string) = discard a.string
+  {.hintAsError[ConvFromXtoItselfNotNeeded]:off.}
+
+template fn2 =
+  {.hintAsError[ConvFromXtoItselfNotNeeded]:on.}
+  proc fn(a: string) = discard a
+  {.hintAsError[ConvFromXtoItselfNotNeeded]:off.}
+
+template gn1 =
+  {.warningAsError[ProveInit]:on.}
+  proc fn(): var int = discard
+  discard fn()
+  {.warningAsError[ProveInit]:off.}
+
+template gn2 =
+  {.warningAsError[ProveInit]:on.}
+  proc fn(): int = discard
+  discard fn()
+  {.warningAsError[ProveInit]:off.}
+
+doAssert not compiles(fn1())
+doAssert compiles(fn2())
+
+doAssert not compiles(gn1())
+doAssert compiles(gn2())
diff --git a/tests/mvarious.nim b/tests/mvarious.nim
deleted file mode 100755
index 333b34d33..000000000
--- a/tests/mvarious.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test a submodule

-

-#type

-#  TStringArr = array [0.. *] of string

-

-proc exportme* = nil

diff --git a/tests/navigator/minclude.nim b/tests/navigator/minclude.nim
new file mode 100644
index 000000000..f65ebfab9
--- /dev/null
+++ b/tests/navigator/minclude.nim
@@ -0,0 +1,2 @@
+# An include file.
+foo(3)
diff --git a/tests/navigator/tincludefile.nim b/tests/navigator/tincludefile.nim
new file mode 100644
index 000000000..a913d0736
--- /dev/null
+++ b/tests/navigator/tincludefile.nim
@@ -0,0 +1,29 @@
+discard """
+  disabled: true
+  cmd: "nim check $options --defusages:$file,12,7 $file"
+  nimout: '''def tincludefile_temp.nim(11, 10)
+usage tincludefile_temp.nim(12, 8)
+  '''
+"""
+
+
+
+proc foo(x: int) =
+  echo x
+
+foo(3)
+echo "yes", 1 != 3
+
+#!EDIT!#
+discard """
+  cmd: "nim check $options --defusages:$file/../minclude.nim,2,2 $file"
+  nimout: '''def tincludefile_temp.nim(10, 6)
+usage minclude.nim(2, 1)
+  '''
+"""
+
+
+proc foo(x: int) =
+  echo x
+
+include minclude
diff --git a/tests/navigator/tnav1.nim b/tests/navigator/tnav1.nim
new file mode 100644
index 000000000..e76c921f3
--- /dev/null
+++ b/tests/navigator/tnav1.nim
@@ -0,0 +1,33 @@
+discard """
+  disabled: true
+  cmd: "nim check $options --defusages:$file,12,7 $file"
+  nimout: '''def tnav1_temp.nim(11, 10)
+usage tnav1_temp.nim(12, 8)
+  '''
+"""
+
+import std / [times]
+
+proc foo(x: int) =
+  echo x
+
+foo(3)
+echo "yes", 1 != 3
+
+#!EDIT!#
+discard """
+  cmd: "nim check $options --defusages:$file,15,2 $file"
+  nimout: '''def tnav1_temp.nim(12, 6)
+usage tnav1_temp.nim(15, 1)
+  '''
+"""
+
+
+import std / [times]
+
+proc foo(x: int) =
+  echo x
+
+foo(3)
+echo "yes", 1 != 3
+
diff --git a/tests/newconfig/bar/config.nims b/tests/newconfig/bar/config.nims
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/newconfig/bar/config.nims
diff --git a/tests/newconfig/bar/mfoo.nim b/tests/newconfig/bar/mfoo.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/newconfig/bar/mfoo.nim
diff --git a/tests/newconfig/bar/mfoo.nim.cfg b/tests/newconfig/bar/mfoo.nim.cfg
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/newconfig/bar/mfoo.nim.cfg
diff --git a/tests/newconfig/bar/mfoo.nims b/tests/newconfig/bar/mfoo.nims
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/newconfig/bar/mfoo.nims
diff --git a/tests/newconfig/bar/nim.cfg b/tests/newconfig/bar/nim.cfg
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/newconfig/bar/nim.cfg
diff --git a/tests/newconfig/foo2/mfoo2.customext b/tests/newconfig/foo2/mfoo2.customext
new file mode 100644
index 000000000..66c8b1d15
--- /dev/null
+++ b/tests/newconfig/foo2/mfoo2.customext
@@ -0,0 +1,2 @@
+doAssert defined(nimscript)
+echo "123"
diff --git a/tests/newconfig/mconfigcheck.nims b/tests/newconfig/mconfigcheck.nims
new file mode 100644
index 000000000..8df6715f6
--- /dev/null
+++ b/tests/newconfig/mconfigcheck.nims
@@ -0,0 +1,9 @@
+mode = ScriptMode.Verbose
+proc build() =
+  echo "building nim... "
+  exec "sleep 10"
+  exec "nonexistant command"
+  echo getCurrentDir()
+
+echo "hello"
+build()
diff --git a/tests/newconfig/mymath.nim b/tests/newconfig/mymath.nim
new file mode 100644
index 000000000..5668b448b
--- /dev/null
+++ b/tests/newconfig/mymath.nim
@@ -0,0 +1,4 @@
+
+
+proc ln*(x: float): float =
+  return 0.5
diff --git a/tests/newconfig/tfoo.nim b/tests/newconfig/tfoo.nim
new file mode 100644
index 000000000..0c6ded470
--- /dev/null
+++ b/tests/newconfig/tfoo.nim
@@ -0,0 +1,13 @@
+discard """
+  cmd: "nim default --hint:cc:off --hint:cc $file"
+  output: '''hello world! 0.5 true'''
+  nimout: '''[NimScript] exec: gcc -v'''
+"""
+
+when not defined(definedefine):
+  {.fatal: "wrong nim script configuration".}
+
+import math, mfriends
+
+discard gen[int]()
+echo "hello world! ", ln 2.0, " ", compileOption("opt", "speed")
diff --git a/tests/newconfig/tfoo.nims b/tests/newconfig/tfoo.nims
new file mode 100644
index 000000000..f22caaacd
--- /dev/null
+++ b/tests/newconfig/tfoo.nims
@@ -0,0 +1,108 @@
+
+mode = ScriptMode.Whatif
+
+exec "gcc -v"
+
+--define:release
+
+--forceBuild
+--path: "../generics"
+
+warning("uninit", off)
+
+block: # supported syntaxes for hint,warning,switch
+  --hint:processing
+  hint("processing", on)
+  hint("processing", off)
+  switch("hint", "processing")
+  switch("hint", "processing:on")
+  switch("hint", "processing:off")
+  switch("hint", "[processing]")
+  switch("hint", "[processing]:on")
+  switch("hint", "[processing]:off") # leave it off
+
+  --warning:UnusedImport
+  switch("warning", "UnusedImport:off")
+  switch("warning", "UnusedImport:on")
+  switch("warning", "[UnusedImport]:off")
+  switch("warning", "[UnusedImport]:on")
+  switch("warning", "[UnusedImport]")
+  switch("warning", "UnusedImport") # leave it on
+
+#--verbosity:2
+patchFile("stdlib", "math", "mymath")
+
+task listDirs, "lists every subdirectory":
+  for x in listDirs("."):
+    echo "DIR ", x
+
+task default, "default target":
+  --define: definedefine
+  setCommand "c"
+
+# bug #6327
+doAssert(existsEnv("dummy") == false)
+
+# issue #7283
+putEnv("dummy", "myval")
+doAssert(existsEnv("dummy"))
+doAssert(getEnv("dummy") == "myval")
+delEnv("dummy")
+doAssert(existsEnv("dummy") == false)
+
+# issue #7393
+let wd = getCurrentDir()
+cd("..")
+doAssert wd != getCurrentDir()
+cd(wd)
+doAssert wd == getCurrentDir()
+
+when false:
+  # this doesn't work in a 'koch testintall' environment
+  doAssert findExe("nim") != ""
+
+# general tests
+mode = ScriptMode.Verbose
+
+doAssert getCommand() == "c"
+setCommand("cpp")
+doAssert getCommand() == "cpp"
+setCommand("c")
+
+doAssert cmpic("HeLLO", "hello") == 0
+
+doAssert fileExists("tests/newconfig/tfoo.nims") == true
+doAssert dirExists("tests") == true
+
+doAssert fileExists("tests/newconfig/tfoo.nims") == true
+doAssert dirExists("tests") == true
+
+discard selfExe()
+
+when defined(windows):
+  doAssert toExe("nim") == "nim.exe"
+  doAssert toDll("nim") == "nim.dll"
+else:
+  doAssert toExe("nim") == "nim"
+  doAssert toDll("nim") == "libnim.so"
+
+rmDir("tempXYZ")
+doAssertRaises(OSError):
+  rmDir("tempXYZ", checkDir = true)
+doAssert dirExists("tempXYZ") == false
+mkDir("tempXYZ")
+doAssert dirExists("tempXYZ") == true
+doAssert fileExists("tempXYZ/koch.nim") == false
+
+when false:
+  # this doesn't work in a 'koch testintall' environment
+  cpFile("koch.nim", "tempXYZ/koch.nim")
+  doAssert fileExists("tempXYZ/koch.nim") == true
+  cpDir("nimsuggest", "tempXYZ/.")
+  doAssert dirExists("tempXYZ/tests") == true
+  doAssert fileExists("tempXYZ/nimsuggest.nim") == true
+  rmFile("tempXYZ/koch.nim")
+  doAssert fileExists("tempXYZ/koch.nim") == false
+
+rmDir("tempXYZ")
+doAssert dirExists("tempXYZ") == false
diff --git a/tests/nimble/nimbleDir/linkedPkgs/pkgA-0.1.0/pkgA.nimble-link b/tests/nimble/nimbleDir/linkedPkgs/pkgA-0.1.0/pkgA.nimble-link
new file mode 100644
index 000000000..8dc825fc9
--- /dev/null
+++ b/tests/nimble/nimbleDir/linkedPkgs/pkgA-0.1.0/pkgA.nimble-link
@@ -0,0 +1,2 @@
+../../simplePkgs/pkgA-0.1.0/pkgA.nimble
+../../simplePkgs/pkgA-0.1.0/
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/linkedPkgs/pkgB-#head/pkgB.nimble-link b/tests/nimble/nimbleDir/linkedPkgs/pkgB-#head/pkgB.nimble-link
new file mode 100644
index 000000000..a57a3cb66
--- /dev/null
+++ b/tests/nimble/nimbleDir/linkedPkgs/pkgB-#head/pkgB.nimble-link
@@ -0,0 +1,2 @@
+../../simplePkgs/pkgB-#head/pkgB.nimble
+../../simplePkgs/pkgB-#head/
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/linkedPkgs/pkgB-0.1.0/pkgB.nimble-link b/tests/nimble/nimbleDir/linkedPkgs/pkgB-0.1.0/pkgB.nimble-link
new file mode 100644
index 000000000..9643c0fa0
--- /dev/null
+++ b/tests/nimble/nimbleDir/linkedPkgs/pkgB-0.1.0/pkgB.nimble-link
@@ -0,0 +1,2 @@
+../../simplePkgs/pkgB-0.1.0/pkgB.nimble
+../../simplePkgs/pkgB-0.1.0/
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA.nimble b/tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA.nimble
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA/module.nim b/tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA/module.nim
new file mode 100644
index 000000000..6cb3b77d9
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgA-0.1.0/pkgA/module.nim
@@ -0,0 +1 @@
+proc pkgATest*(): int = 1
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB.nimble b/tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB.nimble
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB/module.nim b/tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB/module.nim
new file mode 100644
index 000000000..03d2298a2
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgB-#head/pkgB/module.nim
@@ -0,0 +1 @@
+proc pkgBTest*(): int64 = 0xDEADBEEF
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB.nimble b/tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB.nimble
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB/module.nim b/tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB/module.nim
new file mode 100644
index 000000000..56ff64197
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgB-0.1.0/pkgB/module.nim
@@ -0,0 +1 @@
+proc pkgBTest*(): int64 = 0
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC.nimble b/tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC.nimble
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC/module.nim b/tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC/module.nim
new file mode 100644
index 000000000..24a67bbe2
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgC-#aa11/pkgC/module.nim
@@ -0,0 +1 @@
+proc pkgCTest*(): int64 = 1
\ No newline at end of file
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC.nimble b/tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC.nimble
diff --git a/tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC/module.nim b/tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC/module.nim
new file mode 100644
index 000000000..2f243ad82
--- /dev/null
+++ b/tests/nimble/nimbleDir/simplePkgs/pkgC-#head/pkgC/module.nim
@@ -0,0 +1 @@
+proc pkgCTest*(): int64 = 0xDEADBEEF
\ No newline at end of file
diff --git a/tests/nimble/readme.md b/tests/nimble/readme.md
new file mode 100644
index 000000000..10fd21a83
--- /dev/null
+++ b/tests/nimble/readme.md
@@ -0,0 +1,2 @@
+This directory contains tests for the --nimblePath feature.
+
diff --git a/tests/nimble/tnimblepath.nim b/tests/nimble/tnimblepath.nim
new file mode 100644
index 000000000..6ba1be1d1
--- /dev/null
+++ b/tests/nimble/tnimblepath.nim
@@ -0,0 +1,11 @@
+discard """
+  action: run
+  cmd: "nim $target --nimblePath:$fileDir/nimbleDir/simplePkgs $options $file"
+"""
+import pkgA/module as A
+import pkgB/module as B
+import pkgC/module as C
+
+doAssert pkgATest() == 1, "Simple pkgA-0.1.0 wasn't added to path correctly."
+doAssert pkgBTest() == 0xDEADBEEF, "pkgB-#head wasn't picked over pkgB-0.1.0"
+doAssert pkgCTest() == 0xDEADBEEF, "pkgC-#head wasn't picked over pkgC-#aa11"
\ No newline at end of file
diff --git a/tests/nimble/tnimblepathdollar.nim b/tests/nimble/tnimblepathdollar.nim
new file mode 100644
index 000000000..994d975bb
--- /dev/null
+++ b/tests/nimble/tnimblepathdollar.nim
@@ -0,0 +1,7 @@
+import pkgA/module as A
+import pkgB/module as B
+import pkgC/module as C
+
+doAssert pkgATest() == 1, "Simple pkgA-0.1.0 wasn't added to path correctly."
+doAssert pkgBTest() == 0xDEADBEEF, "pkgB-#head wasn't picked over pkgB-0.1.0"
+doAssert pkgCTest() == 0xDEADBEEF, "pkgC-#head wasn't picked over pkgC-#aa11"
diff --git a/tests/nimble/tnimblepathdollar.nims b/tests/nimble/tnimblepathdollar.nims
new file mode 100644
index 000000000..9621fb29f
--- /dev/null
+++ b/tests/nimble/tnimblepathdollar.nims
@@ -0,0 +1,5 @@
+switch("clearNimblePath")
+switch("nimblePath", "$projectdir/nimbleDir/simplePkgs")
+switch("path", "$nimblepath/pkgA-0.1.0")
+switch("path", "$nimblepath/pkgB-#head")
+switch("path", "$nimblepath/pkgC-#head")
diff --git a/tests/nimble/tnimblepathdollar_fault.nim b/tests/nimble/tnimblepathdollar_fault.nim
new file mode 100644
index 000000000..3f0270123
--- /dev/null
+++ b/tests/nimble/tnimblepathdollar_fault.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "cannot open file: pkgA/module"
+"""
+
+# see nims file; comment out `switch("noNimblePath")` there and there would be no error
+
+import pkgA/module as A
+import pkgB/module as B
+import pkgC/module as C
+
+doAssert pkgATest() == 1, "Simple pkgA-0.1.0 wasn't added to path correctly."
+doAssert pkgBTest() == 0xDEADBEEF, "pkgB-#head wasn't picked over pkgB-0.1.0"
+doAssert pkgCTest() == 0xDEADBEEF, "pkgC-#head wasn't picked over pkgC-#aa11"
diff --git a/tests/nimble/tnimblepathdollar_fault.nims b/tests/nimble/tnimblepathdollar_fault.nims
new file mode 100644
index 000000000..7d47da744
--- /dev/null
+++ b/tests/nimble/tnimblepathdollar_fault.nims
@@ -0,0 +1,5 @@
+switch("noNimblePath")
+switch("nimblePath", "$projectdir/nimbleDir/simplePkgs")
+switch("path", "$nimblepath/pkgA-0.1.0")
+switch("path", "$nimblepath/pkgB-#head")
+switch("path", "$nimblepath/pkgC-#head")
diff --git a/tests/nimble/tnimblepathlink.nim b/tests/nimble/tnimblepathlink.nim
new file mode 100644
index 000000000..5b2c7cb5b
--- /dev/null
+++ b/tests/nimble/tnimblepathlink.nim
@@ -0,0 +1,9 @@
+discard """
+  action: run
+  cmd: "nim $target --nimblePath:$fileDir/nimbleDir/linkedPkgs $options $file"
+"""
+import pkgA/module as A
+import pkgB/module as B
+
+doAssert pkgATest() == 1, "Simple linked pkgA-0.1.0 wasn't added to path correctly."
+doAssert pkgBTest() == 0xDEADBEEF, "linked pkgB-#head wasn't picked over pkgB-0.1.0"
\ No newline at end of file
diff --git a/tests/nimdoc/imp.nim b/tests/nimdoc/imp.nim
new file mode 100644
index 000000000..ca08dcb35
--- /dev/null
+++ b/tests/nimdoc/imp.nim
@@ -0,0 +1 @@
+proc fn5*() = discard
diff --git a/tests/nimdoc/m13129.nim b/tests/nimdoc/m13129.nim
new file mode 100644
index 000000000..34e118381
--- /dev/null
+++ b/tests/nimdoc/m13129.nim
@@ -0,0 +1,37 @@
+# issue #13129
+
+when defined(cpp):
+  {.push header: "<vector>".}
+  type
+    Vector[T] {.importcpp: "std::vector".} = object
+  {.pop.}
+elif defined(js):
+  proc endsWith*(s, suffix: cstring): bool {.noSideEffect,importjs: "#.endsWith(#)".}
+elif defined(c):
+  proc c_printf*(frmt: cstring): cint {.
+    importc: "printf", header: "<stdio.h>", varargs, discardable.}
+
+proc main*() =
+  runnableExamples:
+    import std/compilesettings
+    doAssert not defined(m13129Foo1)
+    doAssert defined(m13129Foo2)
+    doAssert not defined(nimdoc)
+    echo "ok2: backend: " & querySetting(backend)
+
+import std/compilesettings
+when defined nimdoc:
+  static:
+    doAssert defined(m13129Foo1)
+    doAssert not defined(m13129Foo2)
+    echo "ok1:" & querySetting(backend)
+
+when isMainModule:
+  when not defined(js):
+    import std/os
+    let cache = querySetting(nimcacheDir)
+    doAssert cache.len > 0
+    let app = getAppFilename()
+    doAssert app.isRelativeTo(cache), $(app, cache)
+    doAssert querySetting(projectFull) == currentSourcePath
+    echo "ok3"
diff --git a/tests/nimdoc/readme.md b/tests/nimdoc/readme.md
new file mode 100644
index 000000000..40b5841eb
--- /dev/null
+++ b/tests/nimdoc/readme.md
@@ -0,0 +1,3 @@
+## links
+* $nim/nimdoc/tester.nim: tests html validation
+* $nim/tests/nimdoc/: tests `runnableExamples` + `nim doc` logic
diff --git a/tests/nimdoc/sub/imp.nim b/tests/nimdoc/sub/imp.nim
new file mode 100644
index 000000000..d66542e45
--- /dev/null
+++ b/tests/nimdoc/sub/imp.nim
@@ -0,0 +1 @@
+proc fn4*() = discard
diff --git a/tests/nimdoc/sub/imp2.nim b/tests/nimdoc/sub/imp2.nim
new file mode 100644
index 000000000..60fa1e72d
--- /dev/null
+++ b/tests/nimdoc/sub/imp2.nim
@@ -0,0 +1 @@
+proc fn3*() = discard
diff --git a/tests/nimdoc/sub/mmain.nim b/tests/nimdoc/sub/mmain.nim
new file mode 100644
index 000000000..42547b0b8
--- /dev/null
+++ b/tests/nimdoc/sub/mmain.nim
@@ -0,0 +1,8 @@
+{.warning[UnusedImport]: off.}
+
+import ../imp as impa
+import imp as impb
+import imp2
+
+proc fn1*() = discard
+proc fn2*() = discard
diff --git a/tests/nimdoc/t15916.nim b/tests/nimdoc/t15916.nim
new file mode 100644
index 000000000..c6c09d94b
--- /dev/null
+++ b/tests/nimdoc/t15916.nim
@@ -0,0 +1,16 @@
+discard """
+cmd: "nim doc --hints:off $file"
+action: "compile"
+joinable: false
+"""
+
+type
+  Test* = object
+    id: int
+
+proc initTest*(id: int): Test =
+  result.id = id
+
+proc hello*() =
+  runnableExamples:
+    discard
diff --git a/tests/nimdoc/t17615.nim b/tests/nimdoc/t17615.nim
new file mode 100644
index 000000000..77ae35a15
--- /dev/null
+++ b/tests/nimdoc/t17615.nim
@@ -0,0 +1,11 @@
+discard """
+  cmd: "nim doc -r $file"
+  errormsg: "runnableExamples must appear before the first non-comment statement"
+  line: 10
+"""
+
+func fn*() =
+  ## foo
+  discard
+  runnableExamples:
+    assert true
diff --git a/tests/nimdoc/trunnableexamples.nim b/tests/nimdoc/trunnableexamples.nim
new file mode 100644
index 000000000..57e725b2e
--- /dev/null
+++ b/tests/nimdoc/trunnableexamples.nim
@@ -0,0 +1,213 @@
+discard """
+cmd: '''nim doc --doccmd:"-d:testFooExternal --hints:off" --hints:off $file'''
+action: "compile"
+nimoutFull: true
+nimout: '''
+foo1
+foo2
+foo3
+foo5
+foo7
+in examplesInTemplate1
+doc in outer
+doc in inner1
+doc in inner2
+foo8
+foo9
+foo6
+'''
+joinable: false
+"""
+
+
+proc fun*() =
+  runnableExamples:
+    block: # `defer` only allowed inside a block
+      defer: echo "foo1"
+
+  runnableExamples:
+    # `fun*` only allowed at top level
+    proc fun*()=echo "foo2"
+    fun()
+    block:
+      defer: echo "foo3"
+
+  runnableExamples:
+    # ditto
+    proc fun*()=echo "foo5"
+    fun()
+
+  runnableExamples("--experimental:codeReordering --warnings:off"):
+    # `codeReordering` only allowed at top level
+    {.experimental: "codeReordering".}
+    proc fun1() = fun2()
+    proc fun2() = echo "foo6"
+    fun1()
+
+  runnableExamples:
+    # only works at top level
+    import std/macros
+    macro myImport(a: static string): untyped =
+      newTree(nnkImportStmt, [newLit a])
+    myImport "str" & "utils"
+    doAssert declared(isAlphaAscii)
+    echo "foo7"
+
+when true: # issue #12746
+  # this proc on its own works fine with `nim doc`
+  proc goodProc*() =
+    runnableExamples:
+      try:
+        discard
+      except CatchableError:
+        # just the general except will work
+        discard
+
+  # FIXED: this proc fails with `nim doc`
+  proc badProc*() =
+    runnableExamples:
+      try:
+        discard
+      except IOError:
+        # specifying Error is culprit
+        discard
+
+when true: # runnableExamples with rdoccmd
+  runnableExamples "-d:testFoo -d:testBar":
+    doAssert defined(testFoo) and defined(testBar)
+    doAssert defined(testFooExternal)
+  runnableExamples "-d:testFoo2":
+    doAssert defined(testFoo2)
+    doAssert not defined(testFoo) # doesn't get confused by other examples
+
+  ## all these syntaxes work too
+  runnableExamples("-d:testFoo2"): discard
+  runnableExamples(): discard
+  runnableExamples: discard
+  runnableExamples "-r:off": # issue #10731
+    doAssert false ## we compile only (-r:off), so this won't be run
+  runnableExamples "-b:js":
+    import std/compilesettings
+    proc startsWith*(s, prefix: cstring): bool {.noSideEffect, importjs: "#.startsWith(#)".}
+    doAssert querySetting(backend) == "js"
+  runnableExamples "-b:cpp":
+    static: doAssert defined(cpp)
+    type std_exception {.importcpp: "std::exception", header: "<exception>".} = object
+
+  proc fun2*() =
+    runnableExamples "-d:foo": discard # checks that it also works inside procs
+
+  template fun3Impl(): untyped =
+    runnableExamples(rdoccmd="-d:foo"):
+      nonexistent
+        # bugfix: this shouldn't be semchecked when `runnableExamples`
+        # has more than 1 argument
+    discard
+
+  proc fun3*[T]() =
+    fun3Impl()
+
+  when false: # future work
+    # passing non-string-litterals (for reuse)
+    const a = "-b:cpp"
+    runnableExamples(a): discard
+
+    # passing seq (to run with multiple compilation options)
+    runnableExamples(@["-b:cpp", "-b:js"]): discard
+
+when true: # bug #16993
+  template examplesInTemplate1*(cond: untyped) =
+    ## in examplesInTemplate1
+    runnableExamples:
+      echo "in examplesInTemplate1"
+    discard
+  examplesInTemplate1 true
+  examplesInTemplate1 true
+  examplesInTemplate1 true
+
+when true: # bug #18054
+  template outer*(body: untyped) =
+    ## outer template doc string.
+    runnableExamples:
+      echo "doc in outer"
+    ##
+    template inner1*() =
+      ## inner1 template doc string.
+      runnableExamples:
+        echo "doc in inner1"
+      ##
+
+    template inner2*() =
+      ## inner2 template doc string.
+      runnableExamples:
+        echo "doc in inner2"
+    body
+  outer:
+    inner1()
+    inner2()
+
+when true: # bug #17835
+  template anyItFake*(s, pred: untyped): bool =
+    ## Foo
+    runnableExamples: discard
+    true
+
+  proc anyItFakeMain*(n: seq[int]): bool =
+    result = anyItFake(n, it == 0)
+      # this was giving: Error: runnableExamples must appear before the first non-comment statement
+
+runnableExamples:
+  block: # bug #17279
+    when int.sizeof == 8:
+      let x = 0xffffffffffffffff
+      doAssert x == -1
+
+  # bug #13491
+  block:
+    proc fun(): int = doAssert false
+    doAssertRaises(AssertionDefect, (discard fun()))
+
+  block:
+    template foo(body) = discard
+    foo (discard)
+
+  block:
+    template fn(body: untyped): untyped = true
+    doAssert(fn do: nonexistent)
+  import std/macros
+  macro foo*(x, y) =
+    result = newLetStmt(x[0][0], x[0][1])
+  foo:
+    a = 1
+  do: discard
+
+# also check for runnableExamples at module scope
+runnableExamples:
+  block:
+    defer: echo "foo8"
+
+runnableExamples:
+  proc fun*()=echo "foo9"
+  fun()
+
+# import std/assertions by default
+runnableExamples("-d:nimPreviewSlimSystem"):
+  doAssert true
+
+# note: there are yet other examples where putting runnableExamples at module
+# scope is needed, for example when using an `include` before an `import`, etc.
+
+##[
+snippet:
+
+.. code-block:: Nim
+    :test:
+
+  doAssert defined(testFooExternal)
+
+]##
+
+when true: # runnableExamples with rdoccmd
+  runnableExamples "-d:testFoo -d:testBar":
+    doAssert defined(testFoo) and defined(testBar)
+    doAssert defined(testFooExternal)
diff --git a/tests/niminaction/Chapter1/various1.nim b/tests/niminaction/Chapter1/various1.nim
new file mode 100644
index 000000000..21553dc40
--- /dev/null
+++ b/tests/niminaction/Chapter1/various1.nim
@@ -0,0 +1,45 @@
+discard """
+  exitCode: 0
+  outputsub: "Woof!"
+"""
+
+import strutils
+echo("hello".to_upper())
+echo("world".toUpper())
+
+type
+  Dog = object #<1>
+    age: int #<2>
+
+let dog = Dog(age: 3) #<3>
+
+proc showNumber(num: int | float) =
+  echo(num)
+
+showNumber(3.14)
+showNumber(42)
+
+for i in 0 ..< 10:
+  echo(i)
+
+block: # Block added due to clash.
+  type
+    Dog = object
+
+  proc bark(self: Dog) = #<1>
+    echo("Woof!")
+
+  let dog = Dog()
+  dog.bark() #<2>
+
+import sequtils, sugar, strutils
+let list = @["Dominik Picheta", "Andreas Rumpf", "Desmond Hume"]
+list.map(
+  (x: string) -> (string, string) => (x.split[0], x.split[1])
+).echo
+
+import strutils
+let list1 = @["Dominik Picheta", "Andreas Rumpf", "Desmond Hume"]
+for name in list1:
+  echo((name.split[0], name.split[1]))
+
diff --git a/tests/niminaction/Chapter2/explicit_discard.nim b/tests/niminaction/Chapter2/explicit_discard.nim
new file mode 100644
index 000000000..7f3b3395e
--- /dev/null
+++ b/tests/niminaction/Chapter2/explicit_discard.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "has to be used (or discarded)"
+  line: 7
+"""
+
+proc myProc(name: string): string = "Hello " & name
+myProc("Dominik")
diff --git a/tests/niminaction/Chapter2/no_def_eq.nim b/tests/niminaction/Chapter2/no_def_eq.nim
new file mode 100644
index 000000000..b9d62e036
--- /dev/null
+++ b/tests/niminaction/Chapter2/no_def_eq.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "type mismatch"
+  line: 16
+"""
+
+type
+    Dog = object
+      name: string
+
+    Cat = object
+      name: string
+
+let dog: Dog = Dog(name: "Fluffy")
+let cat: Cat = Cat(name: "Fluffy")
+
+echo(dog == cat)
diff --git a/tests/niminaction/Chapter2/no_iterator.nim b/tests/niminaction/Chapter2/no_iterator.nim
new file mode 100644
index 000000000..555fac21a
--- /dev/null
+++ b/tests/niminaction/Chapter2/no_iterator.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "type mismatch"
+  line: 6
+"""
+
+for i in 5:
+  echo i
diff --git a/tests/niminaction/Chapter2/no_seq_type.nim b/tests/niminaction/Chapter2/no_seq_type.nim
new file mode 100644
index 000000000..f1494124b
--- /dev/null
+++ b/tests/niminaction/Chapter2/no_seq_type.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "cannot infer the type of the sequence"
+  line: 6
+"""
+
+var list = @[]
diff --git a/tests/niminaction/Chapter2/resultaccept.nim b/tests/niminaction/Chapter2/resultaccept.nim
new file mode 100644
index 000000000..390f7b329
--- /dev/null
+++ b/tests/niminaction/Chapter2/resultaccept.nim
@@ -0,0 +1,28 @@
+discard """
+  output: ""
+"""
+
+# Page 35.
+
+proc implicit: string =
+  "I will be returned"
+  
+proc discarded: string =
+  discard "I will not be returned"
+  
+proc explicit: string =
+  return "I will be returned"
+
+proc resultVar: string =
+  result = "I will be returned"
+  
+proc resultVar2: string =
+  result = ""
+  result.add("I will be ")
+  result.add("returned")
+
+doAssert implicit() == "I will be returned"
+doAssert discarded().len == 0
+doAssert explicit() == "I will be returned"
+doAssert resultVar() == "I will be returned"
+doAssert resultVar2() == "I will be returned"
\ No newline at end of file
diff --git a/tests/niminaction/Chapter2/resultreject.nim b/tests/niminaction/Chapter2/resultreject.nim
new file mode 100644
index 000000000..145345072
--- /dev/null
+++ b/tests/niminaction/Chapter2/resultreject.nim
@@ -0,0 +1,33 @@
+discard """
+  errormsg: "has to be used (or discarded)"
+  line: 27
+"""
+
+# Page 35.
+
+proc implicit: string =
+  "I will be returned"
+
+proc discarded: string =
+  discard "I will not be returned"
+
+proc explicit: string =
+  return "I will be returned"
+
+proc resultVar: string =
+  result = "I will be returned"
+
+proc resultVar2: string =
+  result = ""
+  result.add("I will be ")
+  result.add("returned")
+
+proc resultVar3: string =
+  result = "I am the result"
+  "I will cause an error"
+
+doAssert implicit() == "I will be returned"
+doAssert discarded() == nil
+doAssert explicit() == "I will be returned"
+doAssert resultVar() == "I will be returned"
+doAssert resultVar2() == "I will be returned"
diff --git a/tests/niminaction/Chapter2/various2.nim b/tests/niminaction/Chapter2/various2.nim
new file mode 100644
index 000000000..921f38c7d
--- /dev/null
+++ b/tests/niminaction/Chapter2/various2.nim
@@ -0,0 +1,369 @@
+discard """
+  exitCode: 0
+  outputsub: '''42 is greater than 0'''
+"""
+
+if 42 >= 0:
+  echo "42 is greater than 0"
+
+
+echo("Output: ",
+  5)
+echo(5 +
+  5)
+# --- Removed code that is supposed to fail here. Not going to test those. ---
+
+# Single-line comment
+#[
+Multiline comment
+]#
+when false:
+  echo("Commented-out code")
+
+let decimal = 42
+let hex = 0x42
+let octal = 0o42
+let binary = 0b101010
+
+let a: int16 = 42
+let b = 42'i8
+
+let c = 1'f32 # --- Changed names here to avoid clashes ---
+let d = 1.0e19
+
+let e = false
+let f = true
+
+let g = 'A'
+let h = '\109'
+let i = '\x79'
+
+let text = "The book title is \"Nim in Action\""
+
+let filepath = "C:\\Program Files\\Nim"
+
+# --- Changed name here to avoid clashes ---
+let filepath1 = r"C:\Program Files\Nim"
+
+let multiLine = """foo
+  bar
+  baz
+"""
+echo multiLine
+
+import strutils
+# --- Changed name here to avoid clashes ---
+let multiLine1 = """foo
+  bar
+  baz
+"""
+echo multiLine1.unindent
+doAssert multiLine1.unindent == "foo\nbar\nbaz\n"
+
+proc fillString(): string =
+  result = ""
+  echo("Generating string")
+  for i in 0 .. 4:
+    result.add($i) #<1>
+
+const count = fillString()
+
+var
+  text1 = "hello"
+  number: int = 10
+  isTrue = false
+
+var ç« = "Fire"
+let ogień = true
+
+var `var` = "Hello"
+echo(`var`)
+
+proc myProc(name: string): string = "Hello " & name
+discard myProc("Dominik")
+
+proc bar(): int #<1>
+
+proc foo(): float = bar().float
+proc bar(): int = foo().int
+
+proc noReturn() = echo("Hello")
+proc noReturn2(): void = echo("Hello")
+
+proc noReturn3 = echo("Hello")
+
+proc message(recipient: string): auto =
+  "Hello " & recipient
+
+doAssert message("Dom") == "Hello Dom"
+
+proc max(a: int, b: int): int =
+  if a > b: a else: b
+
+doAssert max(5, 10) == 10
+
+proc max2(a, b: int): int =
+  if a > b: a else: b
+
+proc genHello(name: string, surname = "Doe"): string =
+  "Hello " & name & " " & surname
+
+# -- Leaving these as asserts as that is in the original code, just in case
+# -- somehow in the future `assert` is removed :)
+assert genHello("Peter") == "Hello Peter Doe"
+assert genHello("Peter", "Smith") == "Hello Peter Smith"
+
+proc genHello2(names: varargs[string]): string =
+  result = ""
+  for name in names:
+    result.add("Hello " & name & "\n")
+
+doAssert genHello2("John", "Bob") == "Hello John\nHello Bob\n"
+
+proc getUserCity(firstName, lastName: string): string =
+  case firstName
+  of "Damien": return "Tokyo"
+  of "Alex": return "New York"
+  else: return "Unknown"
+
+proc getUserCity(userID: int): string =
+  case userID
+  of 1: return "Tokyo"
+  of 2: return "New York"
+  else: return "Unknown"
+
+doAssert getUserCity("Damien", "Lundi") == "Tokyo"
+doAssert getUserCity(2) == "New York" # -- Errata here: missing closing "
+
+import sequtils
+let numbers = @[1, 2, 3, 4, 5, 6]
+let odd = filter(numbers, proc (x: int): bool = x mod 2 != 0)
+doAssert odd == @[1, 3, 5]
+
+import sequtils, sugar
+let numbers1 = @[1, 2, 3, 4, 5, 6]
+let odd1 = filter(numbers1, (x: int) -> bool => x mod 2 != 0)
+assert odd1 == @[1, 3, 5]
+
+proc isValid(x: int, validator: proc (x: int): bool) =
+  if validator(x): echo(x, " is valid")
+  else: echo(x, " is NOT valid")
+
+import sugar
+proc isValid2(x: int, validator: (x: int) -> bool) =
+  if validator(x): echo(x, " is valid")
+  else: echo(x, " is NOT valid")
+
+var list: array[3, int]
+list[0] = 1
+list[1] = 42
+assert list[0] == 1
+assert list[1] == 42
+assert list[2] == 0 #<1>
+
+echo list.repr #<2>
+
+# echo list[500]
+
+var list2: array[-10 .. -9, int]
+list2[-10] = 1
+list2[-9] = 2
+
+var list3 = ["Hi", "There"]
+
+var list4 = ["My", "name", "is", "Dominik"]
+for item in list4:
+  echo(item)
+
+for i in list4.low .. list4.high:
+  echo(list4[i])
+
+var list5: seq[int] = @[]
+doAssertRaises(IndexDefect):
+  list5[0] = 1
+
+list5.add(1)
+
+assert list5[0] == 1
+doAssertRaises(IndexDefect):
+  echo list5[42]
+
+# -- Errata: var list: seq[int]; echo(list[0]). This now creates an exception,
+# --         not a SIGSEGV.
+
+block:
+  var list = newSeq[string](3)
+  assert list[0].len == 0
+  list[0] = "Foo"
+  list[1] = "Bar"
+  list[2] = "Baz"
+
+  list.add("Lorem")
+
+block:
+  let list = @[4, 8, 15, 16, 23, 42]
+  for i in 0 ..< list.len:
+    stdout.write($list[i] & " ")
+
+var collection: set[int16]
+doAssert collection == {}
+
+block:
+  let collection = {'a', 'x', 'r'}
+  doAssert 'a' in collection
+
+block:
+  let collection = {'a', 'T', 'z'}
+  let isAllLowerCase = {'A' .. 'Z'} * collection == {}
+  doAssert(not isAllLowerCase)
+
+let age = 10
+if age > 0 and age <= 10:
+  echo("You're still a child")
+elif age > 10 and age < 18:
+  echo("You're a teenager")
+else:
+  echo("You're an adult")
+
+let variable = "Arthur"
+case variable
+of "Arthur", "Zaphod", "Ford":
+  echo("Male")
+of "Marvin":
+  echo("Robot")
+of "Trillian":
+  echo("Female")
+else:
+  echo("Unknown")
+
+let ageDesc = if age < 18: "Non-Adult" else: "Adult"
+
+block:
+  var i = 0
+  while i < 3:
+    echo(i)
+    i.inc
+
+block label:
+  var i = 0
+  while true:
+    while i < 5:
+      if i > 3: break label
+      i.inc
+
+iterator values(): int =
+  var i = 0
+  while i < 5:
+    yield i
+    i.inc
+
+for value in values():
+  echo(value)
+
+import os
+for filename in walkFiles("*.nim"):
+  echo(filename)
+
+for item in @[1, 2, 3]:
+  echo(item)
+
+for i, value in @[1, 2, 3]: echo("Value at ", i, ": ", value)
+
+doAssertRaises(IOError):
+  proc second() =
+    raise newException(IOError, "Somebody set us up the bomb")
+
+  proc first() =
+    second()
+
+  first()
+
+block:
+  proc second() =
+    raise newException(IOError, "Somebody set us up the bomb")
+
+  proc first() =
+    try:
+      second()
+    except:
+      echo("Cannot perform second action because: " &
+        getCurrentExceptionMsg())
+
+  first()
+
+block:
+  type
+    Person = object
+      name: string
+      age: int
+
+  var person: Person
+  var person1 = Person(name: "Neo", age: 28)
+
+block:
+  type
+    PersonObj = object
+      name: string
+      age: int
+    PersonRef = ref PersonObj
+
+  # proc setName(person: PersonObj) =
+  #   person.name = "George"
+
+  proc setName(person: PersonRef) =
+    person.name = "George"
+
+block:
+  type
+    Dog = object
+      name: string
+
+    Cat = object
+      name: string
+
+  let dog: Dog = Dog(name: "Fluffy")
+  let cat: Cat = Cat(name: "Fluffy")
+
+block:
+  type
+    Dog = tuple
+      name: string
+
+    Cat = tuple
+      name: string
+
+  let dog: Dog = (name: "Fluffy")
+  let cat: Cat = (name: "Fluffy")
+
+  echo(dog == cat)
+
+block:
+  type
+    Point = tuple[x, y: int]
+    Point2 = (int, int)
+
+  let pos: Point = (x: 100, y: 50)
+  doAssert pos == (100, 50)
+
+  let pos1: Point = (x: 100, y: 50)
+  let (x, y) = pos1 #<1>
+  let (left, _) = pos1
+  doAssert x == pos1[0]
+  doAssert y == pos1[1]
+  doAssert left == x
+
+block:
+  type
+    Color = enum
+      colRed,
+      colGreen,
+      colBlue
+
+  let color: Color = colRed
+
+block:
+  type
+    Color {.pure.} = enum
+      red, green, blue
+
+  let color = Color.red
diff --git a/tests/niminaction/Chapter3/ChatApp/readme.markdown b/tests/niminaction/Chapter3/ChatApp/readme.markdown
new file mode 100644
index 000000000..200b4df1d
--- /dev/null
+++ b/tests/niminaction/Chapter3/ChatApp/readme.markdown
@@ -0,0 +1,26 @@
+# The ChatApp source code
+
+This directory contains the ChatApp project, which is the project that is
+created as part of Chapter 3 of the Nim in Action book.
+
+To compile run:
+
+```
+nim c src/client
+nim c src/server
+```
+
+You can then run the ``server`` in one terminal by executing ``./src/server``.
+
+After doing so you can execute multiple clients in different terminals and have
+them communicate via the server.
+
+To execute a client, make sure to specify the server address and user name
+on the command line:
+
+```bash
+./src/client localhost Peter
+```
+
+You should then be able to start typing in messages and sending them
+by pressing the Enter key.
\ No newline at end of file
diff --git a/tests/niminaction/Chapter3/ChatApp/src/client.nim b/tests/niminaction/Chapter3/ChatApp/src/client.nim
new file mode 100644
index 000000000..d479ebf43
--- /dev/null
+++ b/tests/niminaction/Chapter3/ChatApp/src/client.nim
@@ -0,0 +1,58 @@
+discard """
+action: compile
+"""
+
+import os, threadpool, asyncdispatch, asyncnet
+import protocol
+
+proc connect(socket: AsyncSocket, serverAddr: string) {.async.} =
+  ## Connects the specified AsyncSocket to the specified address.
+  ## Then receives messages from the server continuously.
+  echo("Connecting to ", serverAddr)
+  # Pause the execution of this procedure until the socket connects to
+  # the specified server.
+  await socket.connect(serverAddr, 7687.Port)
+  echo("Connected!")
+  while true:
+    # Pause the execution of this procedure until a new message is received
+    # from the server.
+    let line = await socket.recvLine()
+    # Parse the received message using ``parseMessage`` defined in the
+    # protocol module.
+    let parsed = parseMessage(line)
+    # Display the message to the user.
+    echo(parsed.username, " said ", parsed.message)
+
+echo("Chat application started")
+# Ensure that the correct amount of command line arguments was specified.
+if paramCount() < 2:
+  # Terminate the client early with an error message if there was not
+  # enough command line arguments specified by the user.
+  quit("Please specify the server address, e.g. ./client localhost username")
+
+# Retrieve the first command line argument.
+let serverAddr = paramStr(1)
+# Retrieve the second command line argument.
+let username = paramStr(2)
+# Initialise a new asynchronous socket.
+var socket = newAsyncSocket()
+
+# Execute the ``connect`` procedure in the background asynchronously.
+asyncCheck connect(socket, serverAddr)
+# Execute the ``readInput`` procedure in the background in a new thread.
+var messageFlowVar = spawn stdin.readLine()
+while true:
+  # Check if the ``readInput`` procedure returned a new line of input.
+  if messageFlowVar.isReady():
+    # If a new line of input was returned, we can safely retrieve it
+    # without blocking.
+    # The ``createMessage`` is then used to create a message based on the
+    # line of input. The message is then sent in the background asynchronously.
+    asyncCheck socket.send(createMessage(username, ^messageFlowVar))
+    # Execute the ``readInput`` procedure again, in the background in a
+    # new thread.
+    messageFlowVar = spawn stdin.readLine()
+
+  # Execute the asyncdispatch event loop, to continue the execution of
+  # asynchronous procedures.
+  asyncdispatch.poll()
diff --git a/tests/niminaction/Chapter3/ChatApp/src/client.nim.cfg b/tests/niminaction/Chapter3/ChatApp/src/client.nim.cfg
new file mode 100644
index 000000000..aed303eef
--- /dev/null
+++ b/tests/niminaction/Chapter3/ChatApp/src/client.nim.cfg
@@ -0,0 +1 @@
+--threads:on
diff --git a/tests/niminaction/Chapter3/ChatApp/src/protocol.nim b/tests/niminaction/Chapter3/ChatApp/src/protocol.nim
new file mode 100644
index 000000000..4c122d4cc
--- /dev/null
+++ b/tests/niminaction/Chapter3/ChatApp/src/protocol.nim
@@ -0,0 +1,55 @@
+import json
+
+type
+  Message* = object
+    username*: string
+    message*: string
+
+  MessageParsingError* = object of Exception
+
+proc parseMessage*(data: string): Message {.raises: [MessageParsingError, KeyError].} =
+  var dataJson: JsonNode
+  try:
+    dataJson = parseJson(data)
+  except JsonParsingError:
+    raise newException(MessageParsingError, "Invalid JSON: " &
+                       getCurrentExceptionMsg())
+  except:
+    raise newException(MessageParsingError, "Unknown error: " &
+                       getCurrentExceptionMsg())
+
+  if not dataJson.hasKey("username"):
+    raise newException(MessageParsingError, "Username field missing")
+
+  result.username = dataJson["username"].getStr()
+  if result.username.len == 0:
+    raise newException(MessageParsingError, "Username field is empty")
+
+  if not dataJson.hasKey("message"):
+    raise newException(MessageParsingError, "Message field missing")
+  result.message = dataJson["message"].getStr()
+  if result.message.len == 0:
+    raise newException(MessageParsingError, "Message field is empty")
+
+proc createMessage*(username, message: string): string =
+  result = $(%{
+    "username": %username,
+    "message": %message
+  }) & "\c\l"
+
+when true:
+  block:
+    let data = """{"username": "dom", "message": "hello"}"""
+    let parsed = parseMessage(data)
+    doAssert parsed.message == "hello"
+    doAssert parsed.username == "dom"
+
+  # Test failure
+  block:
+    try:
+      let parsed = parseMessage("asdasd")
+    except MessageParsingError:
+      doAssert true
+    except:
+      doAssert false
+
diff --git a/tests/niminaction/Chapter3/ChatApp/src/server.nim b/tests/niminaction/Chapter3/ChatApp/src/server.nim
new file mode 100644
index 000000000..fbf0e5110
--- /dev/null
+++ b/tests/niminaction/Chapter3/ChatApp/src/server.nim
@@ -0,0 +1,88 @@
+discard """
+action: compile
+"""
+
+import asyncdispatch, asyncnet
+
+type
+  Client = ref object
+    socket: AsyncSocket
+    netAddr: string
+    id: int
+    connected: bool
+
+  Server = ref object
+    socket: AsyncSocket
+    clients: seq[Client]
+
+proc newServer(): Server =
+  ## Constructor for creating a new ``Server``.
+  Server(socket: newAsyncSocket(), clients: @[])
+
+proc `$`(client: Client): string =
+  ## Converts a ``Client``'s information into a string.
+  $client.id & "(" & client.netAddr & ")"
+
+proc processMessages(server: Server, client: Client) {.async.} =
+  ## Loops while ``client`` is connected to this server, and checks
+  ## whether as message has been received from ``client``.
+  while true:
+    # Pause execution of this procedure until a line of data is received from
+    # ``client``.
+    let line = await client.socket.recvLine()
+
+    # The ``recvLine`` procedure returns ``""`` (i.e. a string of length 0)
+    # when ``client`` has disconnected.
+    if line.len == 0:
+      echo(client, " disconnected!")
+      client.connected = false
+      # When a socket disconnects it must be closed.
+      client.socket.close()
+      return
+
+    # Display the message that was sent by the client.
+    echo(client, " sent: ", line)
+
+    # Send the message to other clients.
+    for c in server.clients:
+      # Don't send it to the client that sent this or to a client that is
+      # disconnected.
+      if c.id != client.id and c.connected:
+        await c.socket.send(line & "\c\l")
+
+proc loop(server: Server, port = 7687) {.async.} =
+  ## Loops forever and checks for new connections.
+
+  # Bind the port number specified by ``port``.
+  server.socket.bindAddr(port.Port)
+  # Ready the server socket for new connections.
+  server.socket.listen()
+  echo("Listening on localhost:", port)
+
+  while true:
+    # Pause execution of this procedure until a new connection is accepted.
+    let (netAddr, clientSocket) = await server.socket.acceptAddr()
+    echo("Accepted connection from ", netAddr)
+
+    # Create a new instance of Client.
+    let client = Client(
+      socket: clientSocket,
+      netAddr: netAddr,
+      id: server.clients.len,
+      connected: true
+    )
+    # Add this new instance to the server's list of clients.
+    server.clients.add(client)
+    # Run the ``processMessages`` procedure asynchronously in the background,
+    # this procedure will continuously check for new messages from the client.
+    asyncCheck processMessages(server, client)
+
+# Check whether this module has been imported as a dependency to another
+# module, or whether this module is the main module.
+when true:
+  # Initialise a new server.
+  var server = newServer()
+  echo("Server initialised!")
+  # Execute the ``loop`` procedure. The ``waitFor`` procedure will run the
+  # asyncdispatch event loop until the ``loop`` procedure finishes executing.
+  waitFor loop(server)
diff --git a/tests/niminaction/Chapter3/various3.nim b/tests/niminaction/Chapter3/various3.nim
new file mode 100644
index 000000000..c7cdf7db4
--- /dev/null
+++ b/tests/niminaction/Chapter3/various3.nim
@@ -0,0 +1,99 @@
+discard """
+matrix: "--mm:refc"
+output: '''
+Future is no longer empty, 42
+'''
+"""
+
+import threadpool
+proc foo: string = "Dog"
+var x: FlowVar[string] = spawn foo()
+doAssert(^x == "Dog")
+
+block:
+  type
+    Box = object
+      case empty: bool
+      of false:
+        contents: string
+      else:
+        discard
+
+  var obj = Box(empty: false, contents: "Hello")
+  doAssert obj.contents == "Hello"
+
+  var obj2 = Box(empty: true)
+  doAssertRaises(FieldDefect):
+    echo(obj2.contents)
+
+import json
+doAssert parseJson("null").kind == JNull
+doAssert parseJson("true").kind == JBool
+doAssert parseJson("42").kind == JInt
+doAssert parseJson("3.14").kind == JFloat
+doAssert parseJson("\"Hi\"").kind == JString
+doAssert parseJson("""{ "key": "value" }""").kind == JObject
+doAssert parseJson("[1, 2, 3, 4]").kind == JArray
+
+import json
+let data = """
+  {"username": "Dominik"}
+"""
+
+let obj = parseJson(data)
+doAssert obj.kind == JObject
+doAssert obj["username"].kind == JString
+doAssert obj["username"].str == "Dominik"
+
+block:
+  proc count10(): int =
+    for i in 0 ..< 10:
+      result.inc
+  doAssert count10() == 10
+
+type
+  Point = tuple[x, y: int]
+
+var point = (5, 10)
+var point2 = (x: 5, y: 10)
+
+type
+  Human = object
+    name: string
+    age: int
+
+var jeff = Human(name: "Jeff", age: 23)
+var amy = Human(name: "Amy", age: 20)
+
+import asyncdispatch
+
+var future = newFuture[int]()
+doAssert(not future.finished)
+
+future.callback =
+  proc (future: Future[int]) =
+    echo("Future is no longer empty, ", future.read)
+
+future.complete(42)
+
+import asyncdispatch, asyncfile
+
+when false:
+  var file = openAsync("")
+  let dataFut = file.readAll()
+  dataFut.callback =
+    proc (future: Future[string]) =
+      echo(future.read())
+
+  asyncdispatch.runForever()
+
+import asyncdispatch, asyncfile, os
+
+proc readFiles() {.async.} =
+  # --- Changed to getTempDir here.
+  var file = openAsync(getTempDir() / "test.txt", fmReadWrite)
+  let data = await file.readAll()
+  echo(data)
+  await file.write("Hello!\n")
+
+waitFor readFiles()
diff --git a/tests/niminaction/Chapter3/various3.nim.cfg b/tests/niminaction/Chapter3/various3.nim.cfg
new file mode 100644
index 000000000..6c1ded992
--- /dev/null
+++ b/tests/niminaction/Chapter3/various3.nim.cfg
@@ -0,0 +1 @@
+threads:on
\ No newline at end of file
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
new file mode 100644
index 000000000..913cd77db
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim
@@ -0,0 +1,83 @@
+discard """
+action: compile
+"""
+
+# See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
+import tables, parseutils, strutils, threadpool
+
+const filename = "pagecounts-20160101-050000"
+
+type
+  Stats = ref object
+    projectName, pageTitle: string
+    requests, contentSize: int
+
+proc `$`(stats: Stats): string =
+  "(projectName: $#, pageTitle: $#, requests: $#, contentSize: $#)" % [
+    stats.projectName, stats.pageTitle, $stats.requests, $stats.contentSize
+  ]
+
+proc parse(chunk: string): Stats =
+  # Each line looks like: en Main_Page 242332 4737756101
+  result = Stats(projectName: "", pageTitle: "", requests: 0, contentSize: 0)
+
+  var projectName = ""
+  var pageTitle = ""
+  var requests = ""
+  var contentSize = ""
+  for line in chunk.splitLines:
+    var i = 0
+    projectName.setLen(0)
+    i.inc parseUntil(line, projectName, Whitespace, i)
+    i.inc skipWhitespace(line, i)
+    pageTitle.setLen(0)
+    i.inc parseUntil(line, pageTitle, Whitespace, i)
+    i.inc skipWhitespace(line, i)
+    requests.setLen(0)
+    i.inc parseUntil(line, requests, Whitespace, i)
+    i.inc skipWhitespace(line, i)
+    contentSize.setLen(0)
+    i.inc parseUntil(line, contentSize, Whitespace, i)
+    i.inc skipWhitespace(line, i)
+
+    if requests.len == 0 or contentSize.len == 0:
+      # Ignore lines with either of the params that are empty.
+      continue
+
+    let requestsInt = requests.parseInt
+    if requestsInt > result.requests and projectName == "en":
+      result = Stats(
+        projectName: projectName,
+        pageTitle: pageTitle,
+        requests: requestsInt,
+        contentSize: contentSize.parseInt
+      )
+
+proc readChunks(filename: string, chunksize = 1000000): Stats =
+  result = Stats(projectName: "", pageTitle: "", requests: 0, contentSize: 0)
+  var file = open(filename)
+  var responses = newSeq[FlowVar[Stats]]()
+  var buffer = newString(chunksize)
+  var oldBufferLen = 0
+  while not endOfFile(file):
+    let readSize = file.readChars(buffer, oldBufferLen, chunksize - oldBufferLen) + oldBufferLen
+    var chunkLen = readSize
+
+    while chunkLen >= 0 and buffer[chunkLen - 1] notin NewLines:
+      # Find where the last line ends
+      chunkLen.dec
+
+    responses.add(spawn parse(buffer[0 ..< chunkLen]))
+    oldBufferLen = readSize - chunkLen
+    buffer[0 ..< oldBufferLen] = buffer[readSize - oldBufferLen .. ^1]
+
+  for resp in responses:
+    let statistic = ^resp
+    if statistic.requests > result.requests:
+      result = statistic
+
+  file.close()
+
+
+when true:
+  echo readChunks(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim.cfg b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim.cfg
new file mode 100644
index 000000000..aed303eef
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency.nim.cfg
@@ -0,0 +1 @@
+--threads:on
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
new file mode 100644
index 000000000..102313de9
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim
@@ -0,0 +1,68 @@
+discard """
+action: compile
+"""
+
+# See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
+import tables, parseutils, strutils, threadpool, re
+
+const filename = "pagecounts-20160101-050000"
+
+type
+  Stats = ref object
+    projectName, pageTitle: string
+    requests, contentSize: int
+
+proc `$`(stats: Stats): string =
+  "(projectName: $#, pageTitle: $#, requests: $#, contentSize: $#)" % [
+    stats.projectName, stats.pageTitle, $stats.requests, $stats.contentSize
+  ]
+
+proc parse(chunk: string): Stats =
+  # Each line looks like: en Main_Page 242332 4737756101
+  result = Stats(projectName: "", pageTitle: "", requests: 0, contentSize: 0)
+
+  var matches: array[4, string]
+  var reg = re"([^\s]+)\s([^\s]+)\s(\d+)\s(\d+)"
+  for line in chunk.splitLines:
+
+    let start = find(line, reg, matches)
+    if start == -1: continue
+
+    let requestsInt = matches[2].parseInt
+    if requestsInt > result.requests and matches[0] == "en":
+      result = Stats(
+        projectName: matches[0],
+        pageTitle: matches[1],
+        requests: requestsInt,
+        contentSize: matches[3].parseInt
+      )
+
+proc readChunks(filename: string, chunksize = 1000000): Stats =
+  result = Stats(projectName: "", pageTitle: "", requests: 0, contentSize: 0)
+  var file = open(filename)
+  var responses = newSeq[FlowVar[Stats]]()
+  var buffer = newString(chunksize)
+  var oldBufferLen = 0
+  while not endOfFile(file):
+    let readSize = file.readChars(buffer, oldBufferLen, chunksize - oldBufferLen) + oldBufferLen
+    var chunkLen = readSize
+
+    while chunkLen >= 0 and buffer[chunkLen - 1] notin NewLines:
+      # Find where the last line ends
+      chunkLen.dec
+
+    responses.add(spawn parse(buffer[0 ..< chunkLen]))
+    oldBufferLen = readSize - chunkLen
+    buffer[0 ..< oldBufferLen] = buffer[readSize - oldBufferLen .. ^1]
+
+  echo("Spawns: ", responses.len)
+  for resp in responses:
+    let statistic = ^resp
+    if statistic.requests > result.requests:
+      result = statistic
+
+  file.close()
+
+
+when true:
+  echo readChunks(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim.cfg b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim.cfg
new file mode 100644
index 000000000..aed303eef
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/concurrency_regex.nim.cfg
@@ -0,0 +1 @@
+--threads:on
diff --git a/tests/niminaction/Chapter6/WikipediaStats/naive.nim b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
new file mode 100644
index 000000000..687177f74
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/naive.nim
@@ -0,0 +1,33 @@
+discard """
+action: compile
+"""
+
+# See this page for info about the format https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-all-sites
+import tables, parseutils, strutils
+
+const filename = "pagecounts-20150101-050000"
+
+proc parse(filename: string): tuple[projectName, pageTitle: string,
+    requests, contentSize: int] =
+  # Each line looks like: en Main_Page 242332 4737756101
+  var file = open(filename)
+  for line in file.lines:
+    var i = 0
+    var projectName = ""
+    i.inc parseUntil(line, projectName, Whitespace, i)
+    i.inc
+    var pageTitle = ""
+    i.inc parseUntil(line, pageTitle, Whitespace, i)
+    i.inc
+    var requests = 0
+    i.inc parseInt(line, requests, i)
+    i.inc
+    var contentSize = 0
+    i.inc parseInt(line, contentSize, i)
+    if requests > result[2] and projectName == "en":
+      result = (projectName, pageTitle, requests, contentSize)
+
+  file.close()
+
+when true:
+  echo parse(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
new file mode 100644
index 000000000..379ec7364
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim
@@ -0,0 +1,76 @@
+discard """
+action: compile
+"""
+
+import os, parseutils, threadpool, strutils
+
+type
+  Stats = ref object
+    domainCode, pageTitle: string
+    countViews, totalSize: int
+
+proc newStats(): Stats =
+  Stats(domainCode: "", pageTitle: "", countViews: 0, totalSize: 0)
+
+proc `$`(stats: Stats): string =
+  "(domainCode: $#, pageTitle: $#, countViews: $#, totalSize: $#)" % [
+    stats.domainCode, stats.pageTitle, $stats.countViews, $stats.totalSize
+  ]
+
+proc parse(line: string, domainCode, pageTitle: var string,
+    countViews, totalSize: var int) =
+  if line.len == 0: return
+  var i = 0
+  domainCode.setLen(0)
+  i.inc parseUntil(line, domainCode, {' '}, i)
+  i.inc
+  pageTitle.setLen(0)
+  i.inc parseUntil(line, pageTitle, {' '}, i)
+  i.inc
+  countViews = 0
+  i.inc parseInt(line, countViews, i)
+  i.inc
+  totalSize = 0
+  i.inc parseInt(line, totalSize, i)
+
+proc parseChunk(chunk: string): Stats =
+  result = newStats()
+  var domainCode = ""
+  var pageTitle = ""
+  var countViews = 0
+  var totalSize = 0
+  for line in splitLines(chunk):
+    parse(line, domainCode, pageTitle, countViews, totalSize)
+    if domainCode == "en" and countViews > result.countViews:
+      result = Stats(domainCode: domainCode, pageTitle: pageTitle,
+                     countViews: countViews, totalSize: totalSize)
+
+proc readPageCounts(filename: string, chunkSize = 1_000_000) =
+  var file = open(filename)
+  var responses = newSeq[FlowVar[Stats]]()
+  var buffer = newString(chunksize)
+  var oldBufferLen = 0
+  while not endOfFile(file):
+    let reqSize = chunksize - oldBufferLen
+    let readSize = file.readChars(buffer, oldBufferLen, reqSize) + oldBufferLen
+    var chunkLen = readSize
+
+    while chunkLen >= 0 and buffer[chunkLen - 1] notin NewLines:
+      chunkLen.dec
+
+    responses.add(spawn parseChunk(buffer[0 ..< chunkLen]))
+    oldBufferLen = readSize - chunkLen
+    buffer[0 ..< oldBufferLen] = buffer[readSize - oldBufferLen .. ^1]
+
+  var mostPopular = newStats()
+  for resp in responses:
+    let statistic = ^resp
+    if statistic.countViews > mostPopular.countViews:
+      mostPopular = statistic
+
+  echo("Most popular is: ", mostPopular)
+
+when true:
+  const file = "pagecounts-20160101-050000"
+  let filename = getCurrentDir() / file
+  readPageCounts(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim.cfg b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim.cfg
new file mode 100644
index 000000000..9d57ecf93
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/parallel_counts.nim.cfg
@@ -0,0 +1 @@
+--threads:on
\ No newline at end of file
diff --git a/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
new file mode 100644
index 000000000..f4b072204
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim
@@ -0,0 +1,17 @@
+discard """
+action: compile
+"""
+
+import threadpool
+
+var counter = 0
+
+proc increment(x: int) =
+  for i in 0 ..< x:
+    let value = counter + 1
+    counter = value
+
+spawn increment(10_000)
+spawn increment(10_000)
+sync()
+echo(counter)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim.cfg b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim.cfg
new file mode 100644
index 000000000..9d57ecf93
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/race_condition.nim.cfg
@@ -0,0 +1 @@
+--threads:on
\ No newline at end of file
diff --git a/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim b/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
new file mode 100644
index 000000000..f4bae3df5
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/sequential_counts.nim
@@ -0,0 +1,38 @@
+discard """
+action: compile
+"""
+
+import os, parseutils
+
+proc parse(line: string, domainCode, pageTitle: var string,
+    countViews, totalSize: var int) =
+  var i = 0
+  domainCode.setLen(0)
+  i.inc parseUntil(line, domainCode, {' '}, i)
+  i.inc
+  pageTitle.setLen(0)
+  i.inc parseUntil(line, pageTitle, {' '}, i)
+  i.inc
+  countViews = 0
+  i.inc parseInt(line, countViews, i)
+  i.inc
+  totalSize = 0
+  i.inc parseInt(line, totalSize, i)
+
+proc readPageCounts(filename: string) =
+  var domainCode = ""
+  var pageTitle = ""
+  var countViews = 0
+  var totalSize = 0
+  var mostPopular = ("", "", 0, 0)
+  for line in filename.lines:
+    parse(line, domainCode, pageTitle, countViews, totalSize)
+    if domainCode == "en" and countViews > mostPopular[2]:
+      mostPopular = (domainCode, pageTitle, countViews, totalSize)
+
+  echo("Most popular is: ", mostPopular)
+
+when true:
+  const file = "pagecounts-20160101-050000"
+  let filename = getCurrentDir() / file
+  readPageCounts(filename)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim b/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim
new file mode 100644
index 000000000..7bdde8397
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "unguarded access: counter"
+  line: 14
+"""
+
+import threadpool, locks
+
+var counterLock: Lock
+initLock(counterLock)
+var counter {.guard: counterLock.} = 0
+
+proc increment(x: int) =
+  for i in 0 ..< x:
+    let value = counter + 1
+    counter = value
+
+spawn increment(10_000)
+spawn increment(10_000)
+sync()
+echo(counter)
diff --git a/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim.cfg b/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim.cfg
new file mode 100644
index 000000000..9d57ecf93
--- /dev/null
+++ b/tests/niminaction/Chapter6/WikipediaStats/unguarded_access.nim.cfg
@@ -0,0 +1 @@
+--threads:on
\ No newline at end of file
diff --git a/tests/niminaction/Chapter7/Tweeter/Tweeter.nimble b/tests/niminaction/Chapter7/Tweeter/Tweeter.nimble
new file mode 100644
index 000000000..0a0ffad1a
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/Tweeter.nimble
@@ -0,0 +1,14 @@
+# Package
+
+version       = "0.1.0"
+author        = "Dominik Picheta"
+description   = "A simple Twitter clone developed in Nim in Action."
+license       = "MIT"
+
+bin = @["tweeter"]
+skipExt = @["nim"]
+
+# Dependencies
+
+requires "nim >= 0.13.1"
+requires "jester >= 0.0.1"
diff --git a/tests/niminaction/Chapter7/Tweeter/public/style.css b/tests/niminaction/Chapter7/Tweeter/public/style.css
new file mode 100644
index 000000000..baacfaf9d
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/public/style.css
@@ -0,0 +1,117 @@
+body {
+  background-color: #f1f9ea;
+  margin: 0;
+  font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+}
+
+div#main {
+  width: 80%;
+  margin-left: auto;
+  margin-right: auto;
+}
+
+div#user {
+  background-color: #66ac32;
+  width: 100%;
+  color: #c7f0aa;
+  padding: 5pt;
+}
+
+div#user > h1 {
+  color: #ffffff;
+}
+
+h1 {
+  margin: 0;
+  display: inline;
+  padding-left: 10pt;
+  padding-right: 10pt;
+}
+
+div#user > form {
+  float: right;
+  margin-right: 10pt;
+}
+
+div#user > form > input[type="submit"] {
+  border: 0px none;
+  padding: 5pt;
+  font-size: 108%;
+  color: #ffffff;
+  background-color: #515d47;
+  border-radius: 5px;
+  cursor: pointer;
+}
+
+div#user > form > input[type="submit"]:hover {
+  background-color: #538c29;
+}
+
+
+div#messages {
+  background-color: #a2dc78;
+  width: 90%;
+  margin-left: auto;
+  margin-right: auto;
+  color: #1a1a1a;
+}
+
+div#messages > div {
+  border-left: 1px solid #869979;
+  border-right: 1px solid #869979;
+  border-bottom: 1px solid #869979;
+  padding: 5pt;
+}
+
+div#messages > div > a, div#messages > div > span {
+  color: #475340;
+}
+
+div#messages > div > a:hover {
+  text-decoration: none;
+  color: #c13746;
+}
+
+h3 {
+  margin-bottom: 0;
+  font-weight: normal;
+}
+
+div#login {
+  width: 200px;
+  margin-left: auto;
+  margin-right: auto;
+  margin-top: 20%;
+
+  font-size: 130%;
+}
+
+div#login span.small {
+  display: block;
+  font-size: 56%;
+}
+
+div#newMessage {
+  background-color: #538c29;
+  width: 90%;
+  margin-left: auto;
+  margin-right: auto;
+  color: #ffffff;
+  padding: 5pt;
+}
+
+div#newMessage span {
+  padding-right: 5pt;
+}
+
+div#newMessage form {
+  display: inline;
+}
+
+div#newMessage > form > input[type="text"] {
+  width: 80%;
+}
+
+div#newMessage > form > input[type="submit"] {
+  font-size: 80%;
+}
diff --git a/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
new file mode 100644
index 000000000..67d9323f2
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/src/createDatabase.nim
@@ -0,0 +1,11 @@
+discard """
+disabled: true
+output: "Database created successfully!"
+"""
+
+import database
+
+var db = newDatabase()
+db.setup()
+echo("Database created successfully!")
+db.close()
diff --git a/tests/niminaction/Chapter7/Tweeter/src/database.nim b/tests/niminaction/Chapter7/Tweeter/src/database.nim
new file mode 100644
index 000000000..bd6667f70
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/src/database.nim
@@ -0,0 +1,93 @@
+import times, db_sqlite, strutils #<1>
+type #<2>
+  Database* = ref object
+    db*: DbConn
+
+  User* = object #<3>
+    username*: string #<4>
+    following*: seq[string] #<5>
+
+  Message* = object #<6>
+    username*: string #<7>
+    time*: Time #<8>
+    msg*: string #<9>
+
+proc newDatabase*(filename = "tweeter.db"): Database =
+  new result
+  result.db = open(filename, "", "", "")
+
+proc close*(database: Database) =
+ database.db.close()
+
+proc setup*(database: Database) =
+  database.db.exec(sql"""
+    CREATE TABLE IF NOT EXISTS User(
+      username text PRIMARY KEY
+    );
+  """)
+
+  database.db.exec(sql"""
+    CREATE TABLE IF NOT EXISTS Following(
+      follower text,
+      followed_user text,
+      PRIMARY KEY (follower, followed_user),
+      FOREIGN KEY (follower) REFERENCES User(username),
+      FOREIGN KEY (followed_user) REFERENCES User(username)
+    );
+  """)
+
+  database.db.exec(sql"""
+    CREATE TABLE IF NOT EXISTS Message(
+      username text,
+      time integer,
+      msg text NOT NULL,
+      FOREIGN KEY (username) REFERENCES User(username)
+    );
+  """)
+
+proc post*(database: Database, message: Message) =
+  if message.msg.len > 140: #<1>
+    raise newException(ValueError, "Message has to be less than 140 characters.")
+
+  database.db.exec(sql"INSERT INTO Message VALUES (?, ?, ?);", #<2>
+    message.username, $message.time.toUnix().int, message.msg) #<3>
+
+proc follow*(database: Database, follower: User, user: User) =
+  database.db.exec(sql"INSERT INTO Following VALUES (?, ?);",#<2>
+    follower.username, user.username)
+
+proc create*(database: Database, user: User) =
+  database.db.exec(sql"INSERT INTO User VALUES (?);", user.username) #<2>
+
+proc findUser*(database: Database, username: string, user: var User): bool =
+  let row = database.db.getRow(
+      sql"SELECT username FROM User WHERE username = ?;", username)
+  if row[0].len == 0: return false
+  else: user.username = row[0]
+
+  let following = database.db.getAllRows(
+      sql"SELECT followed_user FROM Following WHERE follower = ?;", username)
+  user.following = @[]
+  for row in following:
+    if row[0].len != 0:
+      user.following.add(row[0])
+
+  return true
+
+proc findMessages*(database: Database, usernames: seq[string],
+    limit = 10): seq[Message] =
+  result = @[]
+  if usernames.len == 0: return
+  var whereClause = " WHERE "
+  for i in 0 ..< usernames.len:
+    whereClause.add("username = ? ")
+    if i != usernames.high:
+      whereClause.add("or ")
+
+  let messages = database.db.getAllRows(
+      sql("SELECT username, time, msg FROM Message" &
+          whereClause &
+          "ORDER BY time DESC LIMIT " & $limit),
+      usernames)
+  for row in messages:
+    result.add(Message(username: row[0], time: fromUnix(row[1].parseInt), msg: row[2]))
diff --git a/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
new file mode 100644
index 000000000..1b521521c
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/src/tweeter.nim
@@ -0,0 +1,68 @@
+discard """
+disabled: true
+action: compile
+matrix: "--threads:off"
+"""
+
+import asyncdispatch, times
+
+import jester
+
+import database, views/user, views/general
+
+proc userLogin(db: Database, request: Request, user: var User): bool =
+  if request.cookies.hasKey("username"):
+    if not db.findUser(request.cookies["username"], user):
+      user = User(username: request.cookies["username"], following: @[])
+      db.create(user)
+    return true
+  else:
+    return false
+
+let db = newDatabase()
+routes:
+  get "/":
+    var user: User
+    if db.userLogin(request, user):
+      let messages = db.findMessages(user.following & user.username)
+      resp renderMain(renderTimeline(user.username, messages))
+    else:
+      resp renderMain(renderLogin())
+
+  get "/@name":
+    cond '.' notin @"name"
+    var user: User
+    if not db.findUser(@"name", user):
+      halt "User not found"
+    let messages = db.findMessages(@[user.username])
+
+    var currentUser: User
+    if db.userLogin(request, currentUser):
+      resp renderMain(renderUser(user, currentUser) & renderMessages(messages))
+    else:
+      resp renderMain(renderUser(user) & renderMessages(messages))
+
+  post "/follow":
+    var follower: User
+    var target: User
+    if not db.findUser(@"follower", follower):
+      halt "Follower not found"
+    if not db.findUser(@"target", target):
+      halt "Follow target not found"
+    db.follow(follower, target)
+    redirect(uri("/" & @"target"))
+
+  post "/login":
+    setCookie("username", @"username", getTime().utc() + 2.hours)
+    redirect("/")
+
+  post "/createMessage":
+    let message = Message(
+      username: @"username",
+      time: getTime(),
+      msg: @"message"
+    )
+    db.post(message)
+    redirect("/")
+
+runForever()
diff --git a/tests/niminaction/Chapter7/Tweeter/src/views/general.nim b/tests/niminaction/Chapter7/Tweeter/src/views/general.nim
new file mode 100644
index 000000000..0e920b1de
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/src/views/general.nim
@@ -0,0 +1,51 @@
+#? stdtmpl(subsChar = '$', metaChar = '#')
+#import "../database"
+#import user
+#import xmltree
+#
+#proc `$!`(text: string): string = escape(text)
+#end proc
+#
+#proc renderMain*(body: string): string =
+#  result = ""
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Tweeter written in Nim</title>
+    <link rel="stylesheet" type="text/css" href="style.css">
+  </head>
+
+  <body>
+    ${body}
+  </body>
+
+</html>
+#end proc
+#
+#proc renderLogin*(): string =
+#  result = ""
+<div id="login">
+  <span>Login</span>
+  <span class="small">Please type in your username...</span>
+  <form action="login" method="post">
+    <input type="text" name="username">
+    <input type="submit" value="Login">
+  </form>
+</div>
+#end proc
+#
+#proc renderTimeline*(username: string, messages: seq[Message]): string =
+#  result = ""
+<div id="user">
+  <h1>${$!username}'s timeline</h1>
+</div>
+<div id="newMessage">
+  <span>New message</span>
+  <form action="createMessage" method="post">
+    <input type="text" name="message">
+    <input type="hidden" name="username" value="${$!username}">
+    <input type="submit" value="Tweet">
+  </form>
+</div>
+${renderMessages(messages)}
+#end proc
\ No newline at end of file
diff --git a/tests/niminaction/Chapter7/Tweeter/src/views/user.nim b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim
new file mode 100644
index 000000000..4abcf440d
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/src/views/user.nim
@@ -0,0 +1,49 @@
+#? stdtmpl(subsChar = '$', metaChar = '#', toString = "xmltree.escape")
+#import "../database"
+#import xmltree
+#import times
+#
+#proc renderUser*(user: User): string =
+#  result = ""
+<div id="user">
+  <h1>${user.username}</h1>
+  <span>Following: ${$user.following.len}</span>
+</div>
+#end proc
+#
+#proc renderUser*(user: User, currentUser: User): string =
+#  result = ""
+<div id="user">
+  <h1>${user.username}</h1>
+  <span>Following: ${$user.following.len}</span>
+  #if user.username notin currentUser.following:
+  <form action="follow" method="post">
+    <input type="hidden" name="follower" value="${currentUser.username}">
+    <input type="hidden" name="target" value="${user.username}">
+    <input type="submit" value="Follow">
+  </form>
+  #end if
+</div>
+#
+#end proc
+#
+#proc renderMessages*(messages: seq[Message]): string =
+#  result = ""
+<div id="messages">
+  #for message in messages:
+    <div>
+      <a href="/${message.username}">${message.username}</a>
+      <span>${message.time.utc().format("HH:mm MMMM d',' yyyy")}</span>
+      <h3>${message.msg}</h3>
+    </div>
+  #end for
+</div>
+#end proc
+#
+#when true:
+#  echo renderUser(User(username: "d0m96<>", following: @[]))
+#  echo renderMessages(@[
+#    Message(username: "d0m96", time: getTime(), msg: "Hello World!"),
+#    Message(username: "d0m96", time: getTime(), msg: "Testing")
+#  ])
+#end when
diff --git a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
new file mode 100644
index 000000000..c8beb4a30
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nim
@@ -0,0 +1,33 @@
+discard """
+disabled: true
+outputsub: "All tests finished successfully!"
+"""
+
+import database, os, times
+
+when true:
+  removeFile("tweeter_test.db")
+  var db = newDatabase("tweeter_test.db")
+  db.setup()
+
+  db.create(User(username: "d0m96"))
+  db.create(User(username: "nim_lang"))
+
+  db.post(Message(username: "nim_lang", time: getTime() - 4.seconds,
+      msg: "Hello Nim in Action readers"))
+  db.post(Message(username: "nim_lang", time: getTime(),
+      msg: "99.9% off Nim in Action for everyone, for the next minute only!"))
+
+  var dom: User
+  doAssert db.findUser("d0m96", dom)
+  var nim: User
+  doAssert db.findUser("nim_lang", nim)
+  db.follow(dom, nim)
+
+  doAssert db.findUser("d0m96", dom)
+
+  let messages = db.findMessages(dom.following)
+  echo(messages)
+  doAssert(messages[0].msg == "99.9% off Nim in Action for everyone, for the next minute only!")
+  doAssert(messages[1].msg == "Hello Nim in Action readers")
+  echo("All tests finished successfully!")
diff --git a/tests/niminaction/Chapter7/Tweeter/tests/database_test.nims b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nims
new file mode 100644
index 000000000..226905fbf
--- /dev/null
+++ b/tests/niminaction/Chapter7/Tweeter/tests/database_test.nims
@@ -0,0 +1,2 @@
+--path:"../src"
+#switch("path", "./src")
diff --git a/tests/niminaction/Chapter8/canvas/canvas.nim b/tests/niminaction/Chapter8/canvas/canvas.nim
new file mode 100644
index 000000000..ae2765630
--- /dev/null
+++ b/tests/niminaction/Chapter8/canvas/canvas.nim
@@ -0,0 +1,23 @@
+discard """
+action: compile
+"""
+
+import dom
+
+type
+  CanvasRenderingContext* = ref object
+    fillStyle* {.importc.}: cstring
+    strokeStyle* {.importc.}: cstring
+
+{.push importcpp.}
+
+proc getContext*(canvasElement: Element,
+    contextType: cstring): CanvasRenderingContext
+
+proc fillRect*(context: CanvasRenderingContext, x, y, width, height: int)
+
+proc moveTo*(context: CanvasRenderingContext, x, y: int)
+
+proc lineTo*(context: CanvasRenderingContext, x, y: int)
+
+proc stroke*(context: CanvasRenderingContext)
diff --git a/tests/niminaction/Chapter8/canvas/canvas_test.nim b/tests/niminaction/Chapter8/canvas/canvas_test.nim
new file mode 100644
index 000000000..42d222b7b
--- /dev/null
+++ b/tests/niminaction/Chapter8/canvas/canvas_test.nim
@@ -0,0 +1,19 @@
+import canvas, dom
+
+proc onLoad() {.exportc.} =
+  var canvas = document.getElementById("canvas").EmbedElement
+  canvas.width = window.innerWidth
+  canvas.height = window.innerHeight
+  var ctx = canvas.getContext("2d")
+
+  ctx.fillStyle = "#1d4099"
+  ctx.fillRect(0, 0, window.innerWidth, window.innerHeight)
+
+  ctx.strokeStyle = "#ffffff"
+  let letterWidth = 100
+  let letterLeftPos = (window.innerWidth div 2) - (letterWidth div 2)
+  ctx.moveTo(letterLeftPos, 320)
+  ctx.lineTo(letterLeftPos, 110)
+  ctx.lineTo(letterLeftPos + letterWidth, 320)
+  ctx.lineTo(letterLeftPos + letterWidth, 110)
+  ctx.stroke()
diff --git a/tests/niminaction/Chapter8/sdl/sdl.nim b/tests/niminaction/Chapter8/sdl/sdl.nim
new file mode 100644
index 000000000..212f7b022
--- /dev/null
+++ b/tests/niminaction/Chapter8/sdl/sdl.nim
@@ -0,0 +1,38 @@
+when defined(windows):
+  const libName* = "SDL2.dll"
+elif defined(linux) or defined(freebsd) or defined(netbsd):
+  const libName* = "libSDL2.so"
+elif defined(macosx):
+  const libName* = "libSDL2.dylib"
+elif defined(openbsd):
+  const libName* = "libSDL2.so.0.6"
+else:
+  {.error: "SDL library name not set for this platform".}
+
+type
+  SdlWindow = object
+  SdlWindowPtr* = ptr SdlWindow
+  SdlRenderer = object
+  SdlRendererPtr* = ptr SdlRenderer
+
+const INIT_VIDEO* = 0x00000020
+
+{.push dynlib: libName.}
+proc init*(flags: uint32): cint {.importc: "SDL_Init".}
+
+proc createWindowAndRenderer*(width, height: cint, window_flags: cuint,
+    window: var SdlWindowPtr, renderer: var SdlRendererPtr): cint
+    {.importc: "SDL_CreateWindowAndRenderer".}
+
+proc pollEvent*(event: pointer): cint {.importc: "SDL_PollEvent".}
+
+proc setDrawColor*(renderer: SdlRendererPtr, r, g, b, a: uint8): cint
+    {.importc: "SDL_SetRenderDrawColor", discardable.}
+
+proc present*(renderer: SdlRendererPtr) {.importc: "SDL_RenderPresent".}
+
+proc clear*(renderer: SdlRendererPtr) {.importc: "SDL_RenderClear".}
+
+proc drawLines*(renderer: SdlRendererPtr, points: ptr tuple[x, y: cint],
+    count: cint): cint {.importc: "SDL_RenderDrawLines", discardable.}
+{.pop.}
diff --git a/tests/niminaction/Chapter8/sdl/sdl_test.nim b/tests/niminaction/Chapter8/sdl/sdl_test.nim
new file mode 100644
index 000000000..db1700e0d
--- /dev/null
+++ b/tests/niminaction/Chapter8/sdl/sdl_test.nim
@@ -0,0 +1,41 @@
+discard """
+action: compile
+"""
+
+import os
+import sdl
+
+if sdl.init(INIT_VIDEO) == -1:
+  quit("Couldn't initialise SDL")
+
+var window: SdlWindowPtr
+var renderer: SdlRendererPtr
+if createWindowAndRenderer(640, 480, 0, window, renderer) == -1:
+  quit("Couldn't create a window or renderer")
+
+discard pollEvent(nil)
+renderer.setDrawColor 29, 64, 153, 255
+renderer.clear
+renderer.setDrawColor 255, 255, 255, 255
+
+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 = [
+    (260'i32, 320'i32),
+    (260'i32, 110'i32),
+    (360'i32, 320'i32),
+    (360'i32, 110'i32)
+  ]
+else:
+  var points = [
+    (260.cint, 320.cint),
+    (260.cint, 110.cint),
+    (360.cint, 320.cint),
+    (360.cint, 110.cint)
+  ]
+
+renderer.drawLines(addr points[0], points.len.cint)
+
+renderer.present
+sleep(5000)
diff --git a/tests/niminaction/Chapter8/sfml/sfml.nim b/tests/niminaction/Chapter8/sfml/sfml.nim
new file mode 100644
index 000000000..fea85fcd4
--- /dev/null
+++ b/tests/niminaction/Chapter8/sfml/sfml.nim
@@ -0,0 +1,26 @@
+{.passL: "-lsfml-graphics -lsfml-system -lsfml-window".}
+
+type
+  VideoMode* {.importcpp: "sf::VideoMode".} = object
+  RenderWindowObj {.importcpp: "sf::RenderWindow".} = object
+  RenderWindow* = ptr RenderWindowObj
+  Color* {.importcpp: "sf::Color".} = object
+  Event* {.importcpp: "sf::Event".} = object
+
+{.push cdecl, header: "<SFML/Graphics.hpp>".}
+
+proc videoMode*(modeWidth, modeHeight: cuint, modeBitsPerPixel: cuint = 32): VideoMode
+    {.importcpp: "sf::VideoMode(@)", constructor.}
+
+proc newRenderWindow*(mode: VideoMode, title: cstring): RenderWindow
+    {.importcpp: "new sf::RenderWindow(@)", constructor.}
+
+proc pollEvent*(window: RenderWindow, event: var Event): bool
+    {.importcpp: "#.pollEvent(@)".}
+
+proc newColor*(red, green, blue, alpha: uint8): Color
+    {.importcpp: "sf::Color(@)", constructor.}
+
+proc clear*(window: RenderWindow, color: Color) {.importcpp: "#.clear(@)".}
+
+proc display*(window: RenderWindow) {.importcpp: "#.display()".}
diff --git a/tests/niminaction/Chapter8/sfml/sfml_test.nim b/tests/niminaction/Chapter8/sfml/sfml_test.nim
new file mode 100644
index 000000000..e71060cb4
--- /dev/null
+++ b/tests/niminaction/Chapter8/sfml/sfml_test.nim
@@ -0,0 +1,14 @@
+discard """
+action: compile
+disabled: "windows"
+"""
+
+import sfml, os
+var window = newRenderWindow(videoMode(800, 600), "SFML works!")
+
+var event: Event
+discard window.pollEvent(event)
+window.clear(newColor(29, 64, 153, 255))
+window.display()
+
+sleep(1000)
diff --git a/tests/niminaction/Chapter9/configurator/configurator.nim b/tests/niminaction/Chapter9/configurator/configurator.nim
new file mode 100644
index 000000000..0d5627889
--- /dev/null
+++ b/tests/niminaction/Chapter9/configurator/configurator.nim
@@ -0,0 +1,84 @@
+import macros
+
+proc createRefType(ident: NimIdent, identDefs: seq[NimNode]): NimNode =
+  result = newTree(nnkTypeSection,
+    newTree(nnkTypeDef,
+      newIdentNode(ident),
+      newEmptyNode(),
+      newTree(nnkRefTy,
+        newTree(nnkObjectTy,
+          newEmptyNode(),
+          newEmptyNode(),
+          newTree(nnkRecList,
+            identDefs
+          )
+        )
+      )
+    )
+  )
+
+proc toIdentDefs(stmtList: NimNode): seq[NimNode] =
+  expectKind(stmtList, nnkStmtList)
+  result = @[]
+
+  for child in stmtList:
+    expectKind(child, nnkCall)
+    result.add(newIdentDefs(child[0], child[1][0]))
+
+template constructor(ident: untyped): untyped =
+  proc `new ident`(): `ident` =
+    new result
+
+proc createLoadProc(typeName: NimIdent, identDefs: seq[NimNode]): NimNode =
+  var cfgIdent = newIdentNode("cfg")
+  var filenameIdent = newIdentNode("filename")
+  var objIdent = newIdentNode("obj")
+
+  var body = newStmtList()
+  body.add quote do:
+    var `objIdent` = parseFile(`filenameIdent`)
+
+  for identDef in identDefs:
+    let fieldNameIdent = identDef[0]
+    let fieldName = $fieldNameIdent.ident
+    case $identDef[1].ident
+    of "string":
+      body.add quote do:
+        `cfgIdent`.`fieldNameIdent` = `objIdent`[`fieldName`].getStr
+    of "int":
+      body.add quote do:
+        `cfgIdent`.`fieldNameIdent` = `objIdent`[`fieldName`].getNum().int
+    else:
+      doAssert(false, "Not Implemented")
+
+  return newProc(newIdentNode("load"),
+    [newEmptyNode(),
+     newIdentDefs(cfgIdent, newIdentNode(typeName)),
+     newIdentDefs(filenameIdent, newIdentNode("string"))],
+    body)
+
+macro config*(typeName: untyped, fields: untyped): untyped =
+  result = newStmtList()
+
+  let identDefs = toIdentDefs(fields)
+  result.add createRefType(typeName.ident, identDefs)
+  result.add getAst(constructor(typeName.ident))
+  result.add createLoadProc(typeName.ident, identDefs)
+
+  echo treeRepr(typeName)
+  echo treeRepr(fields)
+
+  echo treeRepr(result)
+  echo toStrLit(result)
+  # TODO: Verify that we can export fields in config type so that it can be
+  # used in another module.
+
+import json
+config MyAppConfig:
+  address: string
+  port: int
+
+var myConf = newMyAppConfig()
+myConf.load("myappconfig.cfg")
+echo("Address: ", myConf.address)
+echo("Port: ", myConf.port)
diff --git a/tests/notnil/tmust_compile.nim b/tests/notnil/tmust_compile.nim
new file mode 100644
index 000000000..3a013e9ed
--- /dev/null
+++ b/tests/notnil/tmust_compile.nim
@@ -0,0 +1,75 @@
+discard """
+  output: '''success'''
+"""
+
+# bug #6682
+{.experimental: "notnil".}
+
+type
+    Fields = enum
+        A=1, B, C
+
+    Obj = object
+        fld: array[Fields, int]
+
+    AsGeneric[T] = array[Fields, T]
+    Obj2[T] = object
+      fld: AsGeneric[T]
+
+var a: Obj # this works
+
+var arr: array[Fields, int]
+
+var b = Obj() # this doesn't (also doesn't works with additional fields)
+
+var z = Obj2[int]()
+
+echo "success"
+
+# bug #6555
+
+import tables
+
+type
+  TaskOrNil = ref object
+  Task = TaskOrNil not nil
+
+let table = newTable[string, Task]()
+table.del("task")
+
+# bug #6121
+
+import json
+
+type
+
+  foo = object
+    thing: ptr int not nil
+
+  CTS = ref object
+    subs_by_sid: Table[int, foo]
+
+
+proc parse(cts: CTS, jn: JsonNode) =
+  var y = jn.getInt(4523)
+  let ces = foo(
+    thing: addr y
+  )
+
+  cts.subs_by_sid[0] = ces
+
+
+# bug #6489
+
+proc p(x: proc(){.closure.} not nil) = discard
+p(proc(){.closure.} = discard)
+
+# bug #6490
+
+proc p2(a: proc()) =
+    if a.isNil:
+        raise newException(ValueError, "a is nil")
+    else:
+        let b: proc() not nil = a
+
+p2(writeStackTrace)
diff --git a/tests/notnil/tnotnil.nim b/tests/notnil/tnotnil.nim
new file mode 100644
index 000000000..c33b6fcac
--- /dev/null
+++ b/tests/notnil/tnotnil.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "type mismatch"
+  line: 13
+"""
+{.experimental: "notnil".}
+type
+  PObj = ref TObj not nil
+  TObj = object
+    x: int
+
+proc q2(x: string) = discard
+
+q2(nil)
diff --git a/tests/notnil/tnotnil1.nim b/tests/notnil/tnotnil1.nim
new file mode 100644
index 000000000..60666d64d
--- /dev/null
+++ b/tests/notnil/tnotnil1.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "'y' is provably nil"
+  line:25
+"""
+
+import strutils
+{.experimental: "notnil".}
+
+type
+  TObj = object
+    x, y: int
+
+proc q(x: pointer not nil) =
+  discard
+
+proc p() =
+  var x: pointer
+  if not x.isNil:
+    q(x)
+
+  let y = x
+  if not y.isNil:
+    q(y)
+  else:
+    q(y)
+
+p()
diff --git a/tests/notnil/tnotnil2.nim b/tests/notnil/tnotnil2.nim
new file mode 100644
index 000000000..6cd08de73
--- /dev/null
+++ b/tests/notnil/tnotnil2.nim
@@ -0,0 +1,24 @@
+discard """
+  errormsg: "cannot prove 'y' is not nil"
+  line:20
+"""
+
+import strutils
+{.experimental: "notnil".}
+
+type
+  TObj = object
+    x, y: int
+
+proc q(x: pointer not nil) =
+  discard
+
+proc p() =
+  var x: pointer
+  let y = x
+  if not y.isNil or y != x:
+    q(y)
+  else:
+    q(y)
+
+p()
diff --git a/tests/notnil/tnotnil3.nim b/tests/notnil/tnotnil3.nim
new file mode 100644
index 000000000..31a4efef7
--- /dev/null
+++ b/tests/notnil/tnotnil3.nim
@@ -0,0 +1,35 @@
+discard """
+  errormsg: "cannot prove 'variable' is not nil"
+  line: 31
+"""
+
+# bug #584
+# Testprogram for 'not nil' check
+{.experimental: "notnil".}
+const testWithResult = true
+
+type
+  A = object
+  B = object
+  C = object
+    a: ref A
+    b: ref B
+
+
+proc testNotNil(c: ref C not nil) =
+  discard
+
+
+when testWithResult:
+  proc testNotNilOnResult(): ref C =
+    new(result)
+    #result.testNotNil() # Here 'not nil' can't be proved
+
+
+var variable: ref C
+new(variable)
+variable.testNotNil() # Here 'not nil' is proved
+
+when testWithResult:
+  discard testNotNilOnResult()
+
diff --git a/tests/notnil/tnotnil4.nim b/tests/notnil/tnotnil4.nim
new file mode 100644
index 000000000..c5178f71b
--- /dev/null
+++ b/tests/notnil/tnotnil4.nim
@@ -0,0 +1,23 @@
+discard ""
+type
+   TObj = ref object
+
+{.experimental: "notnil".}
+
+proc check(a: TObj not nil) =
+  echo repr(a)
+
+proc doit() =
+   var x : array[0..1, TObj]
+
+   let y = x[0]
+   if y != nil:
+      check(y)
+
+doit()
+
+# bug #2352
+
+proc p(x: proc() {.noconv.} not nil) = discard
+p(proc() {.noconv.} = discard)
+# Error: cannot prove 'proc () {.noconv.} = discard ' is not nil
diff --git a/tests/notnil/tnotnil5.nim b/tests/notnil/tnotnil5.nim
new file mode 100644
index 000000000..2dcb7f7c3
--- /dev/null
+++ b/tests/notnil/tnotnil5.nim
@@ -0,0 +1,28 @@
+discard """
+  matrix: "--threads:on"
+"""
+
+{.experimental: "parallel".}
+{.experimental: "notnil".}
+import threadpool
+
+type
+  AO = object
+    x: int
+
+  A = ref AO not nil
+
+proc process(a: A): A =
+  return A(x: a.x+1)
+
+proc processMany(ayys: openArray[A]): seq[A] =
+  var newAs: seq[FlowVar[A]]
+
+  parallel:
+    for a in ayys:
+      newAs.add(spawn process(a))
+  for newAflow in newAs:
+    let newA = ^newAflow
+    if isNil(newA):
+      return @[]
+    result.add(newA)
diff --git a/tests/notnil/tnotnil_in_generic.nim b/tests/notnil/tnotnil_in_generic.nim
new file mode 100644
index 000000000..89d20f182
--- /dev/null
+++ b/tests/notnil/tnotnil_in_generic.nim
@@ -0,0 +1,28 @@
+discard """
+  errormsg: "cannot prove 'x' is not nil"
+"""
+
+# bug #2216
+{.experimental: "notnil".}
+
+type
+    A[T] = ref object
+        x: int
+        ud: T
+
+proc good[T](p: A[T]) =
+    discard
+
+proc bad[T](p: A[T] not nil) =
+    discard
+
+
+proc go() =
+    let s = A[int](x: 1)
+
+    good(s)
+    bad(s)
+    var x: A[int]
+    bad(x)
+
+go()
diff --git a/tests/notnil/tnotnil_in_objconstr.nim b/tests/notnil/tnotnil_in_objconstr.nim
new file mode 100644
index 000000000..471150f44
--- /dev/null
+++ b/tests/notnil/tnotnil_in_objconstr.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "The Foo type requires the following fields to be initialized: bar, baz"
+  line: "17"
+"""
+{.experimental: "notnil".}
+# bug #2355
+type
+  Base = object of RootObj
+    baz: ref int not nil
+
+  Foo = object of Base
+    foo: ref int
+    bar: ref int not nil
+
+var x: ref int = new(int)
+# Create instance without initializing the `bar` field
+var f = Foo(foo: x)
+echo f.bar.isNil # true
diff --git a/tests/notnil/tparse.nim b/tests/notnil/tparse.nim
new file mode 100644
index 000000000..5c938ff04
--- /dev/null
+++ b/tests/notnil/tparse.nim
@@ -0,0 +1,18 @@
+# issue #16324
+
+{.push experimental: "notnil".}
+
+block:
+  type Foo = ref object
+    value: int
+    
+  proc newFoo1(): Foo not nil =               # This compiles
+    return Foo(value: 1)
+    
+  proc newFoo2(): Foo not nil {.inline.} =    # This does not
+    return Foo(value: 1)
+
+  doAssert newFoo1().value == 1
+  doAssert newFoo2().value == 1
+
+{.pop.}
diff --git a/tests/objects/m19342.c b/tests/objects/m19342.c
new file mode 100644
index 000000000..113f65309
--- /dev/null
+++ b/tests/objects/m19342.c
@@ -0,0 +1,12 @@
+struct Node
+{
+  int data[25];
+};
+
+
+struct Node hello(int name) {
+  struct Node x = {999, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+            0, 1, 2, 3, 4, 5, 6, 7 ,8, 9,
+            1, 2, 3, 4, 5};
+  return x;
+}
\ No newline at end of file
diff --git a/tests/objects/mobject_default_value.nim b/tests/objects/mobject_default_value.nim
new file mode 100644
index 000000000..224549501
--- /dev/null
+++ b/tests/objects/mobject_default_value.nim
@@ -0,0 +1,15 @@
+type
+  Clean = object
+    mem: int
+  Default* = object
+    poi: int = 12
+    clc: Clean
+    se*: range[0'i32 .. high(int32)]
+
+  NonDefault* = object
+    poi: int
+
+  PrellDeque*[T] = object
+    pendingTasks*: range[0'i32 .. high(int32)]
+    head: T
+    tail: T
diff --git a/tests/objects/t12753.nim b/tests/objects/t12753.nim
new file mode 100644
index 000000000..1009433be
--- /dev/null
+++ b/tests/objects/t12753.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''
+(v: [(v: [0.0, 1.1]), (v: [2.2, 3.3])])
+(v: [(v: [0.0, 1.1]), (v: [2.2, 3.3])])
+'''
+"""
+
+type
+  V = object
+    v:array[2,float]
+  M = object
+    v:array[2,V]
+
+var
+  a = M(v:[ V(v:[0.0,1.0]), V(v:[2.0,3.0]) ])
+  b = M(v:[ V(v:[0.0,0.1]), V(v:[0.2,0.3]) ])
+
+echo M(v: [V(v: [b.v[0].v[0] + a.v[0].v[0], b.v[0].v[1] + a.v[0].v[1]]),
+       V(v: [b.v[1].v[0] + a.v[1].v[0], b.v[1].v[1] + a.v[1].v[1]])])
+b = M(v: [V(v: [b.v[0].v[0] + a.v[0].v[0], b.v[0].v[1] + a.v[0].v[1]]),
+      V(v: [b.v[1].v[0] + a.v[1].v[0], b.v[1].v[1] + a.v[1].v[1]])])
+echo b
diff --git a/tests/objects/t17437.nim b/tests/objects/t17437.nim
new file mode 100644
index 000000000..b5c0e0525
--- /dev/null
+++ b/tests/objects/t17437.nim
@@ -0,0 +1,22 @@
+discard """
+  cmd: "nim check $file"
+  errormsg: ""
+  nimout: '''
+t17437.nim(20, 16) Error: undeclared identifier: 'x'
+t17437.nim(20, 16) Error: expression 'x' has no type (or is ambiguous)
+t17437.nim(20, 19) Error: incorrect object construction syntax
+t17437.nim(20, 19) Error: incorrect object construction syntax
+t17437.nim(20, 12) Error: expression '' has no type (or is ambiguous)
+'''
+"""
+
+# bug #17437 invalid object construction should result in error
+
+type
+  V = ref object
+    x, y: int
+
+proc m =
+  var v = V(x: x, y)
+
+m()
diff --git a/tests/objects/t19342.nim b/tests/objects/t19342.nim
new file mode 100644
index 000000000..d40d15a4b
--- /dev/null
+++ b/tests/objects/t19342.nim
@@ -0,0 +1,18 @@
+discard """
+  targets: "c cpp"
+"""
+
+{.compile: "m19342.c".}
+
+# bug #19342
+type
+  Node* {.bycopy.} = object
+    data: array[25, cint]
+
+proc myproc(name: cint): Node {.importc: "hello", cdecl.}
+
+proc parse =
+  let node = myproc(10)
+  doAssert node.data[0] == 999
+
+parse()
diff --git a/tests/objects/t19342_2.nim b/tests/objects/t19342_2.nim
new file mode 100644
index 000000000..6f6d0f2b3
--- /dev/null
+++ b/tests/objects/t19342_2.nim
@@ -0,0 +1,18 @@
+discard """
+  targets: "c cpp"
+"""
+
+{.compile: "m19342.c".}
+
+# bug #19342
+type
+  Node* {.byRef.} = object
+    data: array[25, cint]
+
+proc myproc(name: cint): Node {.importc: "hello", cdecl.}
+
+proc parse =
+  let node = myproc(10)
+  doAssert node.data[0] == 999
+
+parse()
\ No newline at end of file
diff --git a/tests/objects/t20972.nim b/tests/objects/t20972.nim
new file mode 100644
index 000000000..6383dc9b1
--- /dev/null
+++ b/tests/objects/t20972.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--mm:refc -d:release; --mm:orc -d:release"
+"""
+
+{.passC: "-fsanitize=undefined -fsanitize-undefined-trap-on-error -Wall -Wextra -pedantic -flto".}
+{.passL: "-fsanitize=undefined -fsanitize-undefined-trap-on-error -flto".}
+
+# bug #20972
+type ForkedEpochInfo = object
+  case kind: bool
+  of true, false: discard
+var info = ForkedEpochInfo(kind: true)
+doAssert info.kind
+info.kind = false
+doAssert not info.kind
diff --git a/tests/objects/t22301.nim b/tests/objects/t22301.nim
new file mode 100644
index 000000000..8746bf584
--- /dev/null
+++ b/tests/objects/t22301.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "branch initialization with a runtime discriminator is not supported for a branch whose fields have default values."
+"""
+
+# bug #22301
+type
+  Enum = enum A, B
+  Object = object
+    case a: Enum
+    of A:
+      integer: int = 200
+    of B:
+      time: string
+
+let x = A
+let s = Object(a: x)
+echo s
\ No newline at end of file
diff --git a/tests/objects/t3734.nim b/tests/objects/t3734.nim
new file mode 100644
index 000000000..cebef6081
--- /dev/null
+++ b/tests/objects/t3734.nim
@@ -0,0 +1,17 @@
+discard """
+output: "i0"
+"""
+
+type
+  Application = object
+      config: void
+      i: int
+      f: void
+
+proc printFields(rec: Application) =
+  for k, v in fieldPairs(rec):
+    echo k, v
+
+var app: Application
+
+printFields(app)
diff --git a/tests/objects/t4318.nim b/tests/objects/t4318.nim
new file mode 100644
index 000000000..beadd6909
--- /dev/null
+++ b/tests/objects/t4318.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: "--mm:refc"
+"""
+
+
+type
+  A = object of RootObj
+  B = object of A
+
+method identify(a:A) {.base.} = echo "A"
+method identify(b:B) = echo "B"
+
+var b: B
+
+doAssertRaises(ObjectAssignmentDefect):
+  var a: A = b
+  discard a
diff --git a/tests/objects/tdefaultfieldscheck.nim b/tests/objects/tdefaultfieldscheck.nim
new file mode 100644
index 000000000..8a05439d9
--- /dev/null
+++ b/tests/objects/tdefaultfieldscheck.nim
@@ -0,0 +1,16 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout:
+'''
+tdefaultfieldscheck.nim(14, 17) Error: type mismatch: got <string> but expected 'int'
+'''
+"""
+
+
+type
+  Date* = object
+    goal: float = 7
+    name: int = "string"
+
+echo default(Date)
diff --git a/tests/objects/tdefaultrangetypescheck.nim b/tests/objects/tdefaultrangetypescheck.nim
new file mode 100644
index 000000000..71e7ac59b
--- /dev/null
+++ b/tests/objects/tdefaultrangetypescheck.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "cannot convert 0 to range 1..5(int)"
+  line: 9
+"""
+
+type
+  Point = object
+    y: int
+    x: range[1..5] = 0
+
+echo default(Point)
diff --git a/tests/objects/tillegal_recursion.nim b/tests/objects/tillegal_recursion.nim
new file mode 100644
index 000000000..428c2e445
--- /dev/null
+++ b/tests/objects/tillegal_recursion.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "Cannot inherit from: 'Foo:ObjectType'"
+  line: 7
+"""
+# bug #1691
+type
+  Foo = ref object of Foo
diff --git a/tests/objects/tillegal_recursion2.nim b/tests/objects/tillegal_recursion2.nim
new file mode 100644
index 000000000..ce2279f04
--- /dev/null
+++ b/tests/objects/tillegal_recursion2.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "Cannot inherit from: 'Foo'"
+  line: 6
+"""
+type
+  Foo = object of Foo
diff --git a/tests/objects/tillegal_recursion3.nim b/tests/objects/tillegal_recursion3.nim
new file mode 100644
index 000000000..c80f29e28
--- /dev/null
+++ b/tests/objects/tillegal_recursion3.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "Cannot inherit from: 'Foo'"
+  line: 6
+"""
+type
+  Foo = object of ref Foo
diff --git a/tests/objects/tobj_asgn_dont_slice.nim b/tests/objects/tobj_asgn_dont_slice.nim
new file mode 100644
index 000000000..ce67c4490
--- /dev/null
+++ b/tests/objects/tobj_asgn_dont_slice.nim
@@ -0,0 +1,25 @@
+discard """
+  matrix: "--mm:refc"
+  outputsub: '''ObjectAssignmentDefect'''
+  exitcode: "1"
+"""
+
+# bug #7637
+type
+  Fruit = object of RootObj
+    name*: string
+  Apple = object of Fruit
+  Pear = object of Fruit
+
+method eat(f: Fruit) {.base.} =
+  raise newException(Exception, "PURE VIRTUAL CALL")
+
+method eat(f: Apple) =
+  echo "fruity"
+
+method eat(f: Pear) =
+  echo "juicy"
+
+let basket = [Apple(name:"a"), Pear(name:"b")]
+
+eat(basket[0])
diff --git a/tests/objects/tobjconstr.nim b/tests/objects/tobjconstr.nim
new file mode 100644
index 000000000..ee5a5b221
--- /dev/null
+++ b/tests/objects/tobjconstr.nim
@@ -0,0 +1,79 @@
+discard """
+  output: '''
+(k: kindA, a: (x: "abc", z: @[1, 1, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 2, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 3, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 4, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 5, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 6, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 7, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 8, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 9, 3]), method: ())
+(k: kindA, a: (x: "abc", z: @[1, 10, 3]), method: ())
+(y: 0, x: 123)
+(y: 678, x: 123)
+(z: 89, y: 0, x: 128)
+(y: 678, x: 123)
+(y: 678, x: 123)
+(y: 0, x: 123)
+(y: 678, x: 123)
+(y: 123, x: 678)
+'''
+"""
+
+type
+  TArg = object
+    x: string
+    z: seq[int]
+  TKind = enum kindXY, kindA
+  TEmpty = object
+  TDummy = ref object
+    case k: TKind
+    of kindXY: x, y: int
+    of kindA:
+      a: TArg
+      `method`: TEmpty # bug #1791
+
+proc main() =
+  for i in 1..10:
+    let d = TDummy(k: kindA, a: TArg(x: "abc", z: @[1,i,3]), `method`: TEmpty())
+    echo d[]
+
+main()
+
+# bug #6294
+type
+  A = object of RootObj
+    x*: int
+  B = object of A
+    y*: int
+  BS = object of B
+  C = object of BS
+    z*: int
+
+proc main2 =
+  # inherited fields are ignored, so no fields are set
+  when true:
+    var
+      o: B
+    o = B(x: 123)
+    echo o
+    o = B(y: 678, x: 123)
+    echo o
+
+  # inherited fields are ignored
+  echo C(x: 128, z: 89)          # (y: 0, x: 0)
+  echo B(y: 678, x: 123)  # (y: 678, x: 0)
+  echo B(x: 123, y: 678)  # (y: 678, x: 0)
+
+  when true:
+    # correct, both with `var` and `let`;
+    var b=B(x: 123)
+    echo b                  # (y: 0, x: 123)
+    b=B(y: 678, x: 123)
+    echo b                  # (y: 678, x: 123)
+    b=B(y: b.x, x: b.y)
+    echo b                  # (y: 123, x: 678)
+
+main2()
+GC_fullCollect()
diff --git a/tests/objects/tobjconstr2.nim b/tests/objects/tobjconstr2.nim
new file mode 100644
index 000000000..cf4a694b4
--- /dev/null
+++ b/tests/objects/tobjconstr2.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''42
+Foo'''
+"""
+
+type TFoo{.exportc.} = object
+ x:int
+
+var s{.exportc.}: seq[TFoo] = @[]
+
+s.add TFoo(x: 42)
+
+echo s[0].x
+
+
+# bug #563
+type
+  Foo {.inheritable.} =
+    object
+      x: int
+
+  Bar =
+    object of Foo
+      y: int
+
+var a = Bar(y: 100, x: 200) # works
+var b = Bar(x: 100, y: 200) # used to fail
+
+# bug 1275
+
+type
+  Graphic = object of RootObj
+    case kind: range[0..1]
+    of 0:
+      radius: float
+    of 1:
+      size: tuple[w, h: float]
+
+var d = Graphic(kind: 1, size: (12.9, 6.9))
+
+# bug #1274
+type
+  K = enum Koo, Kar
+  Graphic2 = object of RootObj
+    case kind: K
+    of Koo:
+      radius: float
+    of Kar:
+      size: tuple[w, h: float]
+
+type NamedGraphic = object of Graphic2
+  name: string
+
+var ngr = NamedGraphic(kind: Koo, radius: 6.9, name: "Foo")
+echo ngr.name
+
+GC_fullCollect()
diff --git a/tests/objects/tobjcov.nim b/tests/objects/tobjcov.nim
new file mode 100644
index 000000000..a12f74702
--- /dev/null
+++ b/tests/objects/tobjcov.nim
@@ -0,0 +1,24 @@
+discard """
+action: compile
+targets: "c"
+"""
+
+# Covariance is not type safe:
+# Note: `nim cpp` makes it a compile error (after codegen), even with:
+# `var f = cast[proc (x: var TA) {.nimcall.}](cast[pointer](bp))`, which
+# currently removes all the `cast` in cgen'd code, hence the compile error.
+
+type
+  TA = object of RootObj
+    a: int
+  TB = object of TA
+    b: array[0..5000_000, int]
+
+proc ap(x: var TA) = x.a = -1
+proc bp(x: var TB) = x.b[high(x.b)] = -1
+
+# in Nim proc (x: TB) is compatible to proc (x: TA),
+# but this is not type safe:
+var f = cast[proc (x: var TA) {.nimcall.}](bp)
+var a: TA
+f(a) # bp expects a TB, but gets a TA
diff --git a/tests/objects/tobject.nim b/tests/objects/tobject.nim
new file mode 100644
index 000000000..a185bebcb
--- /dev/null
+++ b/tests/objects/tobject.nim
@@ -0,0 +1,74 @@
+
+type Obj = object
+  foo: int
+
+proc makeObj(x: int): Obj =
+  result.foo = x
+
+block: # object basic methods
+  block: # it should convert an object to a string
+    var obj = makeObj(1)
+    # Should be "obj: (foo: 1)" or similar.
+    doAssert($obj == "(foo: 1)")
+  block: # it should test equality based on fields
+    doAssert(makeObj(1) == makeObj(1))
+
+# bug #10203
+
+type
+  TMyObj = TYourObj
+  TYourObj = object of RootObj
+    x, y: int
+
+proc init: TYourObj =
+  result.x = 0
+  result.y = -1
+
+proc f(x: var TYourObj) =
+  discard
+
+var m: TMyObj = init()
+f(m)
+
+var a: TYourObj = m
+var b: TMyObj = a
+
+# bug #10195
+type
+  InheritableFoo {.inheritable.} = ref object
+  InheritableBar = ref object of InheritableFoo # ERROR.
+
+block: # bug #14698
+  const N = 3
+  type Foo[T] = ref object
+    x1: int
+    when N == 2:
+      x2: float
+    when N == 3:
+      x3: seq[int]
+    else:
+      x4: char
+      x4b: array[9, char]
+
+  let t = Foo[float](x1: 1)
+  doAssert $(t[]) == "(x1: 1, x3: @[])"
+  doAssert t.sizeof == int.sizeof
+  type Foo1 = object
+    x1: int
+    x3: seq[int]
+  doAssert t[].sizeof == Foo1.sizeof
+
+# bug #147
+type
+  TValue* {.pure, final.} = object of RootObj
+    a: int
+  PValue = ref TValue
+  PPValue = ptr PValue
+
+
+var x: PValue
+new x
+var sp: PPValue = addr x
+
+sp.a = 2
+doAssert sp.a == 2
diff --git a/tests/objects/tobject3.nim b/tests/objects/tobject3.nim
new file mode 100644
index 000000000..9ff1743ce
--- /dev/null
+++ b/tests/objects/tobject3.nim
@@ -0,0 +1,95 @@
+discard """
+  output: '''TBar2
+TFoo
+'''
+"""
+
+## XXX this output needs to be adapted for VCC which produces different results.
+
+# It turned out that it's hard to generate correct for these two test cases at
+# the same time.
+
+type
+  TFoo = ref object of RootObj
+    Data: int
+  TBar = ref object of TFoo
+    nil
+  TBar2 = ref object of TBar
+    d2: int
+
+template super(self: TBar): TFoo = self
+
+template super(self: TBar2): TBar = self
+
+proc Foo(self: TFoo) =
+  echo "TFoo"
+
+#proc Foo(self: TBar) =
+#  echo "TBar"
+#  Foo(super(self))
+# works when this code is uncommented
+
+proc Foo(self: TBar2) =
+  echo "TBar2"
+  Foo(super(self))
+
+var b: TBar2
+new(b)
+
+Foo(b)
+
+# bug #837
+type
+  PView* = ref TView
+  TView* {.inheritable.} = object
+    data: int
+
+  PWindow* = ref TWindow
+  TWindow* = object of TView
+    data3: int
+
+  PDesktop* = ref TDesktop
+  TDesktop* = object of TView
+    data2: int
+
+proc makeDesktop(): PDesktop = new(TDesktop)
+
+proc makeWindow(): PWindow = new(TWindow)
+
+proc thisCausesError(a: PView, b: PView) =
+  discard
+
+var dd = makeDesktop()
+var aa = makeWindow()
+
+thisCausesError(dd, aa)
+
+# bug  #5892
+type
+    Foo6 = distinct array[4, float32]
+    AnotherFoo = distinct array[4, float32]
+
+    AbstractAnimationSampler* = ref object of RootObj
+
+    AnimationSampler*[T] = ref object of AbstractAnimationSampler
+        sampleImpl: proc(s: AnimationSampler[T], p: float): T
+
+    ArrayAnimationSampler*[T] = ref object of AnimationSampler[T]
+
+proc newArrayAnimationSampler*[T](): ArrayAnimationSampler[T] =
+    result.new()
+    result.sampleImpl = nil
+
+discard newArrayAnimationSampler[Foo6]()
+discard newArrayAnimationSampler[AnotherFoo]()
+
+type
+  DefaultIsNone* = pointer | ptr | ref | proc {.nimcall.} | cstring | cstringArray
+  OptionKind* {.pure.} = enum None, Some
+  OptionA* [T] = object of RootObj
+    when T is DefaultIsNone:
+      value: T
+    else:
+      value: T
+      kind: OptionKind
+  SomeA* [T] = object of OptionA[T]
diff --git a/tests/objects/tobject_default_value.nim b/tests/objects/tobject_default_value.nim
new file mode 100644
index 000000000..0cd05e4f3
--- /dev/null
+++ b/tests/objects/tobject_default_value.nim
@@ -0,0 +1,780 @@
+discard """
+  matrix: "-d:nimPreviewRangeDefault --mm:refc; -d:nimPreviewRangeDefault --warningAsError:ProveInit --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/[times, macros, tables]
+
+type
+  Guess = object
+    poi: DateTime
+
+  GuessDistinct = distinct Guess
+
+block:
+  var x: Guess
+  discard Guess()
+
+  var y: GuessDistinct
+
+  discard y
+
+  discard GuessDistinct(x)
+
+
+import mobject_default_value
+
+block:
+  let x = Default()
+  doAssert x.se == 0'i32
+
+block:
+  let x = default(Default)
+  doAssert x.se == 0'i32
+# echo Default(poi: 12)
+# echo Default(poi: 17)
+
+# echo NonDefault(poi: 77)
+
+block:
+  var x: Default
+  doAssert x.se == 0'i32
+
+type
+  ObjectBase = object of RootObj
+    value = 12
+
+  ObjectBaseDistinct = distinct ObjectBase
+
+  DinstinctInObject = object
+    data: ObjectBaseDistinct
+
+  Object = object of ObjectBase
+    time: float = 1.2
+    date: int
+    scale: range[1..10]
+
+  Object2 = object
+    name: Object
+
+  Object3 = object
+    obj: Object2
+
+  ObjectTuple = tuple
+    base: ObjectBase
+    typ: int
+    obj: Object
+
+  TupleInObject = object
+    size = 777
+    data: ObjectTuple
+
+  Ref = ref object of ObjectBase
+
+  RefInt = ref object of Ref
+    data = 73
+
+  Ref2 = ref object of ObjectBase
+
+  RefInt2 = ref object of Ref
+    data = 73
+
+var t {.threadvar.}: Default
+# var m1, m2 {.threadvar.}: Default
+
+block:
+  doAssert t.se == 0'i32
+
+block: # ARC/ORC cannot bind destructors twice, so it cannot
+      # be moved into main
+  block:
+    var x: Ref
+    new(x)
+    doAssert x.value == 12, "Ref.value = " & $x.value
+
+    var y: RefInt
+    new(y)
+    doAssert y.value == 12
+    doAssert y.data == 73
+
+  block:
+    var x: Ref2
+    new(x, proc (x: Ref2) {.nimcall.} = discard "call Ref")
+    doAssert x.value == 12, "Ref.value = " & $x.value
+
+    proc call(x: RefInt2) =
+      discard "call RefInt"
+
+    var y: RefInt2
+    new(y, call)
+    doAssert y.value == 12
+    doAssert y.data == 73
+
+template main {.dirty.} =
+  block: # bug #16744
+    type
+      R = range[1..10]
+      Obj = object
+        r: R
+
+    var
+      rVal: R = default(R) # Works fine
+      objVal = default(Obj)
+
+    doAssert rVal == 1
+    doAssert objVal.r == 1
+
+  block: # bug #16744
+    type
+      R = range[1..10]
+      Obj = object
+        r: R
+
+    var
+      rVal: R = default(R) # Works fine
+      objVal = Obj()
+
+    doAssert rVal == 1 # it should be 1
+    doAssert objVal.r == 1
+
+  block: # bug #3608
+    type
+      abc = ref object
+        w: range[2..100]
+
+    proc createABC(): abc =
+      new(result)
+      result.w = 20
+
+    doAssert createABC().w == 20
+
+  block:
+    var x = new ObjectBase
+    doAssert x.value == 12
+
+    proc hello(): ref ObjectBase =
+      new result
+
+    let z = hello()
+    doAssert z.value == 12
+
+  block:
+    var base = ObjectBase()
+    var x: ObjectBaseDistinct = ObjectBaseDistinct(base)
+    doAssert ObjectBase(x).value == 12
+    let y = ObjectBaseDistinct(default(ObjectBase))
+    doAssert ObjectBase(y).value == 12
+
+    let m = ObjectBaseDistinct(ObjectBase())
+    doAssert ObjectBase(m).value == 12
+
+    proc hello(): ObjectBaseDistinct =
+      result = ObjectBaseDistinct(default(ObjectBase))
+
+    let z = hello()
+    doAssert ObjectBase(z).value == 12
+
+  block:
+    var x: DinstinctInObject
+    x.data = ObjectBaseDistinct(default(ObjectBase))
+
+    doAssert ObjectBase(x.data).value == 12
+
+  block:
+    var x = Object()
+    doAssert x.value == 12
+    doAssert x.time == 1.2
+    doAssert x.scale == 1
+
+    let y = default(Object)
+    doAssert y.value == 12
+    doAssert y.time == 1.2
+    doAssert y.scale == 1
+
+    var x1, x2, x3 = default(Object)
+    doAssert x1.value == 12
+    doAssert x1.time == 1.2
+    doAssert x1.scale == 1
+    doAssert x2.value == 12
+    doAssert x2.time == 1.2
+    doAssert x2.scale == 1
+    doAssert x3.value == 12
+    doAssert x3.time == 1.2
+    doAssert x3.scale == 1
+
+  block:
+    var x = new Object
+    doAssert x[] == default(Object)
+
+  block:
+    var x = default(Object2)
+    doAssert x.name.value == 12
+    doAssert x.name.time == 1.2
+    doAssert x.name.scale == 1
+
+  block:
+    let x = Object2()
+    doAssert x.name.value == 12
+    doAssert x.name.time == 1.2
+    doAssert x.name.scale == 1
+
+  block:
+    var x: ref Object2
+    new x
+    doAssert x[] == default(Object2)
+
+  block:
+    var x = default(Object3)
+    doAssert x.obj.name.value == 12
+    doAssert x.obj.name.time == 1.2
+    doAssert x.obj.name.scale == 1
+
+  block:
+    var x = Object3()
+    doAssert x.obj.name.value == 12
+    doAssert x.obj.name.time == 1.2
+    doAssert x.obj.name.scale == 1
+
+  when nimvm:
+    # todo
+    discard "fixme"
+  else:
+    when defined(gcArc) or defined(gcOrc):
+      block: #seq
+        var x = newSeq[Object](10)
+        let y = x[0]
+        doAssert y.value == 12
+        doAssert y.time == 1.2
+        doAssert y.scale == 1
+
+      block:
+        var x: seq[Object]
+        setLen(x, 5)
+        let y = x[^1]
+        doAssert y.value == 12
+        doAssert y.time == 1.2
+        doAssert y.scale == 1
+
+      block:
+        var my = @[1, 2, 3, 4, 5]
+        my.setLen(0)
+        my.setLen(5)
+        doAssert my == @[0, 0, 0, 0, 0]
+
+      block:
+        var my = "hello"
+        my.setLen(0)
+        my.setLen(5)
+        doAssert $(@my) == """@['\x00', '\x00', '\x00', '\x00', '\x00']"""
+
+  block: # array
+    var x: array[10, Object] = default(array[10, Object])
+    let y = x[0]
+    doAssert y.value == 12
+    doAssert y.time == 1.2
+    doAssert y.scale == 1
+
+  block: # array
+    var x {.noinit.}: array[10, Object]
+    discard x
+
+  block: # tuple
+    var x = default(ObjectTuple)
+    doAssert x.base.value == 12
+    doAssert x.typ == 0
+    doAssert x.obj.time == 1.2
+    doAssert x.obj.date == 0
+    doAssert x.obj.scale == 1
+    doAssert x.obj.value == 12
+
+  block: # tuple in object
+    var x = default(TupleInObject)
+    doAssert x.data.base.value == 12
+    doAssert x.data.typ == 0
+    doAssert x.data.obj.time == 1.2
+    doAssert x.data.obj.date == 0
+    doAssert x.data.obj.scale == 1
+    doAssert x.data.obj.value == 12
+    doAssert x.size == 777
+
+  type
+    ObjectArray = object
+      data: array[10, Object]
+
+  block:
+    var x = default(ObjectArray)
+    let y = x.data[0]
+    doAssert y.value == 12
+    doAssert y.time == 1.2
+    doAssert y.scale == 1
+
+  block:
+    var x: PrellDeque[int]
+    doAssert x.pendingTasks == 0
+
+  type
+    Color = enum
+      Red, Blue, Yellow
+
+    ObjectVarint = object
+      case kind: Color
+      of Red:
+        data: int = 10
+      of Blue:
+        fill = "123"
+      of Yellow:
+        time = 1.8'f32
+
+    ObjectVarint1 = object
+      case kind: Color = Blue
+      of Red:
+        data1: int = 10
+      of Blue:
+        fill2 = "123"
+        cry: float
+      of Yellow:
+        time3 = 1.8'f32
+        him: int
+
+  block:
+    var x = ObjectVarint(kind: Red)
+    doAssert x.kind == Red
+    doAssert x.data == 10
+
+  block:
+    var x = ObjectVarint(kind: Blue)
+    doAssert x.kind == Blue
+    doAssert x.fill == "123"
+
+  block:
+    var x = ObjectVarint(kind: Yellow)
+    doAssert x.kind == Yellow
+    doAssert typeof(x.time) is float32
+
+  block:
+    var x = default(ObjectVarint1)
+    doAssert x.kind == Blue
+    doAssert x.fill2 == "123"
+    x.cry = 326
+
+  type
+    ObjectVarint2 = object
+      case kind: Color
+      of Red:
+        data: int = 10
+      of Blue:
+        fill = "123"
+      of Yellow:
+        time = 1.8'f32
+
+  block:
+    var x = ObjectVarint2(kind: Blue)
+    doAssert x.fill == "123"
+
+  block:
+    type
+      Color = enum
+        Red, Blue, Yellow
+  
+    type
+      ObjectVarint3 = object
+        case kind: Color = Blue
+        of Red:
+          data1: int = 10
+        of Blue:
+          case name: Color = Blue
+          of Blue:
+            go = 12
+          else:
+            temp = 66
+          fill2 = "123"
+          cry: float
+        of Yellow:
+          time3 = 1.8'f32
+          him: int
+
+    block:
+      var x = default(ObjectVarint3)
+      doAssert x.kind == Blue
+      doAssert x.name == Blue
+      doAssert x.go == 12
+
+    block:
+      var x = ObjectVarint3(kind: Blue, name: Red, temp: 99)
+      doAssert x.kind == Blue
+      doAssert x.name == Red
+      doAssert x.temp == 99
+
+  block:
+    type
+      Default = tuple
+        id: int = 1
+        obj: ObjectBase
+        name: string
+
+      Class = object
+        def: Default
+
+      Member = object
+        def: Default = (id: 777, obj: ObjectBase(), name: "fine")
+
+    block:
+      var x = default(Default)
+      doAssert x.id == 1
+      doAssert x.obj == default(ObjectBase)
+      doAssert x.name == ""
+
+    block:
+      var x = default(Class)
+      doAssert x.def == default(Default)
+      doAssert x.def.id == 1
+      doAssert x.def.obj == default(ObjectBase)
+      doAssert x.def.name == ""
+
+    block:
+      var x = default(Member)
+      doAssert x.def.id == 777
+      doAssert x.def.obj == default(ObjectBase)
+      doAssert x.def.name == "fine"
+
+  block:
+    var x {.noinit.} = 12
+    doAssert x == 12
+
+    type
+      Pure = object
+        id: int = 12
+
+    var y {.noinit.}: Pure
+    doAssert y.id == 0
+
+    var z {.noinit.}: Pure = Pure(id: 77)
+    doAssert z.id == 77
+
+  block: # bug #20681
+    type A = object
+      d: DateTime = DateTime()
+
+    let x = default(A)
+    doAssert $x == "(d: Uninitialized DateTime)"
+
+  block: # bug #20715
+    block:
+      type
+        Foo = enum
+          A
+          B
+
+        Bar = object
+          case foo: Foo
+          of A:
+            t: range[-1..2]
+          else: discard
+
+      var d = default(Bar)
+      doAssert d.t == -1
+
+    block:
+      type
+        Foo = enum
+          A
+          B
+
+        Bar = object
+          case foo: Foo
+          of A:
+            t: range[0..2]
+          else: discard
+
+      var d = default(Bar)
+      doAssert d.t == 0
+
+    block: # bug #20740
+      block:
+        proc foo(x: static DateTime = Datetime()) =
+          discard
+
+        foo()
+
+      block:
+        macro foo(x: static DateTime) =
+          discard x
+
+        macro foo2: untyped =
+          var x = DateTime()
+
+          result = quote do:
+            foo(`x`)
+
+        foo2()
+
+
+  block: # issue #20699
+    type
+      Either[A,B] = object
+        case kind:bool
+        of false:
+          b: B
+        of true:
+            a: A
+      O = object of RootRef
+
+    proc oToEither(o:O):Either[O,void] =
+      Either[O,void](kind:true,a: o)
+
+    discard oToEither(O())
+
+  block: # bug #20695
+    type
+      Default = object
+        tabs: Table[string, int] = initTable[string, int]()
+
+    let d = default(Default)
+    doAssert d.tabs.len == 0
+
+  block:
+    type
+      Default = object
+        tabs: Table[string, int] = Table[string, int]()
+
+    let d = default(Default)
+    doAssert d.tabs.len == 0
+
+
+  block:
+    type DjangoDateTime = distinct DateTime
+
+    type Default = object
+      data: DjangoDateTime = DjangoDateTime(DateTime())
+
+    let x = default(Default)
+    doAssert x.data is DjangoDateTime
+
+  block:
+    type DjangoDateTime = distinct DateTime
+
+    type Default = object
+      data = DjangoDateTime(DateTime())
+
+    let x = default(Default)
+    doAssert x.data is DjangoDateTime
+
+  block:
+    type
+      Result2 = object
+        case o: bool
+        of false:
+          e: float
+        of true:
+          v {.requiresInit.} : int = 1
+
+    proc startSessionSync(): Result2 =
+      return Result2(o: true)
+
+    proc mainSync =
+      let ff = startSessionSync()
+      doAssert ff.v == 1
+
+    mainSync()
+
+  block:
+    type
+      Result2 = object
+        v {.requiresInit.} : int = 1
+
+    proc startSessionSync(): Result2 =
+      return Result2()
+
+    proc mainSync =
+      let ff = startSessionSync()
+      doAssert ff.v == 1
+
+    mainSync()
+
+  block: # bug #21801
+    func evaluate(i: int): float =
+      0.0
+
+    func evaluate(): float =
+      0.0
+
+    type SearchOptions = object
+        evaluation: proc(): float = evaluate
+
+  block:
+    func evaluate(): float =
+      0.0
+
+    type SearchOptions = object
+        evaluation: proc(): float = evaluate
+
+  block:
+    func evaluate(i: int): float =
+      0.0
+
+    type SearchOptions = object
+        evaluation = evaluate
+  block:
+    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 `?`[T, E](self: Result[T, E]): auto =
+      let v = (self)
+      if not v.oResultPrivate:
+        when compiles(`assignResult?`(default(typeof(result)))):
+          when typeof(result) is typeof(v):
+            `assignResult?`(v)
+          elif E is void:
+            `assignResult?`(err(typeof(result)))
+          else:
+            `assignResult?`(err(typeof(result), v.eResultPrivate))
+          return
+        else:
+          return
+            when typeof(result) is typeof(v):
+              v
+            elif E is void:
+              err(typeof(result))
+            else:
+              err(typeof(result), v.eResultPrivate)
+
+      when not(T is void):
+        v.vResultPrivate
+        
+    type R = Result[int, string]
+
+    proc testAssignResult() =
+      var assigned: bool
+      template `assignResult?`(v: Result) =
+        assigned = true
+        result = v
+
+      proc failed(): Result[int, string] =
+        discard
+
+      proc calling(): Result[int, string] =
+        let _ = ? failed()
+        doAssert false
+
+      let r = calling()
+      doAssert assigned
+
+    when nimvm:
+      when not defined(js):
+        testAssignResult()
+    else:
+      testAssignResult()
+
+  block: # bug #22123
+    type Thing = object
+      x: float32 = 1
+
+    type ThingWithArray = object
+        arr: array[256, float32]
+        n: float32 = 1
+
+    type Container = ref object
+        thing: array[5, Thing]
+        thing_with_array: array[5, ThingWithArray]
+
+    var foo = new Container
+    doAssert int(foo.thing[0].x) == 1
+
+  block: # bug #22613
+    type
+      K = enum
+        A = "a"
+        B = "b"
+      T = object
+        case kind: K = B
+        of A:
+          a: int
+        of B:
+          b: float
+
+    doAssert T().kind == B
+
+  block: # bug #22926
+    type
+      Direction = enum
+        North
+        South
+        East
+        West
+
+      ArrayObj1 = object
+        list: array[Direction, int]
+
+      ArrayObj2 = object
+        list: array[Direction, int] = [1, 2, 3, 4]
+
+    block:
+      var a: ArrayObj1
+      doAssert a.list[West] == 0
+      var b = default ArrayObj1
+      doAssert b.list[North] == 0
+
+
+    block:
+      var a: ArrayObj2
+      doAssert a.list[West] == 0
+      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/tobjects_issues.nim b/tests/objects/tobjects_issues.nim
new file mode 100644
index 000000000..f1a416d04
--- /dev/null
+++ b/tests/objects/tobjects_issues.nim
@@ -0,0 +1,117 @@
+discard """
+  output: '''
+tbObj of TC true
+true
+5
+true
+is Nil false
+'''
+"""
+
+
+block t1053:
+  type
+    TA = object of RootObj
+      a: int
+    TB = object of TA
+      b: int
+    TC = object of TB
+      c: int
+
+  proc test(p: TA) =
+    if p of TB:
+      echo "tbObj of TC ", p of TC
+
+  var v = TC()
+  v.a = 1
+  v.b = 2
+  v.c = 3
+  test(v)
+
+
+
+block t924:
+  type
+    MyObject = object of RootObj
+      x: int
+  var asd: MyObject
+
+  proc isMyObject(obj: RootObj) =
+      echo obj of MyObject
+      if obj of MyObject:
+          let a = MyObject(obj)
+          echo a.x
+
+  asd.x = 5
+  isMyObject(asd)
+
+
+
+block t4673:
+  type
+    BaseObj[T] = ref object of RootObj
+    SomeObj = ref object of BaseObj[int]
+
+  proc doSomething[T](o: BaseObj[T]) =
+    echo "true"
+  var o = new(SomeObj)
+  o.doSomething() # Error: cannot instantiate: 'T'
+
+
+
+block t1658:
+  type
+    Loop = ref object
+      onBeforeSelect: proc (L: Loop)
+
+  var L: Loop
+  new L
+  L.onBeforeSelect = proc (bar: Loop) =
+    echo "is Nil ", bar.isNil
+
+  L.onBeforeSelect(L)
+
+
+
+block t2508:
+  type
+    GenericNodeObj[T] = ref object
+      obj: T
+    Node = ref object
+      children: seq[Node]
+      parent: Node
+      nodeObj: GenericNodeObj[int]
+
+  proc newNode(nodeObj: GenericNodeObj): Node =
+    result = Node(nodeObj: nodeObj)
+    newSeq(result.children, 10)
+
+  var genericObj = GenericNodeObj[int]()
+  var myNode = newNode(genericObj)
+
+
+
+block t2540:
+  type
+    BaseSceneNode[T] = ref object of RootObj
+      children: seq[BaseSceneNode[T]]
+      parent: BaseSceneNode[T]
+    SceneNode[T] = ref object of BaseSceneNode[T]
+    SomeObj = ref object
+
+  proc newSceneNode[T](): SceneNode[T] =
+    new result
+    result.children = @[]
+
+  var aNode = newSceneNode[SomeObj]()
+
+
+block t3038:
+  type
+    Data[T] = ref object of RootObj
+      data: T
+    Type = ref object of RootObj
+    SubType[T] = ref object of Type
+      data: Data[T]
+    SubSubType = ref object of SubType[int]
+    SubSubSubType = ref object of SubSubType
diff --git a/tests/objects/tobjects_various.nim b/tests/objects/tobjects_various.nim
new file mode 100644
index 000000000..55db9312e
--- /dev/null
+++ b/tests/objects/tobjects_various.nim
@@ -0,0 +1,120 @@
+discard """
+  output: '''
+34
+b
+wohoo
+baz
+'''
+"""
+
+
+block tobject2:
+  # Tests the object implementation
+  type
+    TPoint2d {.inheritable.} = object
+      x, y: int
+    TPoint3d = object of TPoint2d
+      z: int # added a field
+
+  proc getPoint( p: var TPoint2d) =
+    writeLine(stdout, p.x)
+
+  var p: TPoint3d
+
+  TPoint2d(p).x = 34
+  p.y = 98
+  p.z = 343
+
+  getPoint(p)
+
+
+
+block tofopr:
+  type
+    TMyType {.inheritable.} = object
+      len: int
+      data: string
+
+    TOtherType = object of TMyType
+
+  proc p(x: TMyType): bool =
+    return x of TOtherType
+
+  var
+    m: TMyType
+    n: TOtherType
+
+  doAssert p(m) == false
+  doAssert p(n)
+
+
+
+block toop:
+  type
+    TA = object of RootObj
+      x, y: int
+    TB = object of TA
+      z: int
+    TC = object of TB
+      whatever: string
+
+  proc p(a: var TA) = echo "a"
+  proc p(b: var TB) = echo "b"
+
+  var c: TC
+  p(c)
+
+
+
+block tfefobjsyntax:
+  type
+    Foo = object
+      a, b: int
+      s: string
+    FooBar = object of RootObj
+      n, m: string
+    Baz = object of FooBar
+
+  proc invoke(a: ref Baz) =
+    echo "baz"
+
+  # check object construction:
+  let x = (ref Foo)(a: 0, b: 45, s: "wohoo")
+  echo x.s
+
+  var y: ref FooBar = (ref Baz)(n: "n", m: "m")
+  invoke((ref Baz)(y))
+
+
+
+block t3012:
+  type
+    A {.inheritable.} = object
+    C {.inheritable.} = ref object
+
+  type
+    AA = ref object of A
+    CC = ref object of C
+
+
+
+block t7244:
+  type
+    Foo = ref object of RootRef
+    Bar = ref object of Foo
+
+  proc test(foo: var Foo) = discard
+  proc test(bar: var Bar) = test(Foo(bar))
+
+
+import std/macros
+
+#bug #20856
+macro ensureImplWorksOnConstr(t: typed): untyped =
+  expectKind(t, nnkObjConstr)
+  doAssert t[0].getTypeInst.getImpl.repr == "A = object"
+  doAssert t[0].getImpl.repr == "A = object"
+
+type A = object
+
+ensureImplWorksOnConstr(A())
diff --git a/tests/objects/tobjpragma.nim b/tests/objects/tobjpragma.nim
new file mode 100644
index 000000000..789b3ec4e
--- /dev/null
+++ b/tests/objects/tobjpragma.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''
+2
+3
+9
+257
+1
+2
+3
+'''
+disabled: "true"
+"""
+
+# Disabled since some versions of GCC ignore the 'packed' attribute
+
+# Test
+
+type
+  Foo {.packed.} = object
+    a: int8
+    b: int8
+
+  Bar {.packed.} = object
+    a: int8
+    b: int16
+
+  Daz {.packed.} = object
+    a: int32
+    b: int8
+    c: int32
+
+
+var f = Foo(a: 1, b: 1)
+var b: Bar
+var d: Daz
+
+echo sizeof(f)
+echo sizeof(b)
+echo sizeof(d)
+echo (cast[ptr int16](f.addr)[])
+
+type
+  Union {.union.} = object
+    a: int8
+    b: int8
+
+var u: Union
+u.a = 1
+echo u.b
+u.a = 2
+echo u.b
+u.b = 3
+echo u.a
diff --git a/tests/toop1.nim b/tests/objects/toop1.nim
index 8bae002e7..3e9b24990 100755..100644
--- a/tests/toop1.nim
+++ b/tests/objects/toop1.nim
@@ -1,23 +1,26 @@
+discard """
+  output: "34[]o 5"
+"""
 # Test the stuff in the tutorial
 import macros
 
 type
-  TFigure = object of TObject    # abstract base class:
-    draw: proc (my: var TFigure) # concrete classes implement this proc
-  
-proc init(f: var TFigure) = 
+  TFigure = object of RootObj    # abstract base class:
+    draw: proc (my: var TFigure) {.nimcall.} # concrete classes implement this
+
+proc init(f: var TFigure) =
   f.draw = nil
 
 type
   TCircle = object of TFigure
     radius: int
-  
-proc drawCircle(my: var TCircle) = stdout.writeln("o " & $my.radius)
 
-proc init(my: var TCircle) = 
+proc drawCircle(my: var TCircle) = stdout.writeLine("o " & $my.radius)
+
+proc init(my: var TCircle) =
   init(TFigure(my)) # call base constructor
   my.radius = 5
-  my.draw = drawCircle
+  my.draw = cast[proc (my: var TFigure) {.nimcall.}](drawCircle)
 
 type
   TRectangle = object of TFigure
@@ -25,13 +28,14 @@ type
 
 proc drawRectangle(my: var TRectangle) = stdout.write("[]")
 
-proc init(my: var TRectangle) = 
+proc init(my: var TRectangle) =
   init(TFigure(my)) # call base constructor
   my.width = 5
   my.height = 10
-  my.draw = drawRectangle
+  my.draw = cast[proc (my: var TFigure) {.nimcall.}](drawRectangle)
 
-macro `!` (n: expr): stmt = 
+macro `!` (n: varargs[untyped]): typed =
+  let n = callsite()
   result = newNimNode(nnkCall, n)
   var dot = newNimNode(nnkDotExpr, n)
   dot.add(n[1])    # obj
@@ -51,20 +55,20 @@ macro `!` (n: expr): stmt =
     result.add(n[1]) # obj
 
 type
-  TSocket* = object of TObject
+  TSocket* = object of RootObj
     FHost: int # cannot be accessed from the outside of the module
                # the `F` prefix is a convention to avoid clashes since
                # the accessors are named `host`
-               
-proc `host=`*(s: var TSocket, value: int) {.inline.} = 
+
+proc `host=`*(s: var TSocket, value: int) {.inline.} =
   ## setter of hostAddr
   s.FHost = value
 
 proc host*(s: TSocket): int {.inline.} =
   ## getter of hostAddr
   return s.FHost
-  
-var 
+
+var
   s: TSocket
 s.host = 34  # same as `host=`(s, 34)
 stdout.write(s.host)
@@ -76,7 +80,6 @@ var
 init(r)
 init(c)
 r!draw
-c!draw() 
+c!draw()
 
 #OUT 34[]o 5
-
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/objects/tunsafenew.nim b/tests/objects/tunsafenew.nim
new file mode 100644
index 000000000..6c1b33cd9
--- /dev/null
+++ b/tests/objects/tunsafenew.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "conversion from int literal(-1) to Natural is invalid"
+"""
+
+type
+  Obj = object
+    case b: bool
+    else: discard
+var o: ref Obj
+unsafeNew(o, -1)
\ No newline at end of file
diff --git a/tests/objects/tunsafenew2.nim b/tests/objects/tunsafenew2.nim
new file mode 100644
index 000000000..83112bcfc
--- /dev/null
+++ b/tests/objects/tunsafenew2.nim
@@ -0,0 +1,15 @@
+discard """
+valgrind: "leaks"
+matrix: "-d:useMalloc"
+targets: "c cpp"
+"""
+
+type
+  Obj = object
+    case b: bool
+    else: discard
+    a: UncheckedArray[byte]
+
+var o: ref Obj
+unsafeNew(o, sizeof(Obj) + 512)
+zeroMem(addr o.a, 512)
diff --git a/tests/objects/twhen1.nim b/tests/objects/twhen1.nim
new file mode 100644
index 000000000..fe072a46b
--- /dev/null
+++ b/tests/objects/twhen1.nim
@@ -0,0 +1,89 @@
+const Z = 0
+
+type
+  Foo[T] = object
+   when true:
+     u: int
+   else:
+     v: int
+  Foo1[T] = object
+   when T is int:
+     x: T
+   elif true:
+     z: char
+  Foo2[x:static[int]] = object
+    when (x and 1) == 1:
+      x: array[x+1,int]
+    else:
+      x: array[x,int]
+
+  Foo3 = Foo2[128]
+
+  # #8417
+  Foo4[A: static[int]] = object
+    when Z == 0:
+      discard
+    else:
+      discard
+
+block:
+  var x: Foo[int] = Foo[int](u: 42)
+  doAssert x.u == 42
+
+# Don't evaluate `when` branches before the type is instantiated
+block:
+  var x: Foo1[bool] = Foo1[bool](z: 'o')
+  doAssert x.z == 'o'
+
+block:
+  var x: Foo2[3]
+  doAssert x.x.len == 4
+
+block:
+  var x: Foo2[4]
+  doAssert x.x.len == 4
+
+block:
+  var x: Foo3
+  doAssert x.x.len == 128
+
+block:
+  var x: Foo4[0]
+
+type
+  MyObject = object
+    x: int
+    when (NimMajor, NimMinor) >= (1, 1):
+      y: int
+discard MyObject(x: 100, y: 200)
+
+block: # Ensure when evaluates properly in objects
+  type X[bits: static int] = object #22474
+    when bits >= 256:
+     data32: byte
+    else:
+     data16: byte
+
+  static:
+    discard X[255]().data16
+    discard X[256]().data32
+
+
+  type ComplexExprObject[S: static string, I: static int, Y: static auto] = object
+    when 'h' in S and I < 10 and Y isnot float:
+      a: int
+    elif I > 30:
+      b: int
+    elif typeof(Y) is float:
+      c: int
+    else:
+      d: int
+
+  static:
+    discard ComplexExprObject["hello", 9, 300i32]().a
+    discard ComplexExprObject["", 40, 30f]().b
+    discard ComplexExprObject["", 20, float 30]().c
+    discard ComplexExprObject["", 20, ""]().d
+
+
+
diff --git a/tests/objvariant/t14581.nim b/tests/objvariant/t14581.nim
new file mode 100644
index 000000000..72ba32f18
--- /dev/null
+++ b/tests/objvariant/t14581.nim
@@ -0,0 +1,25 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+  output: "abc: @[(kind: A, x: 0)]"
+"""
+
+import std/tables
+
+type E = enum
+  A, B
+
+type O = object
+  case kind: E
+  of A:
+    x: int
+  of B:
+    y: int 
+
+proc someTable(): Table[string, seq[O]] =
+  result = initTable[string, seq[O]]()
+  result["abc"] = @[O(kind: A)]
+
+const t = someTable()
+
+for k, v in t:
+  echo k, ": ", v
diff --git a/tests/objvariant/tadrdisc.nim b/tests/objvariant/tadrdisc.nim
new file mode 100644
index 000000000..5e4e39a44
--- /dev/null
+++ b/tests/objvariant/tadrdisc.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "type mismatch: got <TKind>"
+  file: "tadrdisc.nim"
+  line: 20
+"""
+# Test that the address of a discriminants cannot be taken
+
+type
+  TKind = enum ka, kb, kc
+  TA = object
+    case k: TKind
+    of ka: x, y: int
+    of kb: a, b: string
+    of kc: c, d: float
+
+proc setKind(k: var TKind) =
+  k = kc
+
+var a: TA
+setKind(a.k)
diff --git a/tests/objvariant/tcheckedfield1.nim b/tests/objvariant/tcheckedfield1.nim
new file mode 100644
index 000000000..4a6c49f66
--- /dev/null
+++ b/tests/objvariant/tcheckedfield1.nim
@@ -0,0 +1,61 @@
+discard """
+  nimout: "tcheckedfield1.nim(39, 6) Warning: cannot prove that field 'x.s' is accessible [ProveField]"
+  action: run
+  output: "abc abc"
+"""
+
+import strutils
+
+{.warning[ProveField]: on.}
+{.experimental: "notnil".}
+type
+  TNodeKind = enum
+    nkBinary, nkTernary, nkStr
+  PNode = ref TNode not nil
+  TNode = object
+    case k: TNodeKind
+    of nkBinary, nkTernary: a, b: PNode
+    of nkStr: s: string
+
+  PList = ref object
+    data: string
+    next: PList
+
+proc getData(x: PList not nil) =
+  echo x.data
+
+var head: PList
+
+proc processList() =
+  var it = head
+  while it != nil:
+    getData(it)
+    it = it.next
+
+proc toString2(x: PNode): string =
+  if x.k < nkStr:
+    toString2(x.a) & " " & toString2(x.b)
+  else:
+    x.s
+
+proc toString(x: PNode): string =
+  case x.k
+  of nkTernary, nkBinary:
+    toString(x.a) & " " & toString(x.b)
+  of nkStr:
+    x.s
+
+proc toString3(x: PNode): string =
+  if x.k <= nkBinary:
+    toString3(x.a) & " " & toString3(x.b)
+  else:
+    x.s # x.k in {nkStr}  --> fact:  not (x.k <= nkBinary)
+
+proc p() =
+  var x: PNode = PNode(k: nkStr, s: "abc")
+
+  let y = x
+  if not y.isNil:
+    echo toString(y), " ", toString2(y)
+
+p()
diff --git a/tests/objvariant/tconstobjvariant.nim b/tests/objvariant/tconstobjvariant.nim
new file mode 100644
index 000000000..45a647707
--- /dev/null
+++ b/tests/objvariant/tconstobjvariant.nim
@@ -0,0 +1,18 @@
+# This is a sample code, the first echo statement prints out the error
+type
+  A = object
+    case w: uint8
+    of 1:
+      n: int
+    else:
+      other: string
+
+const
+  a = A(w: 1, n: 5)
+
+proc foo =
+
+  let c = [a]
+  doAssert c[0].n == 5
+
+foo()
\ No newline at end of file
diff --git a/tests/objvariant/tconstructionorder.nim b/tests/objvariant/tconstructionorder.nim
new file mode 100644
index 000000000..5ca484884
--- /dev/null
+++ b/tests/objvariant/tconstructionorder.nim
@@ -0,0 +1,114 @@
+discard """
+  output: "SUCCESS"
+"""
+
+# A test to ensure that the order in which a variant
+# object is constructed doesn't matter.
+
+type
+  NodeKind = enum
+    Literal, Operator
+
+  Node = ref object
+    case kind: NodeKind
+    of Literal:
+      value: int
+    of Operator:
+      left, right: Node
+      operator: char
+
+# The trees used through out this test should
+# be the same after construction, the only difference
+# being the way we specify their construction.
+# This will test that all the values are what we expect.
+proc assertTree(root: Node) =
+  # check root of tree
+  doAssert root.kind == Operator
+  doAssert root.operator == '*'
+
+  # check left subtree
+  doAssert root.left.value == 5
+  doAssert root.left.kind == Literal
+
+  # check right subtree
+  doAssert root.right.kind == Operator
+  doAssert root.right.operator == '+'
+
+  doAssert root.right.left.value == 5
+  doAssert root.right.left.kind == Literal
+
+  doAssert root.right.right.value == 10
+  doAssert root.right.right.kind == Literal
+
+proc newLiteralNode(value: int): Node =
+  result = Node(
+    kind: Literal,
+    value: value
+  )
+
+var rootOrder1 = Node(
+  kind: Operator,
+  operator: '*',
+  left: newLiteralNode(5),
+  right: Node(
+    left: newLiteralNode(5),
+    right: newLiteralNode(10),
+    kind: Operator,
+    operator: '+'
+  )
+)
+assertTree(rootOrder1)
+
+var rootOrder2 = Node(
+  operator: '*',
+  kind: Operator,
+  left: newLiteralNode(5),
+  right: Node(
+    left: newLiteralNode(5),
+    right: newLiteralNode(10),
+    kind: Operator,
+    operator: '+'
+  )
+)
+assertTree(rootOrder2)
+
+var rootOrder3 = Node(
+  left: newLiteralNode(5),
+  operator: '*',
+  kind: Operator,
+  right: Node(
+    left: newLiteralNode(5),
+    right: newLiteralNode(10),
+    kind: Operator,
+    operator: '+'
+  )
+)
+assertTree(rootOrder3)
+
+var rootOrder4 = Node(
+  left: newLiteralNode(5),
+  operator: '*',
+  kind: Operator,
+  right: Node(
+    left: newLiteralNode(5),
+    kind: Operator,
+    operator: '+',
+    right: newLiteralNode(10)
+  )
+)
+assertTree(rootOrder4)
+
+var rootOrder5 = Node(
+  left: newLiteralNode(5),
+  operator: '*',
+  kind: Operator,
+  right: Node(
+    left: newLiteralNode(5),
+    operator: '+',
+    right: newLiteralNode(10),
+    kind: Operator
+  )
+)
+assertTree(rootOrder5)
+
+echo "SUCCESS"
diff --git a/tests/objvariant/temptycaseobj.nim b/tests/objvariant/temptycaseobj.nim
new file mode 100644
index 000000000..2b2c40514
--- /dev/null
+++ b/tests/objvariant/temptycaseobj.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "identifier expected, but got 'keyword of'"
+  line: 11
+"""
+
+type
+  TMyEnum = enum enA, enU, enO
+  TMyCase = object
+    case e: TMyEnum
+    of enA:
+    of enU: x, y: int
+    of enO: a, b: string
diff --git a/tests/objvariant/tfloatrangeobj.nim b/tests/objvariant/tfloatrangeobj.nim
new file mode 100644
index 000000000..67e886302
--- /dev/null
+++ b/tests/objvariant/tfloatrangeobj.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''(kind: 2.0, twoStr: "TWO STR")
+(kind: 1.0)
+'''
+disabled: "true"
+"""
+type
+  FloatRange = range[1.0..3.0]
+  VariantObj = object
+    case kind: FloatRange
+    of 2.0: twoStr: string
+
+echo VariantObj(kind: 2.0, twoStr: "TWO STR")
+echo VariantObj(kind: 1.0)
diff --git a/tests/objvariant/tnon_zero_discrim_err.nim b/tests/objvariant/tnon_zero_discrim_err.nim
new file mode 100644
index 000000000..c595bba1b
--- /dev/null
+++ b/tests/objvariant/tnon_zero_discrim_err.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "low(kind) must be 0 for discriminant"
+  line: 7
+"""
+type
+  HoledObj = object
+    case kind: int
+    of 0: a: int
+    else: discard
+
+let someInt = low(int)
+case someInt
+of 938: echo HoledObj(kind: someInt, a: 1)
+else: discard
diff --git a/tests/objvariant/treassign.nim b/tests/objvariant/treassign.nim
new file mode 100644
index 000000000..527204616
--- /dev/null
+++ b/tests/objvariant/treassign.nim
@@ -0,0 +1,58 @@
+discard """
+  output: "SUCCESS"
+"""
+
+type
+    BasicNumber = object of RootObj
+        value: float32
+    RefChild* = ref object
+        curr*: TokenObject
+    Token* {.pure.} = enum
+        foo,
+        bar,
+    TokenObject = object
+        case kind*: Token
+        of Token.foo:
+            foo*: string
+        of Token.bar:
+            bar*: BasicNumber
+
+
+var t = RefChild()
+
+t.curr = TokenObject(kind: Token.bar, bar: BasicNumber(value: 12.34))
+
+t.curr = TokenObject(kind: Token.foo, foo: "foo")
+
+echo "SUCCESS"
+
+proc passToVar(x: var Token) = discard
+
+{.cast(uncheckedAssign).}:
+  passToVar(t.curr.kind)
+
+  t.curr = TokenObject(kind: t.curr.kind, foo: "abc")
+
+  t.curr.kind = Token.foo
+
+
+block:
+  type
+    TokenKind = enum
+      strLit, intLit
+    Token = object
+      case kind*: TokenKind
+      of strLit:
+        s*: string
+      of intLit:
+        i*: int64
+
+  var t = Token(kind: strLit, s: "abc")
+
+  {.cast(uncheckedAssign).}:
+
+    # inside the 'cast' section it is allowed to assign to the 't.kind' field directly:
+    t.kind = intLit
+
+  {.cast(uncheckedAssign).}:
+    t.kind = strLit
\ No newline at end of file
diff --git a/tests/objvariant/trt_discrim.nim b/tests/objvariant/trt_discrim.nim
new file mode 100644
index 000000000..95b2a9f76
--- /dev/null
+++ b/tests/objvariant/trt_discrim.nim
@@ -0,0 +1,198 @@
+template accept(x) =
+  static: assert(compiles(x))
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+type
+  Kind = enum k1 = 0, k2 = 33, k3 = 84, k4 = 278, k5 = 1000 # Holed enum work! #No they don't..
+  KindObj = object
+    case kind: Kind
+    of k1, k2..k3: i32: int32
+    of k4: f32: float32
+    else: str: string
+
+  IntObj = object
+    case kind: uint8
+    of low(uint8) .. 127: bad: string
+    of 128'u8: neutral: string
+    of 129 .. high(uint8): good: string
+
+  OtherKind = enum ok1, ok2, ok3, ok4, ok5
+  NestedKindObj = object
+    case kind: Kind
+    of k3, k5: discard
+    of k2: str: string
+    of k1, k4:
+      case otherKind: OtherKind
+      of ok1, ok2..ok3: i32: int32
+      of ok4: f32: float32
+      else: nestedStr: string
+
+let kind = k4 # actual value should have no impact on the analysis.
+
+accept: # Mimics the structure of the type. The optimial case.
+  case kind
+  of k1, k2, k3: discard KindObj(kind: kind, i32: 1)
+  of k4: discard KindObj(kind: kind, f32: 2.0)
+  else: discard KindObj(kind: kind, str: "3")
+
+accept: # Specifying the else explicitly is fine too.
+  case kind
+  of k1, k2, k3: discard KindObj(kind: kind, i32: 1)
+  of k4: discard KindObj(kind: kind, f32: 2.0)
+  of k5: discard KindObj(kind: kind, str: "3")
+
+accept:
+  case kind
+  of k1..k3, k5: discard
+  else: discard KindObj(kind: kind, f32: 2.0)
+
+accept:
+  case kind
+  of k4, k5: discard
+  else: discard KindObj(kind: kind, i32: 1)
+
+accept: # elif branches are ignored
+  case kind
+  of k1, k2, k3: discard KindObj(kind: kind, i32: 1)
+  of k4: discard KindObj(kind: kind, f32: 2.0)
+  elif kind in {k1..k5}: discard
+  else: discard KindObj(kind: kind, str: "3")
+
+reject: # k4 conflicts with i32
+  case kind
+  of k1, k2, k3, k4: discard KindObj(kind: kind, i32: 1)
+  else: discard KindObj(kind: kind, str: "3")
+
+reject: # k4 is not caught, conflicts with str in the else branch
+  case kind
+  of k1, k2, k3: discard KindObj(kind: kind, i32: 1)
+  else: discard KindObj(kind: kind, str: "3")
+
+reject: # elif branches are ignored
+  case kind
+  of k1, k2, k3: discard KindObj(kind: kind, i32: 1)
+  elif kind == k4: discard
+  else: discard KindObj(kind: kind, str: "3")
+
+let intKind = 29'u8
+
+accept:
+  case intKind
+  of low(uint8) .. 127: discard IntObj(kind: intKind, bad: "bad")
+  of 128'u8: discard IntObj(kind: intKind, neutral: "neutral")
+  of 129 .. high(uint8): discard IntObj(kind: intKind, good: "good")
+
+reject: # 0 leaks to else
+  case intKind
+  of low(uint8) .. 127: discard IntObj(kind: intKind, bad: "bad")
+  of 129 .. high(uint8): discard IntObj(kind: intKind, good: "good")
+
+accept:
+  case intKind
+  of low(uint8) .. 127: discard IntObj(kind: intKind, bad: "bad")
+  of 128'u8: discard IntObj(kind: intKind, neutral: "neutral")
+  of 139'u8, 140 .. high(uint8), 129'u8 .. 138'u8: discard IntObj(kind: intKind, good: "good")
+
+
+accept:
+  case kind
+  of {k1, k2}, [k3]: discard KindObj(kind: kind, i32: 1)
+  of k4: discard KindObj(kind: kind, f32: 2.0)
+  else: discard KindObj(kind: kind, str: "3")
+
+reject:
+  case kind
+  of {k1, k2, k3}, [k4]: discard KindObj(kind: kind, i32: 1)
+  else: discard KindObj(kind: kind, str: "3")
+
+accept:
+  case kind
+  of k3, k5: discard NestedKindObj(kind: kind)
+  of k2: discard NestedKindObj(kind: kind, str: "not nested")
+  of k1, k4:
+    let otherKind = ok5
+    case otherKind
+    of ok1..ok3: discard NestedKindObj(kind: kind, otherKind: otherKind, i32: 3)
+    of ok4: discard NestedKindObj(kind: kind, otherKind: otherKind, f32: 5.0)
+    else: discard NestedKindObj(kind: kind, otherKind: otherKind,
+                                nestedStr: "nested")
+
+reject:
+  case kind
+  of k3, k5: discard NestedKindObj(kind: kind)
+  of k2: discard NestedKindObj(kind: kind, str: "not nested")
+  of k1, k4:
+    let otherKind = ok5
+    case otherKind
+    of ok1..ok3: discard NestedKindObj(kind: kind, otherKind: otherKind, i32: 3)
+    else: discard NestedKindObj(kind: kind, otherKind: otherKind,
+                                nestedStr: "nested")
+
+var varkind = k4
+
+reject: # not immutable.
+  case varkind
+  of k1, k2, k3: discard KindObj(varkind: kind, i32: 1)
+  of k4: discard KindObj(varkind: kind, f32: 2.0)
+  else: discard KindObj(varkind: kind, str: "3")
+
+accept:
+  proc kindProc(kind: Kind): KindObj =
+    case kind:
+    of k1: result = KindObj(kind: kind, i32: 1)
+    else: discard
+
+reject:
+  proc varKindProc(kind: var Kind): KindObj =
+    case kind:
+    of k1: result = KindObj(kind: kind, i32: 1)
+    else: discard
+
+type
+  Kind3 = enum
+    A, B, C, E
+
+  OkRange = range[B..C]
+  NotOkRange = range[B..E]
+
+  CaseObject = object
+    case kind: Kind3
+    of B, C:
+      field: int
+    else: discard
+
+accept:
+  let rtDiscriminator: OkRange = B
+  discard CaseObject(kind: rtDiscriminator, field: 1)
+
+accept:
+  let rtDiscriminator = B
+  discard CaseObject(kind: OkRange(rtDiscriminator), field: 1)
+
+accept:
+  const rtDiscriminator: NotOkRange = B
+  discard CaseObject(kind: rtDiscriminator, field: 1)
+
+accept:
+  discard CaseObject(kind: NotOkRange(B), field: 1)
+
+reject:
+  let rtDiscriminator: NotOkRange = B
+  discard CaseObject(kind: rtDiscriminator, field: 1)
+
+reject:
+  let rtDiscriminator = B
+  discard CaseObject(kind: NotOkRange(rtDiscriminator), field: 1)
+
+reject:
+  type Obj = object
+    case x: int
+    of 0 .. 1000:
+      field: int
+    else:
+      discard
+
+  let x: range[0..15] = 1
+  let o = Obj(x: x, field: 1)
diff --git a/tests/objvariant/trt_discrim_err0.nim b/tests/objvariant/trt_discrim_err0.nim
new file mode 100644
index 000000000..02b551cbc
--- /dev/null
+++ b/tests/objvariant/trt_discrim_err0.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "possible values {k1, k3, k4} are in conflict with discriminator values for selected object branch 3"
+  line: 17
+"""
+
+type
+  Kind = enum k1, k2, k3, k4, k5
+  KindObj = object
+    case kind: Kind
+    of k1, k2..k3: i32: int32
+    of k4: f32: float32
+    else: str: string
+
+let kind = k3
+case kind
+of k2: discard KindObj(kind: kind, i32: 1)
+else: discard KindObj(kind: kind, str: "3")
diff --git a/tests/objvariant/trt_discrim_err1.nim b/tests/objvariant/trt_discrim_err1.nim
new file mode 100644
index 000000000..de29420a2
--- /dev/null
+++ b/tests/objvariant/trt_discrim_err1.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "branch initialization with a runtime discriminator is not supported inside of an `elif` branch."
+  line: 16
+"""
+type
+  Color = enum Red, Green, Blue
+  ColorObj = object
+    case colorKind: Color
+    of Red: red: string
+    of Green: green: string
+    of Blue: blue: string
+
+let colorKind = Blue
+case colorKind
+of Red: echo ColorObj(colorKind: colorKind, red: "red")
+elif colorKind == Green: echo ColorObj(colorKind: colorKind, green: "green")
+else: echo ColorObj(colorKind: colorKind, blue: "blue")
diff --git a/tests/objvariant/trt_discrim_err2.nim b/tests/objvariant/trt_discrim_err2.nim
new file mode 100644
index 000000000..4f2790bc6
--- /dev/null
+++ b/tests/objvariant/trt_discrim_err2.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: " branch initialization with a runtime discriminator only supports ordinal types with 2^16 elements or less."
+  line: 13
+"""
+type
+  HoledObj = object
+    case kind: range[0 .. 20000]
+    of 0: a: int
+    else: discard
+
+let someInt = low(int)
+case someInt
+of 938: echo HoledObj(kind: someInt, a: 1)
+else: discard
diff --git a/tests/objvariant/trt_discrim_err3.nim b/tests/objvariant/trt_discrim_err3.nim
new file mode 100644
index 000000000..e739c3d50
--- /dev/null
+++ b/tests/objvariant/trt_discrim_err3.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "runtime discriminator must be immutable if branch fields are initialized, a 'let' binding is required."
+  line: 16
+"""
+
+type
+  Kind = enum k1, k2, k3, k4, k5
+  KindObj = object
+    case kind: Kind
+    of k1, k2..k3: i32: int32
+    of k4: f32: float32
+    else: str: string
+
+var kind = k3
+case kind
+of k2: discard KindObj(kind: kind, i32: 1)
+else: discard KindObj(kind: kind, str: "3")
diff --git a/tests/objvariant/tvariantstack.nim b/tests/objvariant/tvariantstack.nim
new file mode 100644
index 000000000..7fd41b476
--- /dev/null
+++ b/tests/objvariant/tvariantstack.nim
@@ -0,0 +1,77 @@
+discard """
+output: "came here"
+"""
+#BUG
+type
+  TAnyKind = enum
+    nkInt,
+    nkFloat,
+    nkString
+  PAny = ref TAny
+  TAny = object
+    case kind: TAnyKind
+    of nkInt: intVal: int
+    of nkFloat: floatVal: float
+    of nkString: strVal: string
+
+  TStack* = object
+    list*: seq[TAny]
+
+proc newStack(): TStack =
+  result.list = @[]
+
+proc push(Stack: var TStack, item: TAny) =
+  var nSeq: seq[TAny] = @[item]
+  for i in items(Stack.list):
+    nSeq.add(i)
+  Stack.list = nSeq
+
+proc pop(Stack: var TStack): TAny =
+  result = Stack.list[0]
+  Stack.list.delete(0)
+
+var stack = newStack()
+
+var s = TAny(kind: nkString, strVal: "test")
+
+stack.push(s)
+
+var nr = TAny(kind: nkInt, intVal: 78)
+
+stack.push(nr)
+
+var t = stack.pop()
+echo "came here"
+
+
+# another regression:
+type
+  LexerToken* = enum
+    ltYamlDirective, ltYamlVersion, ltTagDirective, ltTagShorthand,
+    ltTagUri, ltUnknownDirective, ltUnknownDirectiveParams, ltEmptyLine,
+    ltDirectivesEnd, ltDocumentEnd, ltStreamEnd, ltIndentation, ltQuotedScalar,
+    ltScalarPart, ltBlockScalarHeader, ltBlockScalar, ltSeqItemInd, ltMapKeyInd,
+    ltMapValInd, ltBraceOpen, ltBraceClose, ltBracketOpen, ltBracketClose,
+    ltComma, ltLiteralTag, ltTagHandle, ltAnchor, ltAlias
+
+const tokensWithValue =
+    {ltScalarPart, ltQuotedScalar, ltYamlVersion, ltTagShorthand, ltTagUri,
+     ltUnknownDirective, ltUnknownDirectiveParams, ltLiteralTag, ltAnchor,
+     ltAlias, ltBlockScalar}
+
+type
+  TokenWithValue = object
+    case kind: LexerToken
+    of tokensWithValue:
+      value: string
+    of ltIndentation:
+      indentation: int
+    of ltTagHandle:
+      handle, suffix: string
+    else: discard
+
+proc sp(v: string): TokenWithValue =
+  # test.nim(27, 17) Error: a case selecting discriminator 'kind' with value 'ltScalarPart' appears in the object construction, but the field(s) 'value' are in conflict with this value.
+  TokenWithValue(kind: ltScalarPart, value: v)
+
+let a = sp("test")
diff --git a/tests/objvariant/tyaoption.nim b/tests/objvariant/tyaoption.nim
new file mode 100644
index 000000000..80bfa4bae
--- /dev/null
+++ b/tests/objvariant/tyaoption.nim
@@ -0,0 +1,70 @@
+discard """
+  output: '''some(str), some(5), none
+some(5!)
+some(10)
+34'''
+"""
+
+import strutils
+
+type Option[A] = object
+  case isDefined*: bool
+    of true:
+      value*: A
+    of false:
+      nil
+
+proc some[A](value: A): Option[A] =
+  Option[A](isDefined: true, value: value)
+
+proc none[A](): Option[A] =
+  Option[A](isDefined: false)
+
+proc `$`[A](o: Option[A]): string =
+  if o.isDefined:
+    "some($1)" % [$o.value]
+  else:
+    "none"
+
+let x = some("str")
+let y = some(5)
+let z = none[int]()
+
+echo x, ", ", y, ", ", z
+
+proc intOrString[A : int | string](o: Option[A]): Option[A] =
+  when A is int:
+    some(o.value + 5)
+  elif A is string:
+    some(o.value & "!")
+  else:
+    o
+
+#let a1 = intOrString(none[String]())
+let a2 = intOrString(some("5"))
+let a3 = intOrString(some(5))
+#echo a1
+echo a2
+echo a3
+
+
+# bug #10033
+
+type
+  Token = enum
+    Int,
+    Float
+
+  Base = ref object of RootObj
+    case token: Token
+    of Int:
+      bInt: int
+    of Float:
+      bFloat: float
+
+  Child = ref object of Base
+
+let c = new Child
+c.token = Int
+c.bInt = 34
+echo c.bInt
diff --git a/tests/openarray/t6163.nim b/tests/openarray/t6163.nim
new file mode 100644
index 000000000..0e9d4e0e4
--- /dev/null
+++ b/tests/openarray/t6163.nim
@@ -0,0 +1,17 @@
+discard """
+  exitcode: 0
+  targets: "c cpp js"
+  output: '''19316
+'''
+"""
+
+from sugar import `->`, `=>`
+from math import `^`, sum
+from sequtils import filter, map, toSeq
+
+proc f: int =
+  toSeq(10..<10_000).filter(a => a == ($a).map(d => (d.ord-'0'.ord).int^4).sum).sum
+
+var a = f()
+
+echo a
diff --git a/tests/openarray/t8259.nim b/tests/openarray/t8259.nim
new file mode 100644
index 000000000..283c6cd02
--- /dev/null
+++ b/tests/openarray/t8259.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "invalid type: 'openArray[int]' for result"
+  line: 6
+"""
+
+proc foo(a: openArray[int]):auto = a
+echo foo(toOpenArray([1, 2], 0, 2))
diff --git a/tests/openarray/topena1.nim b/tests/openarray/topena1.nim
new file mode 100644
index 000000000..380c57f2a
--- /dev/null
+++ b/tests/openarray/topena1.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "invalid type"
+  file: "topena1.nim"
+  line: 9
+"""
+# Tests a special bug
+
+var
+  x: ref openArray[string] #ERROR_MSG invalid type
diff --git a/tests/openarray/topenarray.nim b/tests/openarray/topenarray.nim
new file mode 100644
index 000000000..25b983651
--- /dev/null
+++ b/tests/openarray/topenarray.nim
@@ -0,0 +1,88 @@
+discard """
+  targets: "c cpp js"
+"""
+
+proc fn1[T](a: openArray[T]): seq[T] =
+  for ai in a: result.add ai
+
+proc fn2[T](a: var openArray[T]): seq[T] =
+  for ai in a: result.add ai
+
+proc fn3[T](a: var openArray[T]) =
+  for i, ai in mpairs(a): ai = i * 10
+
+proc main =
+  var a = [1,2,3,4,5]
+
+  doAssert fn1(a.toOpenArray(1,3)) == @[2,3,4]
+
+  doAssert fn2(toOpenArray(a, 1, 3)) == @[2,3,4]
+  doAssert fn2(a.toOpenArray(1,3)) == @[2,3,4]
+
+  fn3(a.toOpenArray(1,3))
+  when defined(js): discard # xxx bug #15952: `a` left unchanged
+  else: doAssert a == [1, 0, 10, 20, 5]
+
+  block: # bug #12521
+    block:
+      type slice[T] = openArray[T]
+
+      # Proc using that alias
+      proc testing(sl: slice[int]): seq[int] =
+        for item in sl:
+          result.add item
+
+      let mySeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      doAssert testing(mySeq) == mySeq
+      doAssert testing(mySeq[2..^2]) == mySeq[2..^2]
+
+    block:
+      type slice = openArray[int]
+
+      # Proc using that alias
+      proc testing(sl: slice): seq[int] =
+        for item in sl:
+          result.add item
+
+      let mySeq = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      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/topenarrayrepr.nim b/tests/openarray/topenarrayrepr.nim
new file mode 100644
index 000000000..fc40d88c3
--- /dev/null
+++ b/tests/openarray/topenarrayrepr.nim
@@ -0,0 +1,13 @@
+discard """
+  output: "5 - [1]"
+"""
+type
+  TProc = proc (n: int, m: openArray[int64]) {.nimcall.}
+
+proc Foo(x: int, P: TProc) =
+  P(x, [ 1'i64 ])
+
+proc Bar(n: int, m: openArray[int64]) =
+  echo($n & " - " & repr(m))
+
+Foo(5, Bar) #OUT 5 - [1]
diff --git a/tests/topenlen.nim b/tests/openarray/topenlen.nim
index b9d7fbc2d..164241b85 100755..100644
--- a/tests/topenlen.nim
+++ b/tests/openarray/topenlen.nim
@@ -1,8 +1,11 @@
+discard """
+  output: "7"
+"""
 # Tests a special bug
 
 proc choose(b: openArray[string]): string = return b[0]
 
-proc p(a, b: openarray[string]): int =
+proc p(a, b: openArray[string]): int =
   result = a.len + b.len - 1
   for j in 0 .. a.len: inc(result)
   discard choose(a)
diff --git a/tests/openarray/tptrarrayderef.nim b/tests/openarray/tptrarrayderef.nim
new file mode 100644
index 000000000..1b7ef0df0
--- /dev/null
+++ b/tests/openarray/tptrarrayderef.nim
@@ -0,0 +1,84 @@
+discard """
+  output: '''[1, 2, 3, 4]
+3
+['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C']
+OK
+'''
+"""
+
+var
+  arr = [1,2,3]
+  arrp = addr(arr)
+  sss = @[4,5,6,7]
+  sssp = addr(sss)
+  ra = new(array[3, int])
+  raa = [11,12,13]
+
+#bug #3586
+proc mutate[T](arr:openArray[T], brr: openArray[T]) =
+  for i in 0..arr.len-1:
+    doAssert(arr[i] == brr[i])
+
+mutate(arr, arr)
+
+#bug #2240
+proc f(a: openArray[int], b: openArray[int]) =
+  for i in 0..a.len-1:
+   doAssert(a[i] == b[i])
+
+var a = [7,8,9]
+var p = addr a
+f(p[], a)
+f(sssp[], sss)
+
+ra[0] = 11
+ra[1] = 12
+ra[2] = 13
+f(ra[], raa)
+
+#bug #2240b
+proc fillBuffer(buf: var openArray[char]) =
+  for i in 0..buf.len-1:
+    buf[i] = chr(i)
+
+proc fillSeqBuffer(b: ref seq[char]) =
+  fillBuffer(b[])
+
+proc getFilledBuffer(sz: int): ref seq[char] =
+  let s : ref seq[char] = new(seq[char])
+  s[] = newSeq[char](sz)
+  fillBuffer(s[])
+  return s
+
+let aa = getFilledBuffer(3)
+for i in 0..aa[].len-1:
+  doAssert(aa[i] == chr(i))
+
+var
+  x = [1, 2, 3, 4]
+  y1 = block: (
+    a: (block:
+      echo x
+      cast[ptr array[2, int]](addr(x[0]))[]),
+    b: 3)
+  y2 = block:
+    echo y1.a[0] + y1.a[1]
+    cast[ptr array[4, int]](addr(x))[]
+doAssert y1 == ([1, 2], 3)
+doAssert y2 == [1, 2, 3, 4]
+
+template newOpenArray(x: var string, size: int): openArray[char] =
+  var z = 1
+  toOpenArray(x, z, size)
+
+template doSomethingAndCreate(x: var string): openArray[char] =
+  let size = 12
+  newOpenArray(x, size)
+
+proc sinkk(x: openArray[char]) =
+  echo x
+
+var xArrayDeref = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+sinkk doSomethingAndCreate(xArrayDeref)
+
+echo "OK"
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/options/tnimbasepattern.nim b/tests/options/tnimbasepattern.nim
new file mode 100644
index 000000000..1237af5c5
--- /dev/null
+++ b/tests/options/tnimbasepattern.nim
@@ -0,0 +1,26 @@
+discard """
+  cmd: "nim cpp --nimbasepattern:test.h --cincludes:./tests/options $file "
+  output:'''
+(a: 1)
+'''
+"""
+const header = """
+#pragma once
+#include "nimbase.h"
+struct Foo {
+  int a;
+};
+"""
+
+import os
+static:
+  const dir = "./tests/options/"
+  createDir(dir)
+  writeFile(dir / "test.h", header)
+
+type 
+  Foo {.importc.} = object
+    a: int32 = 1
+  
+
+echo $Foo()
\ No newline at end of file
diff --git a/tests/osproc/passenv.nim b/tests/osproc/passenv.nim
new file mode 100644
index 000000000..40b1c3f7c
--- /dev/null
+++ b/tests/osproc/passenv.nim
@@ -0,0 +1,32 @@
+discard """
+  file: "passenv.nim"
+  output: "123"
+  targets: "c cpp objc"
+"""
+
+import osproc, os, strtabs
+
+# Checks that the environment is passed correctly in startProcess
+# To do that launches a copy of itself with a new environment.
+
+if paramCount() == 0:
+  # Parent process
+
+  let env = newStringTable()
+  env["A"] = "1"
+  env["B"] = "2"
+  env["C"] = "3"
+
+  let p = startProcess(
+    getAppFilename(),
+    args = @["child"],
+    env = env,
+    options = {poStdErrToStdOut, poUsePath, poParentStreams}
+  )
+
+  discard p.waitForExit
+
+else:
+  # Child process
+  # should output "123"
+  echo getEnv("A") & getEnv("B") & getEnv("C")
diff --git a/tests/osproc/tclose.nim b/tests/osproc/tclose.nim
new file mode 100644
index 000000000..1c99237c7
--- /dev/null
+++ b/tests/osproc/tclose.nim
@@ -0,0 +1,24 @@
+discard """
+  exitcode: 0
+"""
+
+when defined(linux):
+  import osproc, os
+
+  proc countFds(): int =
+    result = 0
+    for i in walkDir("/proc/self/fd"):
+      result += 1
+
+  let initCount = countFds()
+
+  let p = osproc.startProcess("echo", options={poUsePath})
+  doAssert countFds() == initCount + 3
+  p.close
+  doAssert countFds() == initCount
+
+  let p1 = osproc.startProcess("echo", options={poUsePath})
+  discard p1.inputStream
+  doAssert countFds() == initCount + 3
+  p.close
+  doAssert countFds() == initCount
diff --git a/tests/osproc/texecps.nim b/tests/osproc/texecps.nim
new file mode 100644
index 000000000..b818fe8eb
--- /dev/null
+++ b/tests/osproc/texecps.nim
@@ -0,0 +1,30 @@
+discard """
+joinable: false
+"""
+
+import osproc, streams, strutils, os
+
+const NumberOfProcesses = 13
+
+var gResults {.threadvar.}: seq[string]
+
+proc execCb(idx: int, p: Process) =
+  let exitCode = p.peekExitCode
+  if exitCode < len(gResults):
+    gResults[exitCode] = p.outputStream.readAll.strip
+
+when true:
+  if paramCount() == 0:
+    gResults = newSeq[string](NumberOfProcesses)
+    var checks = newSeq[string](NumberOfProcesses)
+    var commands = newSeq[string](NumberOfProcesses)
+    for i in 0..len(commands) - 1:
+      commands[i] = getAppFileName() & " " & $i
+      checks[i] = $i
+    let cres = execProcesses(commands, options = {poStdErrToStdOut},
+                             afterRunEvent = execCb)
+    doAssert(cres == len(commands) - 1)
+    doAssert(gResults == checks)
+  else:
+    echo paramStr(1)
+    programResult = parseInt(paramStr(1))
diff --git a/tests/osproc/texitsignal.nim b/tests/osproc/texitsignal.nim
new file mode 100644
index 000000000..fbf5068ea
--- /dev/null
+++ b/tests/osproc/texitsignal.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''true
+true'''
+  targets: "c"
+"""
+
+import os, osproc
+when not defined(windows):
+  import posix
+
+# Checks that the environment is passed correctly in startProcess
+# To do that launches a copy of itself with a new environment.
+
+if paramCount() == 0:
+  # Parent process
+
+  let p = startProcess(
+    getAppFilename(),
+    args = @["child"],
+    options = {poStdErrToStdOut, poUsePath, poParentStreams}
+  )
+
+  echo p.running()
+
+  p.kill()
+
+  when defined(windows):
+    # windows kill happens using TerminateProcess(h, 0), so we should get a
+    # 0 here
+    echo p.waitForExit() == 0
+  elif defined(haiku):
+    # on Haiku, the program main thread receive SIGKILLTHR
+    echo p.waitForExit() == 128 + SIGKILLTHR
+  else:
+    # on posix (non-windows), kill sends SIGKILL
+    echo p.waitForExit() == 128 + SIGKILL
+
+else:
+  sleep(5000)  # should get killed before this
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/treadlines.nim b/tests/osproc/treadlines.nim
new file mode 100644
index 000000000..bb6a7f129
--- /dev/null
+++ b/tests/osproc/treadlines.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''
+Error: cannot open 'a.nim'
+Error: cannot open 'b.nim'
+'''
+  targets: "c"
+"""
+
+import osproc
+from std/os import getCurrentCompilerExe
+
+var ps: seq[Process] # compile & run 2 progs in parallel
+const nim = getCurrentCompilerExe()
+for prog in ["a", "b"]:
+  ps.add startProcess(nim, "",
+                      ["r", "--hint:Conf:off", "--hint:Processing:off", prog],
+                      options = {poUsePath, poDaemon, poStdErrToStdOut})
+
+for p in ps:
+  let (lines, exCode) = p.readLines
+  if exCode != 0:
+    for line in lines: echo line
+  p.close
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/osproc/tworkingdir.nim b/tests/osproc/tworkingdir.nim
new file mode 100644
index 000000000..3a3c1b6ab
--- /dev/null
+++ b/tests/osproc/tworkingdir.nim
@@ -0,0 +1,21 @@
+discard """
+  output: ""
+"""
+
+import osproc, os
+when defined(windows):
+  # Windows don't have this issue, so we won't test it.
+  discard
+else:
+  let dir1 = getCurrentDir()
+  var process: Process
+  when defined(android):
+    process = startProcess("/system/bin/env", "/system/bin", ["true"])
+  elif defined(haiku):
+    process = startProcess("/bin/env", "/bin", ["true"])
+  else:
+    process = startProcess("/usr/bin/env", "/usr/bin", ["true"])
+  let dir2 = getCurrentDir()
+  discard process.waitForExit()
+  process.close()
+  doAssert(dir1 == dir2, $dir1 & " != " & $dir2)
diff --git a/tests/overflow/tdistinct_range.nim b/tests/overflow/tdistinct_range.nim
new file mode 100644
index 000000000..f53515d45
--- /dev/null
+++ b/tests/overflow/tdistinct_range.nim
@@ -0,0 +1,6 @@
+discard """
+  outputsub: "Error: unhandled exception: over- or underflow [OverflowDefect]"
+  exitcode: "1"
+"""
+var x: distinct range[0..5]
+dec(x)
\ No newline at end of file
diff --git a/tests/overflow/toverflow.nim b/tests/overflow/toverflow.nim
new file mode 100644
index 000000000..972f929c6
--- /dev/null
+++ b/tests/overflow/toverflow.nim
@@ -0,0 +1,82 @@
+discard """
+  output: "ok"
+  matrix: "--overflowChecks:off; --overflowChecks:off --b:js"
+"""
+# Tests nim's ability to detect overflows
+
+{.push overflowChecks: on.}
+
+var
+  a = high(int)
+  b = -2
+  overflowDetected = false
+
+try:
+  echo(b - a)
+except OverflowDefect:
+  overflowDetected = true
+
+{.pop.} # overflow check
+
+doAssert(overflowDetected)
+
+block: # Overflow checks in a proc
+  var
+    a = high(int)
+    b = -2
+    overflowDetected = false
+
+  {.push overflowChecks: on.}
+  proc foo() =
+    let c = b - a
+  {.pop.}
+
+  try:
+    foo()
+  except OverflowDefect:
+    overflowDetected = true
+
+  doAssert(overflowDetected)
+
+block: # Overflow checks in a forward declared proc
+  var
+    a = high(int)
+    b = -2
+    overflowDetected = false
+
+  proc foo()
+
+  {.push overflowChecks: on.}
+  proc foo() =
+    let c = b - a
+  {.pop.}
+
+  try:
+    foo()
+  except OverflowDefect:
+    overflowDetected = true
+
+  doAssert(overflowDetected)
+
+block: # Overflow checks doesn't affect fwd declaration
+  var
+    a = high(int)
+    b = -2
+    overflowDetected = false
+
+  {.push overflowChecks: on.}
+  proc foo()
+  {.pop.}
+
+  proc foo() =
+    let c = b - a
+
+  try:
+    foo()
+  except OverflowDefect:
+    overflowDetected = true
+
+  doAssert(not overflowDetected)
+
+
+echo "ok"
diff --git a/tests/overflow/toverflow2.nim b/tests/overflow/toverflow2.nim
new file mode 100644
index 000000000..c06b35c6d
--- /dev/null
+++ b/tests/overflow/toverflow2.nim
@@ -0,0 +1,7 @@
+discard """
+  outputsub: "Error: unhandled exception: over- or underflow [OverflowDefect]"
+  exitcode: "1"
+"""
+var a : int32 = 2147483647
+var b : int32 = 2147483647
+var c = a + b
diff --git a/tests/overflow/toverflow_reorder.nim b/tests/overflow/toverflow_reorder.nim
new file mode 100644
index 000000000..fcf7b0c82
--- /dev/null
+++ b/tests/overflow/toverflow_reorder.nim
@@ -0,0 +1,84 @@
+{.experimental: "codeReordering".}
+
+discard """
+  output: "ok"
+  cmd: "nim $target --overflowChecks:off $options $file"
+"""
+# Tests nim's ability to detect overflows
+
+{.push overflowChecks: on.}
+
+var
+  a = high(int)
+  b = -2
+  overflowDetected = false
+
+try:
+  echo b - a
+except OverflowDefect:
+  overflowDetected = true
+
+{.pop.} # overflow check
+
+doAssert(overflowDetected)
+
+block: # Overflow checks in a proc
+  var
+    a = high(int)
+    b = -2
+    overflowDetected = false
+
+  {.push overflowChecks: on.}
+  proc foo() =
+    let c = b - a
+  {.pop.}
+
+  try:
+    foo()
+  except OverflowDefect:
+    overflowDetected = true
+
+  doAssert(overflowDetected)
+
+block: # Overflow checks in a forward declared proc
+  var
+    a = high(int)
+    b = -2
+    overflowDetected = false
+
+  proc foo()
+
+  {.push overflowChecks: on.}
+  proc foo() =
+    let c = b - a
+  {.pop.}
+
+  try:
+    foo()
+  except OverflowDefect:
+    overflowDetected = true
+
+  doAssert(overflowDetected)
+
+block: # Overflow checks doesn't affect fwd declaration
+  var
+    a = high(int)
+    b = -2
+    overflowDetected = false
+
+  {.push overflowChecks: on.}
+  proc foo()
+  {.pop.}
+
+  proc foo() =
+    let c = b - a
+
+  try:
+    foo()
+  except OverflowDefect:
+    overflowDetected = true
+
+  doAssert(not overflowDetected)
+
+
+echo "ok"
diff --git a/tests/tovfint.nim b/tests/overflow/tovfint.nim
index 91eda8d0b..5c440a540 100755..100644
--- a/tests/tovfint.nim
+++ b/tests/overflow/tovfint.nim
@@ -1,17 +1,20 @@
-# this tests the new overflow literals

-

-var

-  i: int

-i = int(0xffffffff)

-when defined(cpu64):

-  if i == 4294967295:

-    write(stdout, "works!\n")

-  else:

-    write(stdout, "broken!\n")

-else:

-  if i == -1:

-    write(stdout, "works!\n")

-  else:

-    write(stdout, "broken!\n")

-

-#OUT works!

+discard """
+  output: "works!"
+"""
+# this tests the new overflow literals
+
+var
+  i: int
+i = int(0xffffffff'i32)
+when defined(cpu64):
+  if i == -1:
+    write(stdout, "works!\n")
+  else:
+    write(stdout, "broken!\n")
+else:
+  if i == -1:
+    write(stdout, "works!\n")
+  else:
+    write(stdout, "broken!\n")
+
+#OUT works!
diff --git a/tests/overflow/trangechecks.nim b/tests/overflow/trangechecks.nim
new file mode 100644
index 000000000..e48b1272b
--- /dev/null
+++ b/tests/overflow/trangechecks.nim
@@ -0,0 +1,48 @@
+discard """
+  output: '''10
+10
+1
+1
+true'''
+"""
+
+# bug #1344
+
+var expected: int
+var x: range[1..10] = 10
+
+try:
+  x += 1
+  echo x
+except OverflowDefect, RangeDefect:
+  expected += 1
+  echo x
+
+try:
+  inc x
+  echo x
+except OverflowDefect, RangeDefect:
+  expected += 1
+  echo x
+
+x = 1
+try:
+  x -= 1
+  echo x
+except OverflowDefect, RangeDefect:
+  expected += 1
+  echo x
+
+try:
+  dec x
+  echo x
+except OverflowDefect, RangeDefect:
+  expected += 1
+  echo x
+
+echo expected == 4
+
+# bug #13698
+var
+  x45 = "hello".cstring
+  p = x45.len.int32
diff --git a/tests/overflow/twronginference.nim b/tests/overflow/twronginference.nim
new file mode 100644
index 000000000..34a982976
--- /dev/null
+++ b/tests/overflow/twronginference.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "cannot convert 256 to int8"
+  line: 9
+"""
+
+# issue #23177
+
+var x: int8
+x = 256
+echo x # 0
diff --git a/tests/overload/importA.nim b/tests/overload/importA.nim
new file mode 100644
index 000000000..f045d11b4
--- /dev/null
+++ b/tests/overload/importA.nim
@@ -0,0 +1,5 @@
+type
+  Field* = object
+    elemSize*: int
+
+template `+`*(x: untyped, y: Field): untyped = x
diff --git a/tests/overload/importB.nim b/tests/overload/importB.nim
new file mode 100644
index 000000000..2dc3adf7a
--- /dev/null
+++ b/tests/overload/importB.nim
@@ -0,0 +1,15 @@
+type
+  Foo*[T] = object
+    v*: T
+
+template `+`*(x: Foo, y: Foo): untyped = x
+
+template newvar*(r: untyped): untyped {.dirty.} =
+  var r: float
+
+template t1*(x: Foo): untyped =
+  newvar(y1)
+  x
+template t2*(x: Foo): untyped =
+  newvar(y2)
+  x
diff --git a/tests/overload/issue22142/tfail_implicit_ambiguous.nim b/tests/overload/issue22142/tfail_implicit_ambiguous.nim
new file mode 100644
index 000000000..2586e0877
--- /dev/null
+++ b/tests/overload/issue22142/tfail_implicit_ambiguous.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "ambiguous call"
+"""
+type
+  A[T] = object
+  C = object
+
+proc test[T: A](param: T): bool = false
+proc test(param: A): bool = true
+doAssert test(A[C]()) == true  # previously would pass
diff --git a/tests/overload/issue22142/tfail_nested_pointers.nim b/tests/overload/issue22142/tfail_nested_pointers.nim
new file mode 100644
index 000000000..1603d98cb
--- /dev/null
+++ b/tests/overload/issue22142/tfail_nested_pointers.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "ambiguous call"
+"""
+
+type
+  A[T] = object
+  C = object
+    x:int
+proc p[T: A[ptr]](x:ptr[T]):bool = false
+proc p(x: ptr[A[ptr]]):bool = true
+var a: A[ptr[C]]
+doAssert p(a.addr) == true
diff --git a/tests/overload/issue22142/tfail_object_is_generic.nim b/tests/overload/issue22142/tfail_object_is_generic.nim
new file mode 100644
index 000000000..b46795bd5
--- /dev/null
+++ b/tests/overload/issue22142/tfail_object_is_generic.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "ambiguous call"
+"""
+
+#[
+As of the time of writing `object` needs some special
+treament in order to be considered "generic" in the right
+context when used implicitly
+]#
+
+type
+  C = object
+
+proc test[T: object](param: T): bool = false
+proc test(param: object): bool = true  
+doAssert test(C()) == true  # previously would pass
diff --git a/tests/overload/issue22142/tfail_typeclass_var_invar.nim b/tests/overload/issue22142/tfail_typeclass_var_invar.nim
new file mode 100644
index 000000000..07db65fef
--- /dev/null
+++ b/tests/overload/issue22142/tfail_typeclass_var_invar.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "ambiguous call"
+"""
+
+type C = object
+proc test[T: ptr](param: var T): bool = false
+proc test(param: var ptr): bool = true
+var d: ptr[C]
+doAssert test(d) == true  # previously would pass
diff --git a/tests/overload/issue22142/tissue22142_shouldpass.nim b/tests/overload/issue22142/tissue22142_shouldpass.nim
new file mode 100644
index 000000000..90d4efe51
--- /dev/null
+++ b/tests/overload/issue22142/tissue22142_shouldpass.nim
@@ -0,0 +1,68 @@
+type
+  A[T] = object of RootObj
+  B[T] = object
+  C = object
+    x:int
+
+# change (previously true)
+block:
+  proc test[J;H: A[J];T: B[H]](param: T): bool = false
+  proc test[T](param: B[T]): bool = true
+  doAssert test(B[A[int]]()) == false
+block:  # object is more specific then `T`
+  proc p[H:object;T:ptr[H]](param:T):bool = false
+  proc p[T](param:ptr[T]):bool= true
+  var l: ptr[C]
+  doAssert p(l) == false
+block:
+  proc p[T:A[object]](param:T):bool = false
+  proc p[T](param: A[T]):bool= true
+  doAssert p(A[C]()) == false
+block:
+  proc test[H;T: A[H]](param: T): bool = false
+  proc test(param: A): bool = true
+  doAssert test(A[C]()) == false
+
+# change (previously ambiguous)
+block:
+  proc p[T](a: A[T]): bool = false
+  proc p[T: object](a: T): bool = true
+  doAssert p(A[int]()) == false
+block:  # A is more specific than `object`
+  proc test[T: A](param: T): bool = false
+  proc test[T: object](param: T): bool = true
+  doAssert test(A[int]()) == false
+block:
+  proc test[T: A](param: T): bool = false
+  proc test(param: object): bool = true
+  doAssert test(A[int]()) == false
+block:
+  proc test[H;T: A[H]](param: T): bool = false
+  proc test(param: object): bool = true
+  doAssert test(A[C]()) == false
+block:
+  proc test[H;T: A[B[H]]](param: T): bool = false
+  proc test[T: object](param: T): bool = true
+  doAssert test(A[B[int]]()) == false
+block:
+  #[
+  This was referenced in the nim compiler source (`sumGeneric`) as a case
+  that was supposed to not be ambiguous, yet it was
+  ]#
+  proc test[J;H:A[J]; T: A[H]](param: T): bool = false
+  proc test[H;T: A[H]](param: T): bool = true
+  doAssert test(A[A[C]]()) == false
+block:
+  proc test[J;T:A[J]](param: A[T]): bool = false
+  proc test[T](param: A[T]): bool = true
+  doAssert test(A[A[C]]()) == false
+block:
+  proc test[T](param: A[T]): bool = false
+  proc test[T: object](param: A[T]): bool = true
+  doAssert test(A[C]()) == true
+
+
+block: #anti-regression (object is more specific then `T`)
+  proc test[J;T:A[J]](param: A[T]): bool = false
+  proc test(param: A[A[object]]): bool = true
+  doAssert test(A[A[C]]()) == true
\ No newline at end of file
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/t23249.nim b/tests/overload/t23249.nim
new file mode 100644
index 000000000..f4657833b
--- /dev/null
+++ b/tests/overload/t23249.nim
@@ -0,0 +1,17 @@
+# issue #23249
+
+type Control* = object
+proc onAction*(c: Control, handler: proc(e: int) {.gcsafe.}) = discard
+proc onAction*(c: Control, handler: proc() {.gcsafe.}) = discard
+
+template setControlHandlerBlock(c: Control, p: untyped, a: untyped) =
+    when compiles(c.p(nil)):
+        c.p() do() {.gcsafe.}: a
+    else:
+        c.p = proc() {.gcsafe.} =
+            a
+
+proc mkLayout() =
+  var b: Control
+  setControlHandlerBlock(b, onAction):
+    echo "hi"
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/t7416.nim b/tests/overload/t7416.nim
new file mode 100644
index 000000000..4a9b2e7cb
--- /dev/null
+++ b/tests/overload/t7416.nim
@@ -0,0 +1,9 @@
+type
+  Foo[T] = object
+  IntFoo = Foo[int]
+
+proc bar(b: object|tuple) = discard
+proc bar(b: IntFoo) = discard
+
+var f: IntFoo
+bar(f)
\ No newline at end of file
diff --git a/tests/overload/t8829.nim b/tests/overload/t8829.nim
new file mode 100644
index 000000000..85d87f136
--- /dev/null
+++ b/tests/overload/t8829.nim
@@ -0,0 +1,18 @@
+block:
+  let txt = "Hello World"
+
+  template `[]`[T](p: ptr T, span: Slice[int]): untyped =
+    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]"
+
+
+block:
+  let txt = "Hello World"
+
+  template `[]`[T](p: ptr T, span: Slice[int]): untyped =
+    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/tconverter_to_string.nim b/tests/overload/tconverter_to_string.nim
new file mode 100644
index 000000000..1960372d8
--- /dev/null
+++ b/tests/overload/tconverter_to_string.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''123
+c is not nil'''
+"""
+
+# bug #9149
+
+type
+  Container = ref object
+    data: int
+
+converter containerToString*(x: Container): string = $x.data
+
+var c = Container(data: 123)
+var str = string c
+echo str
+
+if c == nil: # this line can compile on v0.18, but not on 0.19
+  echo "c is nil"
+
+if not c.isNil:
+  echo "c is not nil"
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/tissue966.nim b/tests/overload/tissue966.nim
new file mode 100644
index 000000000..d0a723875
--- /dev/null
+++ b/tests/overload/tissue966.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got <PTest>"
+"""
+
+type
+  PTest = ref object
+
+proc test(x: PTest, y: int) = discard
+
+var buf: PTest
+buf.test()
+
diff --git a/tests/overload/tnamedparamoverloading.nim b/tests/overload/tnamedparamoverloading.nim
new file mode 100644
index 000000000..a7c37ba52
--- /dev/null
+++ b/tests/overload/tnamedparamoverloading.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''
+Using x: 2
+Using y: 2
+'''
+"""
+
+proc foo(x: int) =
+  echo "Using x: ", x
+proc foo(y: int) =
+  echo "Using y: ", y
+
+foo(x = 2)
+foo(y = 2)
\ No newline at end of file
diff --git a/tests/overload/tor_isnt_better.nim b/tests/overload/tor_isnt_better.nim
new file mode 100644
index 000000000..bee125386
--- /dev/null
+++ b/tests/overload/tor_isnt_better.nim
@@ -0,0 +1,41 @@
+type
+  D[T] = object
+  E[T] = object
+
+block: # PR #22261
+  proc d(x: D):bool= false
+  proc d(x: int | D[SomeInteger]):bool= true
+  doAssert d(D[5]()) == false
+
+block: # bug #8568
+#[
+  Since PR #22261 and amendment has been made. Since D is a subset of D | E but
+  not the other way around `checkGeneric` should favor proc g(a: D) instead
+  of asserting ambiguity
+]#
+  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/toverl.nim b/tests/overload/toverl.nim
index 94f251cac..64257be77 100755..100644
--- a/tests/toverl.nim
+++ b/tests/overload/toverl.nim
@@ -1,6 +1,11 @@
-# Test for overloading

-

-type

-  TNone {.exportc: "_NONE", final.} = object

-

-proc TNone(a, b: int) = nil #ERROR_MSG attempt to redefine 'TNone'

+discard """
+  errormsg: "redefinition of \'TNone\'"
+  file: "toverl.nim"
+  line: 11
+"""
+# Test for overloading
+
+type
+  TNone {.exportc: "_NONE", final.} = object
+
+proc TNone(a, b: int) = nil #ERROR_MSG attempt to redefine 'TNone'
diff --git a/tests/overload/toverl4.nim b/tests/overload/toverl4.nim
new file mode 100644
index 000000000..21cedaa96
--- /dev/null
+++ b/tests/overload/toverl4.nim
@@ -0,0 +1,101 @@
+discard """
+  output: '''true
+5.0'''
+"""
+
+#bug #592
+
+type
+  ElementKind = enum inner, leaf
+  TElement[TKey, TData] = object
+    case kind: ElementKind
+    of inner:
+      key: TKey
+      left, right: ref TElement[Tkey, TData]
+    of leaf:
+      data: TData
+  PElement[TKey, TData] = ref TElement[TKey, TData]
+
+proc newElement[Tkey, TData](other: PElement[TKey, TData]): PElement[Tkey, TData] =
+  case other.kind:
+  of inner:
+    PElement[TKey, TData](kind: ElementKind.inner, key: other.key, left: other.left, right: other.right)
+  of leaf:
+    PElement[TKey, TData](kind: ElementKind.leaf, data: other.data)
+
+proc newElement[TKey, TData](key: TKey, left: PElement[TKey, TData] = nil, right: PElement[TKey, TData] = nil) : PElement[TKey, TData] =
+  PElement[TKey, TData](kind: ElementKind.inner, key: key, left: left, right: right)
+
+proc newElement[Tkey, TData](key: Tkey, data: TData) : PElement[Tkey, TData] =
+  PElement[TKey, TData](kind: ElementKind.leaf, data: data)
+
+proc find*[TKey, TData](root: PElement[TKey, TData], key: TKey): TData {.raises: [KeyError].} =
+  if root.left == nil:
+    raise newException(KeyError, "key does not exist: " & key)
+
+  var tmp_element = addr(root)
+
+  while tmp_element.kind == inner and tmp_element.right != nil:
+    tmp_element = if tmp_element.key > key:
+                    addr(tmp_element.left)
+                  else:
+                    addr(tmp_element.right)
+
+  if tmp_element.key == key:
+    return tmp_element.left.data
+  else:
+    raise newException(KeyError, "key does not exist: " & key)
+
+proc add*[TKey, TData](root: var PElement[TKey, TData], key: TKey, data: TData) : bool =
+  if root.left == nil:
+    root.key = key
+    root.left = newElement[TKey, TData](key, data)
+    return true
+
+  var tmp_element = addr(root)
+
+  while tmp_element.kind == ElementKind.inner and tmp_element.right != nil:
+    tmp_element = if tmp_element.key > key:
+                    addr(tmp_element.left)
+                  else:
+                    addr(tmp_element.right)
+
+  if tmp_element.key == key:
+    return false
+
+  var old_element = newElement[TKey, TData](tmp_element[])
+  var new_element = newElement[TKey, TData](key, data)
+
+  tmp_element[] = if tmp_element.key < key:
+                    newElement(key, old_element, new_element)
+                  else:
+                    newElement(tmp_element.key, new_element, old_element)
+
+  return true
+
+var tree = PElement[int, int](kind: ElementKind.inner, key: 0, left: nil, right: nil)
+let result = add(tree, 1, 1)
+echo(result)
+
+# bug #3748
+type
+  Foo = object
+    bar: int
+
+proc bar(cur: Foo, val: int, s:seq[string]) =
+  discard cur.bar
+
+proc does_fail(): Foo =
+  let a = @["a"]
+  result.bar(5, a)
+
+doAssert does_fail().bar == 0
+
+# bug #20645
+
+type Zzz[Gen] = object
+
+proc testZ(z: Zzz) =
+  echo z.Gen(5)
+
+testZ(Zzz[float]())
diff --git a/tests/overload/toverload_issues.nim b/tests/overload/toverload_issues.nim
new file mode 100644
index 000000000..26bf89091
--- /dev/null
+++ b/tests/overload/toverload_issues.nim
@@ -0,0 +1,200 @@
+discard """
+  output: '''
+Version 2 was called.
+This has the highest precedence.
+This has the second-highest precedence.
+This has the lowest precedence.
+baseobj ==
+true
+even better! ==
+true
+done extraI=0
+test 0 complete, loops=0
+done extraI=1
+test 1.0 complete, loops=1
+done extraI=0
+done extraI passed 0
+test no extra complete, loops=2
+1
+'''
+"""
+
+
+# issue 4675
+import importA  # comment this out to make it work
+import importB
+
+var x: Foo[float]
+var y: Foo[float]
+let r = t1(x) + t2(y)
+
+
+
+# Bug: https://github.com/nim-lang/Nim/issues/4475
+# Fix: https://github.com/nim-lang/Nim/pull/4477
+proc test(x: varargs[string], y: int) = discard
+test(y = 1)
+
+
+
+# bug #2220
+when true:
+  type A[T] = object
+  type B = A[int]
+
+  proc q[X](x: X) =
+    echo "Version 1 was called."
+
+  proc q(x: B) =
+    echo "Version 2 was called."
+
+  q(B()) # This call reported as ambiguous.
+
+
+
+# bug #2219
+template testPred(a: untyped) =
+  block:
+    type A = object of RootObj
+    type B = object of A
+    type SomeA = A|A # A hack to make "A" a typeclass.
+
+    when a >= 3:
+      proc p[X: A](x: X) =
+        echo "This has the highest precedence."
+    when a == 2:
+      proc p[X: SomeA](x: X) =
+        echo "This has the second-highest precedence."
+    when a >= 1:
+      proc p[X](x: X) =
+        echo "This has the lowest precedence."
+
+    p(B())
+
+testPred(3)
+testPred(2)
+testPred(1)
+
+
+
+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)
+
+
+
+# bug #2481
+import math
+
+template test(loopCount: int, extraI: int, testBody: untyped): typed =
+  block:
+    for i in 0..loopCount-1:
+      testBody
+    echo "done extraI=", extraI
+
+template test(loopCount: int, extraF: float, testBody: untyped): typed =
+  block:
+    test(loopCount, round(extraF).int, testBody)
+
+template test(loopCount: int, testBody: untyped): typed =
+  block:
+    test(loopCount, 0, testBody)
+    echo "done extraI passed 0"
+
+var
+  loops = 0
+
+test 0, 0:
+  loops += 1
+echo "test 0 complete, loops=", loops
+
+test 1, 1.0:
+  loops += 1
+echo "test 1.0 complete, loops=", loops
+
+when true:
+  # when true we get the following compile time error:
+  #   b.nim(35, 6) Error: expression 'loops += 1' has no type (or is ambiguous)
+  loops = 0
+  test 2:
+    loops += 1
+  echo "test no extra complete, loops=", loops
+
+# bug #2229
+type
+  Type1 = object
+    id: int
+  Type2 = object
+    id: int
+
+proc init(self: var Type1, a: int, b: ref Type2) =
+  echo "1"
+
+proc init(self: var Type2, a: int) =
+  echo """
+    Works when this proc commented out
+    Otherwise error:
+    test.nim(14, 4) Error: ambiguous call; both test.init(self: var Type1, a: int, b: ref Type2) and test.init(self: var Type1, a: int, b: ref Type2) match for: (Type1, int literal(1), ref Type2)
+  """
+
+var aa: Type1
+init(aa, 1, (
+    var bb = new(Type2);
+    bb
+))
+
+
+
+# bug #4545
+type
+  SomeObject = object
+    a: int
+  AbstractObject = object
+    objet: ptr SomeObject
+
+proc convert(this: var SomeObject): AbstractObject =
+  AbstractObject(objet: this.addr)
+
+proc varargProc(args: varargs[AbstractObject, convert]): int =
+  for arg in args:
+    result += arg.objet.a
+
+var obj = SomeObject(a: 17)
+discard varargProc(obj)
+
+
+
+# bug #11239
+
+type MySeq*[T] = object
+
+proc foo(a: seq[int]): string = "foo: seq[int]"
+proc foo[T](a: seq[T]): string = "foo: seq[T]"
+proc foo(a: MySeq[int]): string = "foo: MySeq[int]"
+proc foo[T](a: MySeq[T]): string = "foo: MySeq[T]"
+
+doAssert foo(@[1,2,3]) == "foo: seq[int]"
+doAssert foo(@["WER"]) == "foo: seq[T]"
+doAssert foo(MySeq[int]()) == "foo: MySeq[int]"
+doAssert foo(MySeq[string]()) == "foo: MySeq[T]"
diff --git a/tests/overload/toverload_various.nim b/tests/overload/toverload_various.nim
new file mode 100644
index 000000000..d195a069d
--- /dev/null
+++ b/tests/overload/toverload_various.nim
@@ -0,0 +1,568 @@
+discard """
+  output: '''
+true012innertrue
+m1
+tup1
+another number: 123
+yay
+helloa 1 b 2 x @[3, 4, 5] y 6 z 7
+yay
+12
+ref ref T ptr S
+dynamic: let
+dynamic: var
+static: const
+static: literal
+static: constant folding
+static: static string
+foo1
+1
+'''
+"""
+
+
+import strutils, sequtils
+
+
+block overl2:
+  # Test new overloading resolution rules
+  proc toverl2(x: int): string = return $x
+  proc toverl2(x: bool): string = return $x
+
+  iterator toverl2(x: int): int =
+    var res = 0
+    while res < x:
+      yield res
+      inc(res)
+
+  var
+    pp: proc (x: bool): string {.nimcall.} = toverl2
+
+  stdout.write(pp(true))
+
+  for x in toverl2(3):
+    stdout.write(toverl2(x))
+
+  block:
+    proc toverl2(x: int): string = return "inner"
+    stdout.write(toverl2(5))
+    stdout.write(true)
+
+  stdout.write("\n")
+  #OUT true012innertrue
+
+
+
+block overl3:
+  # Tests more specific generic match:
+  proc m[T](x: T) = echo "m2"
+  proc m[T](x: var ref T) = echo "m1"
+  proc tup[S, T](x: tuple[a: S, b: ref T]) = echo "tup1"
+  proc tup[S, T](x: tuple[a: S, b: T]) = echo "tup2"
+
+  var
+    obj: ref int
+    tu: tuple[a: int, b: ref bool]
+
+  m(obj)
+  tup(tu)
+
+
+
+block toverprc:
+  # Test overloading of procs when used as function pointers
+  proc parseInt(x: float): int {.noSideEffect.} = discard
+  proc parseInt(x: bool): int {.noSideEffect.} = discard
+  proc parseInt(x: float32): int {.noSideEffect.} = discard
+  proc parseInt(x: int8): int {.noSideEffect.} = discard
+  proc parseInt(x: File): int {.noSideEffect.} = discard
+  proc parseInt(x: char): int {.noSideEffect.} = discard
+  proc parseInt(x: int16): int {.noSideEffect.} = discard
+
+  proc parseInt[T](x: T): int = echo x; 34
+
+  type
+    TParseInt = proc (x: string): int {.noSideEffect.}
+
+  var
+    q = TParseInt(parseInt)
+    p: TParseInt = parseInt
+
+  proc takeParseInt(x: proc (y: string): int {.noSideEffect.}): int =
+    result = x("123")
+
+  if false:
+    echo "Give a list of numbers (separated by spaces): "
+    var x = stdin.readline.split.map(parseInt).max
+    echo x, " is the maximum!"
+  echo "another number: ", takeParseInt(parseInt)
+
+
+  type
+    TFoo[a,b] = object
+      lorem: a
+      ipsum: b
+
+  proc bar[a,b](f: TFoo[a,b], x: a) = echo(x, " ", f.lorem, f.ipsum)
+  proc bar[a,b](f: TFoo[a,b], x: b) = echo(x, " ", f.lorem, f.ipsum)
+
+  discard parseInt[string]("yay")
+
+
+
+block toverwr:
+  # Test the overloading resolution in connection with a qualifier
+  proc write(t: File, s: string) =
+    discard # a nop
+  system.write(stdout, "hello")
+  #OUT hello
+
+
+
+block tparams_after_varargs:
+  proc test(a, b: int, x: varargs[int]; y, z: int) =
+    echo "a ", a, " b ", b, " x ", @x, " y ", y, " z ", z
+
+  test 1, 2, 3, 4, 5, 6, 7
+
+  # XXX maybe this should also work with ``varargs[untyped]``
+  template takesBlockA(a, b: untyped; x: varargs[typed]; blck: untyped): untyped =
+    blck
+    echo a, b
+
+  takesBlockA 1, 2, "some", 0.90, "random stuff":
+    echo "yay"
+
+
+
+block tprefer_specialized_generic:
+  proc foo[T](x: T) =
+    echo "only T"
+
+  proc foo[T](x: ref T) =
+    echo "ref T"
+
+  proc foo[T, S](x: ref ref T; y: ptr S) =
+    echo "ref ref T ptr S"
+
+  proc foo[T, S](x: ref T; y: ptr S) =
+    echo "ref T ptr S"
+
+  proc foo[T](x: ref T; default = 0) =
+    echo "ref T; default"
+
+  var x: ref ref int
+  var y: ptr ptr int
+  foo(x, y)
+
+
+
+block tstaticoverload:
+  proc foo(s: string) =
+    echo "dynamic: ", s
+
+  proc foo(s: static[string]) =
+    echo "static: ", s
+
+  let l = "let"
+  var v = "var"
+  const c = "const"
+
+  type staticString = static[string]
+
+  foo(l)
+  foo(v)
+  foo(c)
+  foo("literal")
+  foo("constant" & " " & "folding")
+  foo(staticString("static string"))
+
+# bug #8568 (2)
+
+proc goo(a: int): string = "int"
+proc goo(a: static[int]): string = "static int"
+proc goo(a: var int): string = "var int"
+proc goo[T: int](a: T): string = "T: int"
+#proc goo[T](a: T): string = "nur T"
+
+const tmp1 = 1
+let tmp2 = 1
+var tmp3 = 1
+
+doAssert goo(1) == "static int"
+doAssert goo(tmp1) == "static int"
+doAssert goo(tmp2) == "int"
+doAssert goo(tmp3) == "var int"
+
+doAssert goo[int](1) == "T: int"
+
+doAssert goo[int](tmp1) == "T: int"
+doAssert goo[int](tmp2) == "T: int"
+doAssert goo[int](tmp3) == "T: int"
+
+# bug #6076
+
+type A[T] = object
+
+proc regr(a: A[void]) = echo "foo1"
+proc regr[T](a: A[T]) = doAssert(false)
+
+regr(A[void]())
+
+
+type Foo[T] = object
+
+proc regr[T](p: Foo[T]): seq[T] =
+  discard
+
+proc regr(p: Foo[void]): seq[int] =
+  discard
+
+
+discard regr(Foo[int]())
+discard regr(Foo[void]())
+
+
+type
+  Sha2Context*[bits: static[int],
+               bsize: static[int],
+               T: uint32|uint64] = object
+    count: array[2, T]
+    state: array[8, T]
+    buffer: array[bsize, byte]
+
+  sha224* = Sha2Context[224, 64, uint32]
+  sha256* = Sha2Context[256, 64, uint32]
+  sha384* = Sha2Context[384, 128, uint64]
+  sha512* = Sha2Context[512, 128, uint64]
+  sha512_224* = Sha2Context[224, 128, uint64]
+  sha512_256* = Sha2Context[256, 128, uint64]
+
+type
+  RipemdContext*[bits: static[int]] = object
+    count: array[2, uint32]
+    state: array[bits div 32, uint32]
+    buffer: array[64, byte]
+
+  ripemd128* = RipemdContext[128]
+  ripemd160* = RipemdContext[160]
+  ripemd256* = RipemdContext[256]
+  ripemd320* = RipemdContext[320]
+
+const
+  MaxHmacBlockSize = 256
+
+type
+  HMAC*[HashType] = object
+    mdctx: HashType
+    opadctx: HashType
+
+template sizeBlock*(h: HMAC[Sha2Context]): uint = 1u
+template sizeBlock*(h: HMAC[RipemdContext]): uint = 0u
+
+proc init*[T](hmctx: HMAC[T], key: ptr byte, ulen: uint) =
+  const sizeBlock = hmctx.sizeBlock
+  echo sizeBlock
+
+proc hmac*[A, B](HashType: typedesc, key: openArray[A],
+                 data: openArray[B]) =
+  var ctx: HMAC[HashType]
+  ctx.init(nil, 0)
+
+sha256.hmac("", "")
+
+
+
+# nested generic types
+block:
+  type
+    Foo[T] = object
+      f: T
+    Bar[T] = object
+      b: T
+    Baz[T] = object
+      z: T
+    FooBar[T] = Foo[Bar[T]]
+    FooBarBaz[T] = FooBar[Baz[T]]
+    #Int = int
+    Int = SomeInteger
+    FooBarBazInt = FooBarBaz[Int]
+    FooBarBazX = FooBarBaz[int]
+
+  proc p00(x: Foo): auto = x.f
+  proc p01[T](x: Foo[T]): auto = x.f
+  proc p02[T:Foo](x: T): auto = x.f
+
+  proc p10(x: FooBar): auto = x.f
+  proc p11[T](x: FooBar[T]): auto = x.f
+  proc p12[T:FooBar](x: T): auto = x.f
+  proc p13(x: Foo[Bar]): auto = x.f
+  proc p14[T](x: Foo[Bar[T]]): auto = x.f
+  proc p15[T:Bar](x: Foo[T]): auto = x.f
+  proc p16[T:Foo[Bar]](x: T): auto = x.f
+
+  proc p20(x: FooBarBaz): auto = x.f
+  proc p21[T](x: FooBarBaz[T]): auto = x.f
+  proc p22[T:FooBarBaz](x: T): auto = x.f
+  proc p23(x: FooBar[Baz]): auto = x.f
+  proc p24[T](x: FooBar[Baz[T]]): auto = x.f
+  proc p25[T:Baz](x: FooBar[T]): auto = x.f
+  proc p26[T:FooBar[Baz]](x: T): auto = x.f
+  proc p27(x: Foo[Bar[Baz]]): auto = x.f
+  proc p28[T](x: Foo[Bar[Baz[T]]]): auto = x.f
+  proc p29[T:Baz](x: Foo[Bar[T]]): auto = x.f
+  proc p2A[T:Bar[Baz]](x: Foo[T]): auto = x.f
+  proc p2B[T:Foo[Bar[Baz]]](x: T): auto = x.f
+
+  proc p30(x: FooBarBazInt): auto = x.f
+  proc p31[T:FooBarBazInt](x: T): auto = x.f
+  proc p32(x: FooBarBaz[Int]): auto = x.f
+  proc p33[T:Int](x: FooBarBaz[T]): auto = x.f
+  proc p34[T:FooBarBaz[Int]](x: T): auto = x.f
+  proc p35(x: FooBar[Baz[Int]]): auto = x.f
+  proc p36[T:Int](x: FooBar[Baz[T]]): auto = x.f
+  proc p37[T:Baz[Int]](x: FooBar[T]): auto = x.f
+  proc p38[T:FooBar[Baz[Int]]](x: T): auto = x.f
+  proc p39(x: Foo[Bar[Baz[Int]]]): auto = x.f
+  proc p3A[T:Int](x: Foo[Bar[Baz[T]]]): auto = x.f
+  proc p3B[T:Baz[Int]](x: Foo[Bar[T]]): auto = x.f
+  proc p3C[T:Bar[Baz[Int]]](x: Foo[T]): auto = x.f
+  proc p3D[T:Foo[Bar[Baz[Int]]]](x: T): auto = x.f
+
+  template test(x: typed) =
+    let t00 = p00(x)
+    let t01 = p01(x)
+    let t02 = p02(x)
+    let t10 = p10(x)
+    let t11 = p11(x)
+    let t12 = p12(x)
+    #let t13 = p13(x)
+    let t14 = p14(x)
+    #let t15 = p15(x)
+    #let t16 = p16(x)
+    let t20 = p20(x)
+    let t21 = p21(x)
+    let t22 = p22(x)
+    #let t23 = p23(x)
+    let t24 = p24(x)
+    #let t25 = p25(x)
+    #let t26 = p26(x)
+    #let t27 = p27(x)
+    let t28 = p28(x)
+    #let t29 = p29(x)
+    #let t2A = p2A(x)
+    #let t2B = p2B(x)
+    let t30 = p30(x)
+    let t31 = p31(x)
+    let t32 = p32(x)
+    let t33 = p33(x)
+    let t34 = p34(x)
+    let t35 = p35(x)
+    let t36 = p36(x)
+    let t37 = p37(x)
+    let t38 = p38(x)
+    let t39 = p39(x)
+    let t3A = p3A(x)
+    let t3B = p3B(x)
+    let t3C = p3C(x)
+    let t3D = p3D(x)
+
+  var a: Foo[Bar[Baz[int]]]
+  test(a)
+  var b: FooBar[Baz[int]]
+  test(b)
+  var c: FooBarBaz[int]
+  test(c)
+  var d: FooBarBazX
+  test(d)
+
+
+# overloading on tuples with generic alias
+block:
+  type
+    Foo[F,T] = object
+      exArgs: T
+    FooUn[F,T] = Foo[F,tuple[a:T]]
+    FooBi[F,T1,T2] = Foo[F,tuple[a:T1,b:T2]]
+
+  proc foo1[F,T](x: Foo[F,tuple[a:T]]): int = 1
+  proc foo1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2
+  proc foo2[F,T](x: FooUn[F,T]): int = 1
+  proc foo2[F,T1,T2](x: FooBi[F,T1,T2]):int = 2
+
+  template bar1[F,T](x: Foo[F,tuple[a:T]]): int = 1
+  template bar1[F,T1,T2](x: Foo[F,tuple[a:T1,b:T2]]): int = 2
+  template bar2[F,T](x: FooUn[F,T]): int = 1
+  template bar2[F,T1,T2](x: FooBi[F,T1,T2]): int = 2
+
+  proc test(x: auto, n: int) =
+    doAssert(foo1(x) == n)
+    doAssert(foo2(x) == n)
+    doAssert(bar1(x) == n)
+    doAssert(bar2(x) == n)
+
+  var a: Foo[int, tuple[a:int]]
+  test(a, 1)
+  var b: FooUn[int, int]
+  test(b, 1)
+  var c: Foo[int, tuple[a:int,b:int]]
+  test(c, 2)
+  var d: FooBi[int, int, int]
+  test(d, 2)
+
+
+# inheritance and generics
+block:
+  type
+    Foo[T] = object of RootObj
+      x: T
+    Bar[T] = object of Foo[T]
+      y: T
+    Baz[T] = object of Bar[T]
+      z: T
+
+  template t0(x: Foo[int]): int = 0
+  template t0(x: Bar[int]): int = 1
+  template t0(x: Foo[bool or int]): int = 10
+  template t0(x: Bar[bool or int]): int = 11
+  #template t0[T:bool or int](x: Bar[T]): int = 11
+  template t0[T](x: Foo[T]): int = 20
+  template t0[T](x: Bar[T]): int = 21
+  proc p0(x: Foo[int]): int = 0
+  proc p0(x: Bar[int]): int = 1
+  #proc p0(x: Foo[bool or int]): int = 10
+  #proc p0(x: Bar[bool or int]): int = 11
+  proc p0[T](x: Foo[T]): int = 20
+  proc p0[T](x: Bar[T]): int = 21
+
+  var a: Foo[int]
+  var b: Bar[int]
+  var c: Baz[int]
+  var d: Foo[bool]
+  var e: Bar[bool]
+  var f: Baz[bool]
+  var g: Foo[float]
+  var h: Bar[float]
+  var i: Baz[float]
+  doAssert(t0(a) == 0)
+  doAssert(t0(b) == 1)
+  doAssert(t0(c) == 1)
+  doAssert(t0(d) == 10)
+  doAssert(t0(e) == 11)
+  doAssert(t0(f) == 11)
+  doAssert(t0(g) == 20)
+  doAssert(t0(h) == 21)
+  #doAssert(t0(i) == 21)
+  doAssert(p0(a) == 0)
+  doAssert(p0(b) == 1)
+  doAssert(p0(c) == 1)
+  #doAssert(p0(d) == 10)
+  #doAssert(p0(e) == 11)
+  #doAssert(p0(f) == 11)
+  doAssert(p0(g) == 20)
+  doAssert(p0(h) == 21)
+  doAssert(p0(i) == 21)
+
+  #type
+  #  f0 = proc(x:Foo)
+
+
+block:
+  type
+    TilesetCT[n: static[int]] = distinct int
+    TilesetRT = int
+    Tileset = TilesetCT | TilesetRT
+
+  func prepareTileset(tileset: var Tileset) = discard
+
+  func prepareTileset(tileset: Tileset): Tileset =
+    result = tileset
+    result.prepareTileset
+
+  var parsedTileset: TilesetRT
+  prepareTileset(parsedTileset)
+
+
+block:
+  proc p1[T,U: SomeInteger|SomeFloat](x: T, y: U): int|float =
+    when T is SomeInteger and U is SomeInteger:
+      result = int(x) + int(y)
+    else:
+      result = float(x) + float(y)
+  doAssert(p1(1,2) == 3)
+  doAssert(p1(1.0,2) == 3.0)
+  doAssert(p1(1,2.0) == 3.0)
+  doAssert(p1(1.0,2.0) == 3.0)
+
+  type Foo[T,U] = U
+  template F[T,U](t: typedesc[T], x: U): untyped = Foo[T,U](x)
+  proc p2[T; U,V:Foo[T,SomeNumber]](x: U, y: V): T =
+    T(x) + T(y)
+  #proc p2[T; U:Foo[T,SomeNumber], V:Foo[not T,SomeNumber]](x: U, y: V): T =
+  #  T(x) + T(y)
+  doAssert(p2(F(int,1),F(int,2)) == 3)
+  doAssert(p2(F(float,1),F(float,2)) == 3.0)
+  doAssert(p2(F(float,1),F(float,2.0)) == 3.0)
+  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/tparam_forwarding.nim b/tests/overload/tparam_forwarding.nim
new file mode 100644
index 000000000..b0eea42c7
--- /dev/null
+++ b/tests/overload/tparam_forwarding.nim
@@ -0,0 +1,53 @@
+discard """
+output: '''baz
+10
+100
+1000
+a
+b
+c
+x: 1, y: test 1
+x: 2, y: test 2
+x: 10, y: test 3
+x: 4, y: test 4
+'''
+"""
+
+type
+  Foo = object
+    x: int
+
+proc stringVarargs*(strings: varargs[string, `$`]): void =
+  for s in strings: echo s
+
+proc fooVarargs*(foos: varargs[Foo]) =
+  for f in foos: echo f.x
+
+template templateForwarding*(callable: untyped,
+                             condition: bool,
+                             forwarded: varargs[untyped]): untyped =
+  if condition:
+    callable(forwarded)
+
+proc procForwarding(args: varargs[string]) =
+  stringVarargs(args)
+
+templateForwarding stringVarargs, 17 + 4 < 21, "foo", "bar", 100
+templateForwarding stringVarargs, 10 < 21, "baz"
+
+templateForwarding fooVarargs, "test".len > 3, Foo(x: 10), Foo(x: 100), Foo(x: 1000)
+
+procForwarding "a", "b", "c"
+
+proc hasKeywordArgs(x = 10, y = "y") =
+  echo "x: ", x, ", y: ", y
+
+proc hasRegularArgs(x: int, y: string) =
+  echo "x: ", x, ", y: ", y
+
+templateForwarding(hasRegularArgs, true, 1, "test 1")
+templateForwarding hasKeywordArgs, true, 2, "test 2"
+
+templateForwarding(hasKeywordArgs, true, y = "test 3")
+templateForwarding hasKeywordArgs, true, y = "test 4", x = 4
+
diff --git a/tests/overload/tproc_types_dont_like_subtypes.nim b/tests/overload/tproc_types_dont_like_subtypes.nim
new file mode 100644
index 000000000..6774be156
--- /dev/null
+++ b/tests/overload/tproc_types_dont_like_subtypes.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "got <B, proc (b: B){.closure, gcsafe.}>"
+  line: 20
+"""
+
+type
+  A = ref object of RootObj
+  B = ref object of A
+
+  P = proc (a: A)
+
+# bug #16325
+
+proc doThings(a: A, p: P) =
+  p(a)
+
+var x = proc (b: B) {.closure.} =
+  echo "B"
+
+doThings(B(), x)
diff --git a/tests/overload/tspec.nim b/tests/overload/tspec.nim
new file mode 100644
index 000000000..a84bac244
--- /dev/null
+++ b/tests/overload/tspec.nim
@@ -0,0 +1,118 @@
+discard """
+  output: '''not a var
+not a var
+a var
+B
+int
+T
+int16
+T
+ref T
+123
+2
+1
+@[123, 2, 1]
+Called!
+merge with var
+merge no var'''
+"""
+
+# Things that's even in the spec now!
+
+proc byvar(x: var int) = echo "a var"
+proc byvar(x: int) = echo "not a var"
+byvar(89)
+
+let letSym = 0
+var varSym = 13
+
+byvar(letSym)
+byvar(varSym)
+
+type
+  A = object of RootObj
+  B = object of A
+  C = object of B
+
+proc p(obj: A) =
+  echo "A"
+
+proc p(obj: B) =
+  echo "B"
+
+var c = C()
+# not ambiguous, calls 'B', not 'A' since B is a subtype of A
+# but not vice versa:
+p(c)
+
+proc pp(obj: A, obj2: B) = echo "A B"
+proc pp(obj: B, obj2: A) = echo "B A"
+
+# but this is ambiguous:
+#pp(c, c)
+
+proc takesInt(x: int) = echo "int"
+proc takesInt[T](x: T) = echo "T"
+proc takesInt(x: int16) = echo "int16"
+
+takesInt(4) # "int"
+var x: int32
+takesInt(x) # "T"
+var y: int16
+takesInt(y) # "int16"
+var z: range[0..4] = 0
+takesInt(z) # "T"
+
+proc gen[T](x: ref ref T) = echo "ref ref T"
+proc gen[T](x: ref T) = echo "ref T"
+proc gen[T](x: T) = echo "T"
+
+var ri: ref int
+gen(ri) # "ref T"
+
+
+template rem(x) = discard
+#proc rem[T](x: T) = discard
+
+rem unresolvedExpression(undeclaredIdentifier)
+
+
+proc takeV[T](a: varargs[T]) =
+  for x in a: echo x
+
+takeV([123, 2, 1]) # takeV's T is "int", not "array of int"
+echo(@[123, 2, 1])
+
+# bug #2600
+
+type
+  FutureBase* = ref object of RootObj ## Untyped future.
+
+  Future*[T] = ref object of FutureBase ## Typed future.
+    value: T ## Stored value
+
+  FutureVar*[T] = distinct Future[T]
+
+proc newFuture*[T](): Future[T] =
+  new(result)
+
+proc newFutureVar*[T](): FutureVar[T] =
+  result = FutureVar[T](newFuture[T]())
+
+proc mget*[T](future: FutureVar[T]): var T =
+  Future[T](future).value
+
+proc reset*[T](future: FutureVar[T]) =
+  echo "Called!"
+
+proc merge[T](x: Future[T]) = echo "merge no var"
+proc merge[T](x: var Future[T]) = echo "merge with var"
+
+when true:
+  var foo = newFutureVar[string]()
+  foo.mget() = ""
+  foo.mget.add("Foobar")
+  foo.reset()
+  var bar = newFuture[int]()
+  bar.merge # merge with var
+  merge(newFuture[int]()) # merge no var
diff --git a/tests/overload/tstatic_with_converter.nim b/tests/overload/tstatic_with_converter.nim
new file mode 100644
index 000000000..2bc1dfaab
--- /dev/null
+++ b/tests/overload/tstatic_with_converter.nim
@@ -0,0 +1,48 @@
+discard """
+output: '''
+9.0
+'''
+"""
+
+### bug #6773
+
+{.emit: """ /*INCLUDESECTION*/
+typedef double cimported;
+ 
+cimported set1_imported(double x) {
+  return x;
+}
+ 
+"""}
+ 
+type vfloat{.importc: "cimported".} = object
+ 
+proc set1(a: float): vfloat {.importc: "set1_imported".}
+ 
+converter scalar_to_vector(x: float): vfloat =
+  set1(x)
+ 
+proc sqrt(x: vfloat): vfloat =
+  x
+ 
+proc pow(x, y: vfloat): vfloat =
+  y
+ 
+proc `^`(x: vfloat, exp: static[int]): vfloat =
+  when exp == 0:
+    1.0
+  else:
+    x
+ 
+proc `^`(x: vfloat, exp: static[float]): vfloat =
+  when exp == 0.5:
+    sqrt(x)
+  else:
+    pow(x, exp)
+ 
+proc `$`(x: vfloat): string =
+  let y = cast[ptr float](addr x)
+  result = $y[]
+ 
+let x = set1(9.0)
+echo x^0.5
diff --git a/tests/overload/tsystemcmp.nim b/tests/overload/tsystemcmp.nim
new file mode 100644
index 000000000..aa761b759
--- /dev/null
+++ b/tests/overload/tsystemcmp.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: r"nim c --hints:on $options --threads:on $file"
+  output: '''@["", "a", "ha", "hi", "ho", "huu"]'''
+"""
+
+import algorithm
+
+# bug #1657
+var modules = @["hi", "ho", "", "a", "ha", "huu"]
+sort(modules, system.cmp)
+echo modules
+
+type
+  MyType = object
+    x: string
+
+proc cmp(a, b: MyType): int = cmp(a.x, b.x)
+
+var modulesB = @[MyType(x: "ho"), MyType(x: "ha")]
+sort(modulesB, cmp)
+
+# bug #2397
+
+proc f(x: (proc(a,b: string): int) = system.cmp) = discard
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/tvartypeclass.nim b/tests/overload/tvartypeclass.nim
new file mode 100644
index 000000000..04f3f5a91
--- /dev/null
+++ b/tests/overload/tvartypeclass.nim
@@ -0,0 +1,11 @@
+# issue #13302
+
+proc foo(x: object): int = x.i*2
+proc foo(x: var object) = x.i*=2
+type Foo = object
+  i: int
+let x = Foo(i: 3)
+var y = Foo(i: 4)
+doAssert foo(x) == 6
+foo(y)
+doAssert y.i == 8
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/package/stdlib/stdlib.nimble b/tests/package/stdlib/stdlib.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/package/stdlib/stdlib.nimble
diff --git a/tests/package/stdlib/system.nim b/tests/package/stdlib/system.nim
new file mode 100644
index 000000000..475f8ec5b
--- /dev/null
+++ b/tests/package/stdlib/system.nim
@@ -0,0 +1,2 @@
+# this module is part of tstdlib_name_not_special
+doAssert true
\ No newline at end of file
diff --git a/tests/package/tstdlib_name_not_special.nim b/tests/package/tstdlib_name_not_special.nim
new file mode 100644
index 000000000..e8226a82d
--- /dev/null
+++ b/tests/package/tstdlib_name_not_special.nim
@@ -0,0 +1,3 @@
+# Test whether a another package named 'stdlib' can be imported and used.
+# This caused a crash in the past.
+import stdlib/system
\ No newline at end of file
diff --git a/tests/package_level_objects/definefoo.nim b/tests/package_level_objects/definefoo.nim
new file mode 100644
index 000000000..36576ab59
--- /dev/null
+++ b/tests/package_level_objects/definefoo.nim
@@ -0,0 +1,3 @@
+type
+  Foo* {.package.} = object
+    x, y: int
diff --git a/tests/package_level_objects/mypackage.nimble b/tests/package_level_objects/mypackage.nimble
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/package_level_objects/mypackage.nimble
diff --git a/tests/package_level_objects/tusefoo.nim b/tests/package_level_objects/tusefoo.nim
new file mode 100644
index 000000000..f9bae9545
--- /dev/null
+++ b/tests/package_level_objects/tusefoo.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''@[(x: 3, y: 4)]'''
+"""
+
+type
+  mypackage.Foo = object
+  Other = proc (inp: Foo)
+
+import definefoo
+
+# after this import, Foo is a completely resolved type, so
+# we can create a sequence of it:
+var s: seq[Foo] = @[]
+
+s.add Foo(x: 3, y: 4)
+echo s
diff --git a/tests/package_level_objects/tusefoo2.nim b/tests/package_level_objects/tusefoo2.nim
new file mode 100644
index 000000000..be6b3fcda
--- /dev/null
+++ b/tests/package_level_objects/tusefoo2.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''compiles'''
+"""
+
+# Test that the object type does not need to be resolved at all:
+
+type
+  mypackage.Foo = object
+  Other = proc (inp: Foo)
+
+  Node = ref object
+    external: ptr Foo
+    data: string
+
+var x: Node
+new(x)
+x.data = "compiles"
+
+echo x.data
diff --git a/tests/parallel/nim.cfg b/tests/parallel/nim.cfg
new file mode 100644
index 000000000..d0d2a9305
--- /dev/null
+++ b/tests/parallel/nim.cfg
@@ -0,0 +1,2 @@
+threads:on
+--experimental
diff --git a/tests/parallel/t10913.nim b/tests/parallel/t10913.nim
new file mode 100644
index 000000000..191939100
--- /dev/null
+++ b/tests/parallel/t10913.nim
@@ -0,0 +1,20 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter"
+"""
+
+# bug #10913
+
+import threadpool
+
+proc useParallel*[T](unused: T) =
+  # use a generic T here to show the problem.
+  {.push experimental: "parallel".}
+  parallel:
+    for i in 0..4:
+      spawn echo "echo in parallel"
+  sync()
+  
+  {.pop.}
+
+useParallel(1)
diff --git a/tests/parallel/t5000.nim b/tests/parallel/t5000.nim
new file mode 100644
index 000000000..1dd47a61c
--- /dev/null
+++ b/tests/parallel/t5000.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''50005000'''
+  disabled: "true"
+"""
+
+# XXX this seems to deadlock certain Linux machines
+
+import threadpool, strutils
+
+proc foo(x: int): string = $x
+
+proc main() =
+  var a = newSeq[int]()
+  for i in 1..10000:
+    add(a, i)
+
+  var s = 0
+  for i in a:
+    s += parseInt(^spawn(foo(i)))
+  echo s
+
+setMaxPoolSize 2
+
+parallel:
+  spawn main()
diff --git a/tests/parallel/t7535.nim b/tests/parallel/t7535.nim
new file mode 100644
index 000000000..7817a1c9e
--- /dev/null
+++ b/tests/parallel/t7535.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  errormsg: "'spawn' takes a call expression; got: proc (x: uint32) = echo [x]"
+"""
+
+import threadpool
+
+# bug #7535
+proc print_parallel_nok(r: uint32) =
+  for x in 0..r:
+    spawn (proc (x: uint32) = echo x)
diff --git a/tests/parallel/t9691.nim b/tests/parallel/t9691.nim
new file mode 100644
index 000000000..254f03416
--- /dev/null
+++ b/tests/parallel/t9691.nim
@@ -0,0 +1,9 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  errormsg: "'spawn'ed function cannot have a 'typed' or 'untyped' parameter"
+"""
+
+# bug #9691
+
+import threadpool
+spawn echo()
diff --git a/tests/parallel/tarray_of_channels.nim b/tests/parallel/tarray_of_channels.nim
new file mode 100644
index 000000000..9479227aa
--- /dev/null
+++ b/tests/parallel/tarray_of_channels.nim
@@ -0,0 +1,39 @@
+discard """
+sortoutput: true
+output: '''
+(x: 0.0)
+(x: 0.0)
+(x: 0.0)
+test
+test
+test
+'''
+disabled: "openbsd"
+"""
+
+# bug #2257
+import threadpool
+
+type StringChannel = Channel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when true:
+  main()
diff --git a/tests/parallel/tblocking_channel.nim b/tests/parallel/tblocking_channel.nim
new file mode 100644
index 000000000..f3ccd166a
--- /dev/null
+++ b/tests/parallel/tblocking_channel.nim
@@ -0,0 +1,39 @@
+discard """
+output: ""
+disabled: "freebsd" # see #15725
+"""
+
+import threadpool, os
+
+var chan: Channel[int]
+
+chan.open(2)
+chan.send(1)
+chan.send(2)
+doAssert(not chan.trySend(3)) # At this point chan is at max capacity
+
+proc receiver() =
+    doAssert(chan.recv() == 1)
+    doAssert(chan.recv() == 2)
+    doAssert(chan.recv() == 3)
+    doAssert(chan.recv() == 4)
+    doAssert(chan.recv() == 5)
+
+var msgSent = false
+
+proc emitter() =
+    chan.send(3)
+    msgSent = true
+
+spawn emitter()
+# At this point emitter should be stuck in `send`
+sleep(50) # Sleep a bit to ensure that it is still stuck
+doAssert(not msgSent)
+
+spawn receiver()
+sleep(50) # Sleep a bit to let receicer consume the messages
+doAssert(msgSent) # Sender should be unblocked
+
+doAssert(chan.trySend(4))
+chan.send(5)
+sync()
diff --git a/tests/parallel/tconvexhull.nim b/tests/parallel/tconvexhull.nim
new file mode 100644
index 000000000..a89aa910b
--- /dev/null
+++ b/tests/parallel/tconvexhull.nim
@@ -0,0 +1,60 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+'''
+"""
+
+# parallel convex hull for Nim bigbreak
+# nim c --threads:on -d:release pconvex_hull.nim
+import algorithm, sequtils, threadpool
+
+type Point = tuple[x, y: float]
+
+proc cmpPoint(a, b: Point): int =
+  result = cmp(a.x, b.x)
+  if result == 0:
+    result = cmp(a.y, b.y)
+
+template cross[T](o, a, b: T): untyped =
+  (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x)
+
+template pro(): untyped =
+  while lr1 > 0 and cross(result[lr1 - 1], result[lr1], p[i]) <= 0:
+    discard result.pop
+    lr1 -= 1
+  result.add(p[i])
+  lr1 += 1
+
+proc half[T](p: seq[T]; upper: bool): seq[T] =
+  var i, lr1: int
+  result = @[]
+  lr1 = -1
+  if upper:
+    i = 0
+    while i <= high(p):
+      pro()
+      i += 1
+  else:
+    i = high(p)
+    while i >= low(p):
+      pro()
+      i -= 1
+  discard result.pop
+
+proc convex_hull[T](points: var seq[T], cmp: proc(x, y: T): int {.closure.}) : seq[T] =
+  if len(points) < 2: return points
+  points.sort(cmp)
+  var ul: array[2, FlowVar[seq[T]]]
+  parallel:
+    for k in 0..ul.high:
+      ul[k] = spawn half[T](points, k == 0)
+  result = concat(^ul[0], ^ul[1])
+
+var s = map(toSeq(0..9999), proc(x: int): Point = (float(x div 100), float(x mod 100)))
+# On some runs, this pool size reduction will set the "shutdown" attribute on the
+# worker thread that executes our spawned task, before we can read the flowvars.
+setMaxPoolSize 2
+
+for i in 0..2:
+  doAssert convex_hull[Point](s, cmpPoint) ==
+      @[(0.0, 0.0), (99.0, 0.0), (99.0, 99.0), (0.0, 99.0)]
diff --git a/tests/parallel/tdeepcopy.nim b/tests/parallel/tdeepcopy.nim
new file mode 100644
index 000000000..96ca15ca3
--- /dev/null
+++ b/tests/parallel/tdeepcopy.nim
@@ -0,0 +1,55 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+13 abc
+called deepCopy for int
+called deepCopy for int
+done999 999
+'''
+"""
+
+import threadpool
+
+block one:
+  type
+    PBinaryTree = ref object
+      le, ri: PBinaryTree
+      value: int
+
+  proc main =
+    var x: PBinaryTree
+    deepCopy(x, PBinaryTree(ri: PBinaryTree(le: PBinaryTree(value: 13))))
+    var y: string
+    deepCopy y, "abc"
+    echo x.ri.le.value, " ", y
+
+  main()
+
+
+block two:
+  type
+    Bar[T] = object
+      x: T
+
+  proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] =
+    result.new
+    result.x = b.x
+    when T is int:
+      echo "called deepCopy for int"
+    else:
+      echo "called deepCopy for something else"
+
+  proc foo(b: ref Bar[int]): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+  proc main =
+    var dummy: ref Bar[int]
+    new(dummy)
+    dummy.x = 44
+    #parallel:
+    let f = spawn foo(dummy)
+    let b = spawn foo(dummy)
+    echo "done", ^f, " ", ^b
+
+  main()
diff --git a/tests/parallel/tdeepcopy2.nim b/tests/parallel/tdeepcopy2.nim
new file mode 100644
index 000000000..e8305173d
--- /dev/null
+++ b/tests/parallel/tdeepcopy2.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+called deepCopy for int
+called deepCopy for int
+done999 999
+'''
+"""
+
+import threadpool
+
+
+type
+  Bar[T] = object
+    x: T
+
+proc `=deepCopy`[T](b: ref Bar[T]): ref Bar[T] =
+  result.new
+  result.x = b.x
+  when T is int:
+    echo "called deepCopy for int"
+  else:
+    echo "called deepCopy for something else"
+
+proc foo(b: ref Bar[int]): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+proc main =
+  var dummy: ref Bar[int]
+  new(dummy)
+  dummy.x = 44
+  #parallel:
+  let f = spawn foo(dummy)
+  let b = spawn foo(dummy)
+  echo "done", ^f, " ", ^b
+
+main()
diff --git a/tests/parallel/tdisjoint_slice1.nim b/tests/parallel/tdisjoint_slice1.nim
new file mode 100644
index 000000000..6892e7383
--- /dev/null
+++ b/tests/parallel/tdisjoint_slice1.nim
@@ -0,0 +1,51 @@
+discard """
+  matrix: "--mm:refc"
+  outputsub: "EVEN 28"
+"""
+
+import threadpool, locks
+
+block one:
+  proc odd(a: int) =  echo "ODD  ", a
+  proc even(a: int) = echo "EVEN ", a
+
+  proc main() =
+    var a: array[0..30, int]
+    for i in low(a)..high(a): a[i] = i
+    parallel:
+      var i = 0
+      while i <= 29:
+        spawn even(a[i])
+        spawn odd(a[i+1])
+        inc i, 2
+        # is correct here
+
+  main()
+
+
+block two:
+  var echoLock: Lock
+  initLock echoLock
+
+  proc f(a: openArray[int]) =
+    for x in a:
+      withLock echoLock:
+        echo x
+
+  proc f(a: int) =
+    withLock echoLock:
+      echo a
+
+  proc main() =
+    var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9]
+    parallel:
+      spawn f(a[0..2])
+      #spawn f(a[16..30])
+      var i = 3
+      while i <= 8:
+        spawn f(a[i])
+        spawn f(a[i+1])
+        inc i, 2
+        # is correct here
+
+  main()
diff --git a/tests/parallel/tflowvar.nim b/tests/parallel/tflowvar.nim
new file mode 100644
index 000000000..e44b29a87
--- /dev/null
+++ b/tests/parallel/tflowvar.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''foobarfoobar
+bazbearbazbear
+
+1'''
+  cmd: "nim $target --threads:on $options $file"
+  disabled: "openbsd"
+"""
+
+import threadpool
+
+proc computeSomething(a, b: string): string = a & b & a & b & "\n"
+
+proc main =
+  let fvA = spawn computeSomething("foo", "bar")
+  let fvB = spawn computeSomething("baz", "bear")
+
+  echo(^fvA, ^fvB)
+
+main()
+sync()
+
+
+type
+  TIntSeq = seq[int]
+
+proc t(): TIntSeq =
+  result = @[1]
+
+proc p(): int =
+  var a: FlowVar[TIntSeq]
+  parallel:
+    var aa = spawn t()
+    a = aa
+  result = (^a)[0]
+
+echo p()
diff --git a/tests/parallel/tforstmt.nim b/tests/parallel/tforstmt.nim
new file mode 100644
index 000000000..58de833f3
--- /dev/null
+++ b/tests/parallel/tforstmt.nim
@@ -0,0 +1,25 @@
+discard """
+  output: '''3
+4
+5
+6
+7'''
+  sortoutput: true
+"""
+
+import threadpool, os
+
+proc p(x: int) =
+  os.sleep(100 - x*10)
+  echo x
+
+proc testFor(a, b: int; foo: var openArray[int]) =
+  parallel:
+    for i in max(a, 0) .. min(b, foo.high):
+      spawn p(foo[i])
+
+var arr = [0, 1, 2, 3, 4, 5, 6, 7]
+
+testFor(3, 10, arr)
+
+
diff --git a/tests/parallel/tgc_unsafe.nim b/tests/parallel/tgc_unsafe.nim
new file mode 100644
index 000000000..baf0dc24a
--- /dev/null
+++ b/tests/parallel/tgc_unsafe.nim
@@ -0,0 +1,32 @@
+discard """
+  errormsg: "'consumer' is not GC-safe"
+  line: 19
+"""
+
+# bug #2257
+import threadpool
+
+type StringChannel = Channel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc consumer(ix : int) {.thread.} =
+  echo channels[ix].recv() ###### not GC-safe: 'channels'
+  echo global
+  echo globalB
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when true:
+  main()
diff --git a/tests/parallel/tgc_unsafe2.nim b/tests/parallel/tgc_unsafe2.nim
new file mode 100644
index 000000000..7d98dafcb
--- /dev/null
+++ b/tests/parallel/tgc_unsafe2.nim
@@ -0,0 +1,38 @@
+discard """
+  errormsg: "'consumer' is not GC-safe as it calls 'track'"
+  nimout: '''tgc_unsafe2.nim(21, 6) Warning: 'trick' is not GC-safe as it accesses 'global' which is a global using GC'ed memory [GcUnsafe2]
+tgc_unsafe2.nim(25, 6) Warning: 'track' is not GC-safe as it calls 'trick' [GcUnsafe2]
+tgc_unsafe2.nim(27, 6) Error: 'consumer' is not GC-safe as it calls 'track'
+'''
+"""
+
+import threadpool
+
+type StringChannel = Channel[string]
+var channels: array[1..3, StringChannel]
+
+type
+  MyObject[T] = object
+    x: T
+
+var global: MyObject[string]
+var globalB: MyObject[float]
+
+proc trick(ix: int) =
+  echo global.x
+  echo channels[ix].recv()
+
+proc track(ix: int) = trick(ix)
+
+proc consumer(ix: int) {.thread.} =
+  track(ix)
+
+proc main =
+  for ix in 1..3: channels[ix].open()
+  for ix in 1..3: spawn consumer(ix)
+  for ix in 1..3: channels[ix].send("test")
+  sync()
+  for ix in 1..3: channels[ix].close()
+
+when true:
+  main()
diff --git a/tests/parallel/tguard1.nim b/tests/parallel/tguard1.nim
new file mode 100644
index 000000000..f4c92319b
--- /dev/null
+++ b/tests/parallel/tguard1.nim
@@ -0,0 +1,41 @@
+discard """
+output: "90"
+"""
+
+
+when false:
+  template lock(a, b: ptr Lock; body: stmt) =
+    if cast[int](a) < cast[int](b):
+      pthread_mutex_lock(a)
+      pthread_mutex_lock(b)
+    else:
+      pthread_mutex_lock(b)
+      pthread_mutex_lock(a)
+    {.locks: [a, b].}:
+      try:
+        body
+      finally:
+        pthread_mutex_unlock(a)
+        pthread_mutex_unlock(b)
+
+type
+  ProtectedCounter[T] = object
+    i {.guard: L.}: T
+    L: int
+
+var
+  c: ProtectedCounter[int]
+
+c.i = 89
+
+template atomicRead(L, x): untyped =
+  {.locks: [L].}:
+    x
+
+proc main =
+  {.locks: [c.L].}:
+    inc c.i
+    discard
+  echo(atomicRead(c.L, c.i))
+
+main()
diff --git a/tests/parallel/tguard2.nim b/tests/parallel/tguard2.nim
new file mode 100644
index 000000000..661893bb5
--- /dev/null
+++ b/tests/parallel/tguard2.nim
@@ -0,0 +1,27 @@
+discard """
+  errormsg: "unguarded access: c.i"
+  line: 25
+"""
+
+type
+  ProtectedCounter[T] = object
+    i {.guard: L.}: T
+    L: int
+
+var
+  c: ProtectedCounter[int]
+
+c.i = 89
+
+template atomicRead(L, x): untyped =
+  {.locks: [L].}:
+    x
+
+proc main =
+  {.locks: [c.L].}:
+    inc c.i
+    discard
+  echo(atomicRead(c.L, c.i))
+  echo c.i
+
+main()
diff --git a/tests/parallel/tinvalid_array_bounds.nim b/tests/parallel/tinvalid_array_bounds.nim
new file mode 100644
index 000000000..8dc93c33f
--- /dev/null
+++ b/tests/parallel/tinvalid_array_bounds.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tinvalid_counter_usage.nim b/tests/parallel/tinvalid_counter_usage.nim
new file mode 100644
index 000000000..c6303c651
--- /dev/null
+++ b/tests/parallel/tinvalid_counter_usage.nim
@@ -0,0 +1,26 @@
+discard """
+  errormsg: "invalid usage of counter after increment"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    spawn f(a[0..15])
+    spawn f(a[16..30])
+    var i = 0
+    while i <= 30:
+      inc i
+      spawn f(a[i])
+      inc i
+      #spawn f(a[i+1])
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tlet_spawn.nim b/tests/parallel/tlet_spawn.nim
new file mode 100644
index 000000000..853ffc443
--- /dev/null
+++ b/tests/parallel/tlet_spawn.nim
@@ -0,0 +1,28 @@
+discard """
+output: '''
+done999 999
+'''
+"""
+
+import std/[threadpool, os]
+
+proc foo(): int = 999
+
+# test that the disjoint checker deals with 'a = spawn f(); g = spawn f()':
+
+proc main =
+  parallel:
+    let f = spawn foo()
+    let b = spawn foo()
+  echo "done", f, " ", b
+
+main()
+
+# bug #13781
+proc thread(): string =
+  os.sleep(1000)
+  return "ok"
+
+var fv = spawn thread()
+sync()
+doAssert ^fv == "ok"
diff --git a/tests/parallel/tmissing_deepcopy.nim b/tests/parallel/tmissing_deepcopy.nim
new file mode 100644
index 000000000..ea77936ad
--- /dev/null
+++ b/tests/parallel/tmissing_deepcopy.nim
@@ -0,0 +1,42 @@
+discard """
+  matrix: "--mm:refc"
+  ccodeCheck: "@'genericDeepCopy(' .*"
+  action: compile
+"""
+
+# bug #2286
+
+import threadPool
+
+type
+  Person = ref object
+    name: string
+    friend: Person
+
+var
+  people: seq[Person] = @[]
+
+proc newPerson(name:string): Person =
+  result.new()
+  result.name = name
+
+proc greet(p:Person) =
+  p.friend.name &= "-MUT" # this line crashes the program
+  echo "Person {",
+    " name:", p.name, "(", cast[int](addr p.name),"),",
+    " friend:", p.friend.name, "(", cast[int](addr p.friend.name),") }"
+
+proc setup =
+  for i in 0 ..< 10:
+    people.add newPerson("Person" & $(i + 1))
+  for i in 0 ..< 10:
+    people[i].friend = people[9-i]
+
+proc update =
+  parallel:
+    for i in 0 .. people.high:
+      spawn people[i].greet()
+
+when true:
+  setup()
+  update()
diff --git a/tests/parallel/tnon_disjoint_slice1.nim b/tests/parallel/tnon_disjoint_slice1.nim
new file mode 100644
index 000000000..51762187d
--- /dev/null
+++ b/tests/parallel/tnon_disjoint_slice1.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "cannot prove (i)..(i) disjoint from (i + 1)..(i + 1)"
+  line: 21
+"""
+
+import threadpool
+
+proc f(a: openArray[int]) =
+  for x in a: echo x
+
+proc f(a: int) = echo a
+
+proc main() =
+  var a: array[0..30, int]
+  parallel:
+    #spawn f(a[0..15])
+    #spawn f(a[16..30])
+    var i = 0
+    while i <= 29:
+      spawn f(a[i])
+      spawn f(a[i+1])
+      inc i
+      #inc i  # inc i, 2  would be correct here
+
+main()
diff --git a/tests/parallel/tparfind.nim b/tests/parallel/tparfind.nim
new file mode 100644
index 000000000..cf1bc9336
--- /dev/null
+++ b/tests/parallel/tparfind.nim
@@ -0,0 +1,29 @@
+discard """
+  matrix: "--mm:refc"
+  output: "500"
+"""
+
+import threadpool, sequtils
+
+{.experimental: "parallel".}
+
+proc linearFind(a: openArray[int]; x, offset: int): int =
+  for i, y in a:
+    if y == x: return i+offset
+  result = -1
+
+proc parFind(a: seq[int]; x: int): int =
+  var results: array[4, int]
+  parallel:
+    if a.len >= 4:
+      let chunk = a.len div 4
+      results[0] = spawn linearFind(a[0 ..< chunk], x, 0)
+      results[1] = spawn linearFind(a[chunk ..< chunk*2], x, chunk)
+      results[2] = spawn linearFind(a[chunk*2 ..< chunk*3], x, chunk*2)
+      results[3] = spawn linearFind(a[chunk*3 ..< a.len], x, chunk*3)
+  result = max(results)
+
+
+let data = toSeq(0..1000)
+echo parFind(data, 500)
+
diff --git a/tests/parallel/tpi.nim b/tests/parallel/tpi.nim
new file mode 100644
index 000000000..cd965d585
--- /dev/null
+++ b/tests/parallel/tpi.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''3.141792613595791
+3.141792613595791'''
+"""
+
+import strutils, math, threadpool
+
+proc term(k: float): float = 4 * math.pow(-1, k) / (2*k + 1)
+
+proc piU(n: int): float =
+  var ch = newSeq[FlowVar[float]](n+1)
+  for k in 0..ch.high:
+    ch[k] = spawn term(float(k))
+  for k in 0..ch.high:
+    result += ^ch[k]
+
+proc piS(n: int): float =
+  var ch = newSeq[float](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = spawn term(float(k))
+  for k in 0..ch.high:
+    result += ch[k]
+
+echo formatFloat(piU(5000))
+echo formatFloat(piS(5000))
diff --git a/tests/parallel/tptr_to_ref.nim b/tests/parallel/tptr_to_ref.nim
new file mode 100644
index 000000000..ae02c16e5
--- /dev/null
+++ b/tests/parallel/tptr_to_ref.nim
@@ -0,0 +1,71 @@
+# bug #2854
+
+# Test case for the compiler correctly detecting if a type used by a shared
+# global is gcsafe.
+
+import locks, threadpool, osproc
+
+const MAX_WORKERS = 50
+
+type
+  Killer* = object
+    lock:                      Lock
+    bailed    {.guard: lock.}: bool
+    processes {.guard: lock.}: array[0..MAX_WORKERS-1, ptr Process]
+
+# Hold a lock for a statement.
+template hold(lock: Lock, body: untyped) =
+  lock.acquire
+  defer: lock.release
+  {.locks: [lock].}:
+    body
+
+# Return an initialized Killer.
+proc initKiller*(): Killer =
+  initLock(result.lock)
+  result.lock.hold:
+    result.bailed = false
+    for i, _ in result.processes:
+      result.processes[i] = nil
+
+# Global Killer instance.
+var killer = initKiller()
+
+# remember that a process has been launched, killing it if we have bailed.
+proc launched*(process: ptr Process): int {.gcsafe.} =
+  result = killer.processes.high + 1
+  killer.lock.hold:
+    if killer.bailed:
+      process[].terminate()
+    else:
+      for i, _ in killer.processes:
+        if killer.processes[i] == nil:
+          killer.processes[i] = process
+          result = i
+      assert(result <= killer.processes.high)
+
+
+# A process has been finished with - remove the process from death row.
+# Return true if the process was still present, which will be the
+# case unless we have bailed.
+proc completed*(index: int): bool {.gcsafe.} =
+  result = true
+  if index <= killer.processes.high:
+    killer.lock.hold:
+      result = false
+      if killer.processes[index] != nil:
+        result = true
+        killer.processes[index] = nil
+
+
+# Terminate all the processes killer knows about, doing nothing if
+# already bailed.
+proc bail(): bool {.gcsafe.} =
+  killer.lock.hold:
+    result = not killer.bailed
+    if not killer.bailed:
+      killer.bailed = true
+      for i, process in killer.processes:
+        if process != nil:
+          process[].terminate
+          killer.processes[i] = nil
diff --git a/tests/parallel/treadafterwrite.nim b/tests/parallel/treadafterwrite.nim
new file mode 100644
index 000000000..12eb31402
--- /dev/null
+++ b/tests/parallel/treadafterwrite.nim
@@ -0,0 +1,31 @@
+discard """
+  errormsg: "'foo' not disjoint from 'foo'"
+  line: 23
+  disabled: "true"
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat =
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      let foo = (spawn term(float(k)))
+      assert foo != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/tsendtwice.nim b/tests/parallel/tsendtwice.nim
new file mode 100644
index 000000000..9f4a2e06e
--- /dev/null
+++ b/tests/parallel/tsendtwice.nim
@@ -0,0 +1,65 @@
+discard """
+  matrix: "--mm:refc"
+"""
+
+# bug #4776
+
+import tables, algorithm
+
+type
+  Base* = ref object of RootObj
+    someSeq: seq[int]
+    baseData: array[40000, byte]
+  Derived* = ref object of Base
+    data: array[40000, byte]
+
+type
+  ThreadPool = ref object
+    threads: seq[ptr Thread[ThreadArg]]
+    channels: seq[ThreadArg]
+  TableChannel = Channel[TableRef[string, Base]]
+  ThreadArg = ptr TableChannel
+
+var globalTable {.threadvar.}: TableRef[string, Base]
+globalTable = newTable[string, Base]()
+let d = new(Derived)
+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()
+  var myObj: Base
+  deepCopy(myObj, globalTable["ob"])
+  myObj.someSeq = newSeq[int](100)
+  let table = channel[].recv() # same table
+  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
+
+proc newThreadPool(threadCount: int) = #: ThreadPool =
+  #new(result)
+  #result.threads = newSeq[ptr Thread[ThreadArg]](threadCount)
+  #var channel = cast[ptr TableChannel](allocShared0(sizeof(TableChannel)))
+  channel.open()
+  channel.send(globalTable)
+  channel.send(globalTable)
+  #createThread(threadPtr[], testThread, addr channel)
+  testThread(addr channel)
+  #result.threads[i] = threadPtr
+
+proc stop(p: ThreadPool) =
+  for t in p.threads:
+    joinThread(t[])
+    dealloc(t)
+
+
+newThreadPool(1)#.stop()
diff --git a/tests/parallel/tsimple_array_checks.nim b/tests/parallel/tsimple_array_checks.nim
new file mode 100644
index 000000000..ab292f935
--- /dev/null
+++ b/tests/parallel/tsimple_array_checks.nim
@@ -0,0 +1,75 @@
+discard """
+sortoutput: true
+output: '''
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+Hello 1
+Hello 2
+Hello 3
+Hello 4
+Hello 5
+Hello 6
+'''
+"""
+
+# bug #2287
+
+import threadPool
+
+# If `nums` is an array instead of seq,
+# NONE of the iteration ways below work (including high / len-1)
+let nums = @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+proc log(n:int) =
+  echo n
+
+proc main =
+  parallel:
+    for n in nums: # Error: cannot prove: i <= len(nums) + -1
+      spawn log(n)
+    #for i in 0 ..< nums.len: # Error: cannot prove: i <= len(nums) + -1
+    #for i in 0 .. nums.len-1: # WORKS!
+    #for i in 0 ..< nums.len: # WORKS!
+    #  spawn log(nums[i])
+
+# Array needs explicit size to work, probably related to issue #2287
+#const a: array[0..5, int] = [1,2,3,4,5,6]
+
+#const a = [1,2,3,4,5,6] # Doesn't work
+const a = @[1,2,3,4,5,6] # Doesn't work
+proc f(n: int) = echo "Hello ", n
+
+proc maino =
+  parallel:
+    # while loop doesn't work:
+    var i = 0
+    while i < a.high:
+      #for i in countup(0, a.high-1, 2):
+      spawn f(a[i])
+      spawn f(a[i+1])
+      i += 2
+
+maino() # Doesn't work outside a proc
+
+when true:
+  main()
+
+block two:
+  proc f(a: openArray[int]) =
+    discard
+
+  proc main() =
+    var a: array[0..9, int] = [0,1,2,3,4,5,6,7,8,9]
+    parallel:
+      spawn f(a[0..2])
+
+
+  main()
\ No newline at end of file
diff --git a/tests/parallel/tsysspawn.nim b/tests/parallel/tsysspawn.nim
new file mode 100644
index 000000000..b7ecd1264
--- /dev/null
+++ b/tests/parallel/tsysspawn.nim
@@ -0,0 +1,64 @@
+discard """
+  output: '''4
+8
+(a: 1)
+2
+2
+'''
+  matrix: "--mm:refc"
+"""
+
+import threadpool
+
+var
+  x, y = 0
+
+proc p1 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc x
+
+proc p2 =
+  for i in 0 .. 10_000:
+    discard
+
+  atomicInc y, 2
+
+for i in 0.. 3:
+  spawn(p1())
+  spawn(p2())
+
+sync()
+
+echo x
+echo y
+
+
+#--------------------------------------------------------
+# issue #14014
+
+import threadpool
+
+type A = object
+    a: int
+
+proc f(t: typedesc): t =
+  t(a:1)
+
+let r = spawn f(A)
+echo ^r
+
+proc f2(x: static[int]): int =
+  x
+
+let r2 = spawn f2(2)
+echo ^r2
+
+type statint = static[int]
+
+proc f3(x: statint): int =
+  x
+
+let r3 = spawn f3(2)
+echo ^r3
diff --git a/tests/parallel/tsysspawnbadarg.nim b/tests/parallel/tsysspawnbadarg.nim
new file mode 100644
index 000000000..a8f1ed401
--- /dev/null
+++ b/tests/parallel/tsysspawnbadarg.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "'spawn' takes a call expression"
+  line: 9
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+import threadpool
+
+let foo = spawn(1)
diff --git a/tests/parallel/tuseafterdef.nim b/tests/parallel/tuseafterdef.nim
new file mode 100644
index 000000000..64f835a1b
--- /dev/null
+++ b/tests/parallel/tuseafterdef.nim
@@ -0,0 +1,34 @@
+discard """
+  matrix: "--mm:refc"
+  disabled: true
+  errormsg: "(k)..(k) not disjoint from (k)..(k)"
+  line: 24
+  action: compile
+"""
+
+# bug #1597
+
+import strutils, math, threadpool
+
+type
+  BoxedFloat = object
+    value: float
+
+proc term(k: float): ptr BoxedFloat =
+  var temp = 4 * math.pow(-1, k) / (2*k + 1)
+  result = cast[ptr BoxedFloat](allocShared(sizeof(BoxedFloat)))
+  result.value = temp
+
+proc pi(n: int): float =
+  var ch = newSeq[ptr BoxedFloat](n+1)
+  parallel:
+    for k in 0..ch.high:
+      ch[k] = (spawn term(float(k)))
+      assert ch[k] != nil
+  for k in 0..ch.high:
+    var temp = ch[k][].value
+    result += temp
+    deallocShared(ch[k])
+
+
+echo formatFloat(pi(5000))
diff --git a/tests/parallel/twaitany.nim b/tests/parallel/twaitany.nim
new file mode 100644
index 000000000..d57c5f40f
--- /dev/null
+++ b/tests/parallel/twaitany.nim
@@ -0,0 +1,34 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''true'''
+"""
+
+# bug #7638
+import threadpool, os
+
+proc timer(d: int): int =
+  #echo fmt"sleeping {d}"
+  sleep(d)
+  #echo fmt"done {d}"
+  return d
+
+var durations = [1000, 1500, 2000]
+var tasks: seq[FlowVarBase] = @[]
+var results: seq[int] = @[]
+
+for i in 0 .. durations.high:
+  tasks.add spawn timer(durations[i])
+
+var index = blockUntilAny(tasks)
+while index != -1:
+  results.add ^cast[FlowVar[int]](tasks[index])
+  tasks.del(index)
+  #echo repr results
+  index = blockUntilAny(tasks)
+
+doAssert results.len == 3
+doAssert 1000 in results
+doAssert 1500 in results
+doAssert 2000 in results
+sync()
+echo "true"
diff --git a/tests/parser/t12274.nim b/tests/parser/t12274.nim
new file mode 100644
index 000000000..6b7c9f55a
--- /dev/null
+++ b/tests/parser/t12274.nim
@@ -0,0 +1,13 @@
+discard """
+  joinable: false
+"""
+
+var s: seq[int]
+s.add block:
+  let i = 1
+  i
+s.add try:
+  2
+except:
+  3
+doAssert s == @[1, 2]
diff --git a/tests/parser/t15667.nim b/tests/parser/t15667.nim
new file mode 100644
index 000000000..fcb862825
--- /dev/null
+++ b/tests/parser/t15667.nim
@@ -0,0 +1,61 @@
+discard """
+  cmd: "nim check $options $file"
+  action: "reject"
+  nimout: '''
+t15667.nim(23, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(22, 13) ?
+t15667.nim(28, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(26, 13) ?
+t15667.nim(33, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(31, 25) ?
+t15667.nim(42, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(38, 12) ?
+t15667.nim(56, 5) Error: invalid indentation, maybe you forgot a '=' at t15667.nim(55, 13) ?
+t15667.nim(61, 48) Error: expression expected, but found ','
+'''
+"""
+
+
+
+
+
+
+
+# line 20
+block:
+  proc fn1()
+    discard
+
+block:
+  proc fn2()
+    #
+    discard
+
+block:
+  proc fn3() {.exportc.}
+    #
+    discard
+
+block: # complex example
+  proc asdfasdfsd() {. exportc, 
+      inline
+         .}     # foo
+    #[
+    bar
+    ]#
+    discard
+
+block: # xxx this doesn't work yet (only a bare `invalid indentation` error)
+  proc fn5()
+    ##
+    discard
+
+block: # ditto
+  proc fn6*()
+    ## foo bar
+    runnableExamples: discard
+
+block:
+  proc fn8()
+    runnableExamples:
+      discard
+    discard
+
+# semiStmtList loop issue
+proc bar(k:static bool):SomeNumber = (when k: 3, else: 3.0)
diff --git a/tests/parser/t19430.nim b/tests/parser/t19430.nim
new file mode 100644
index 000000000..c1aa6a92d
--- /dev/null
+++ b/tests/parser/t19430.nim
@@ -0,0 +1,3 @@
+let x = proc() = ## abc
+let y = 3 #[tt.Error
+^ invalid indentation]#
diff --git a/tests/parser/t19662.nim b/tests/parser/t19662.nim
new file mode 100644
index 000000000..7a1864ac6
--- /dev/null
+++ b/tests/parser/t19662.nim
@@ -0,0 +1,6 @@
+                var i: int # bug #19662
+echo i
+
+discard """
+  errormsg: "invalid indentation"
+"""
\ No newline at end of file
diff --git a/tests/parser/t20922.nim b/tests/parser/t20922.nim
new file mode 100644
index 000000000..110610fb1
--- /dev/null
+++ b/tests/parser/t20922.nim
@@ -0,0 +1,35 @@
+discard """
+  cmd: "nim check $options --verbosity:0 --hints:off $file"
+  action: "reject"
+  nimout: '''
+t20922.nim(26, 5) Error: expression expected, but found ':'
+t20922.nim(34, 7) Error: expression expected, but found ':'
+t20922.nim(35, 5) Error: ':' or '=' expected, but got 'keyword of'
+Error: in expression ' '+'': identifier expected, but found ''
+t20922.nim(26, 7) Error: attempting to call undeclared routine: '<Error>'
+Error: in expression ' '+'': identifier expected, but found ''
+t20922.nim(26, 7) Error: attempting to call undeclared routine: '<Error>'
+t20922.nim(26, 7) Error: expression '' cannot be called
+t20922.nim(26, 7) Error: expression '' has no type (or is ambiguous)
+t20922.nim(26, 7) Error: VM problem: dest register is not set
+'''
+"""
+# original test case issue #20922
+type Token = enum
+  incDataPtr,
+  incDataPtrByte
+
+proc mapInstrToToken(instr: char): Token =
+  case instr:
+  of '>':
+    incDataPtr
+  of: '+':
+    incDataPtrByte
+
+# same issue with `of` in object branches (different parser procs calling `exprList`)
+type
+  Bar = enum A, B
+  Foo = object
+    case kind: Bar
+    of: x: int
+    of B: y: float
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/parser/tcommand_as_expr.nim b/tests/parser/tcommand_as_expr.nim
new file mode 100644
index 000000000..f37c34f63
--- /dev/null
+++ b/tests/parser/tcommand_as_expr.nim
@@ -0,0 +1,47 @@
+discard """
+  output: '''140
+5-120-120
+359
+77
+-4
+-1
+-1'''
+"""
+#import math
+import sequtils
+
+proc optarg(x:int, y:int = 0):int = x + 3 * y
+proc singlearg(x:int):int = 20*x
+echo optarg 1, singlearg 2
+
+
+proc foo(x: int): int = x-1
+proc foo(x, y: int): int = x-y
+
+let x = optarg foo 7.foo
+let y = singlearg foo(1, foo 8)
+let z = singlearg 1.foo foo 8
+
+echo x, y, z
+
+let a = [2,4,8].map do (d:int) -> int: d + 1
+echo a[0], a[1], a[2]
+
+echo(foo 8, foo 8)
+
+# bug #7582
+proc f(x: int): int = x
+
+echo f -4
+
+echo int -1 # doesn't compile
+echo int `-` 1 # compiles
+
+var num = 1
+num += int 2
+doAssert num == 3
+
+import options
+var opt = some some none int
+opt = some some none int
+opt = some none Option[int]
diff --git a/tests/parser/tcommandequals.nim b/tests/parser/tcommandequals.nim
new file mode 100644
index 000000000..f41b318ac
--- /dev/null
+++ b/tests/parser/tcommandequals.nim
@@ -0,0 +1,17 @@
+discard """
+  output: '''
+5
+'''
+"""
+
+proc foo(a, b: int) =
+  echo a + b
+
+foo a = 2, b = 3
+
+import macros
+
+macro bar(args: varargs[untyped]): untyped =
+  doAssert args[0].kind == nnkExprEqExpr
+
+bar "a" = 1
diff --git a/tests/parser/tcommandindent.nim b/tests/parser/tcommandindent.nim
new file mode 100644
index 000000000..449c218db
--- /dev/null
+++ b/tests/parser/tcommandindent.nim
@@ -0,0 +1,16 @@
+when false: # parse the following
+  let foo = Obj(
+    field1: proc (src: pointer, srcLen: Natural)
+                    {.nimcall, gcsafe, raises: [IOError, Defect].} =
+      var file = FileOutputStream(s).file
+
+      implementWrites s.buffers, src, srcLen, "FILE",
+                      writeStartAddr, writeLen,
+        file.writeBuffer(writeStartAddr, writeLen)
+    ,
+    field2: proc {.nimcall, gcsafe, raises: [IOError, Defect].} =
+      flushFile FileOutputStream(s).file
+    ,
+    field3: proc () {.nimcall, gcsafe, raises: [IOError, Defect].} =
+      close FileOutputStream(s).file
+  )
diff --git a/tests/parser/tdo.nim b/tests/parser/tdo.nim
new file mode 100644
index 000000000..382d03398
--- /dev/null
+++ b/tests/parser/tdo.nim
@@ -0,0 +1,94 @@
+discard """
+  output: '''
+true
+true
+true
+true inner B
+running with pragma
+ran with pragma
+'''
+"""
+
+template withValue(a, b, c, d, e: untyped) =
+  if c:
+    d
+  else:
+    e
+
+template withValue(a, b, c, d: untyped) =
+  if c:
+    d
+
+const
+  EVENT_READ = 1
+  EVENT_WRITE = 2
+  FLAG_HANDLE = 3
+  EVENT_MASK = 3
+
+var s: string
+
+proc main =
+  var value = false
+  var fd = 8888
+  var event = 0
+  s.withValue(fd, value) do:
+    if value:
+      var oe = (EVENT_MASK)
+      if (oe xor event) != 0:
+        if (oe and EVENT_READ) != 0 and (event and EVENT_READ) == 0:
+          discard
+        if (oe and EVENT_WRITE) != 0 and (event and EVENT_WRITE) == 0:
+          discard
+        if (oe and EVENT_READ) == 0 and (event and EVENT_READ) != 0:
+          discard
+        if (oe and EVENT_WRITE) == 0 and (event and EVENT_WRITE) != 0:
+          discard
+    else:
+      raise newException(ValueError, "error")
+  do:
+    raise newException(ValueError, "Descriptor is not registered in queue")
+
+proc main2 =
+  var unused = 8
+  # test 'then' branch:
+  s.withValue(unused, true) do:
+    echo "true"
+  do:
+    echo "false"
+
+  # test overloading:
+  s.withValue(unused, false) do:
+    echo "cannot come here"
+
+  # test 'else' branch:
+  s.withValue(unused, false) do:
+    echo "false"
+  do:
+    echo "true"
+
+  # test proper nesting:
+  s.withValue(unused, false) do:
+    echo "false"
+    s.withValue(unused, false) do:
+      echo "false inner A"
+    do:
+      echo "true inner A"
+  do:
+    echo "true"
+    s.withValue(unused, false) do:
+      echo "false inner B"
+    do:
+      echo "true inner B"
+
+main2()
+
+proc withPragma(foo: int, bar: proc() {.raises: [].}) =
+  echo "running with pragma"
+  bar()
+
+withPragma(3) do {.raises: [].}:
+  echo "ran with pragma"
+
+doAssert not (compiles do:
+  withPragma(3) do {.raises: [].}:
+    raise newException(Exception))
diff --git a/tests/parser/tdoc_comments.nim b/tests/parser/tdoc_comments.nim
new file mode 100644
index 000000000..3c86e69ea
--- /dev/null
+++ b/tests/parser/tdoc_comments.nim
@@ -0,0 +1,75 @@
+
+# bug #1799
+
+proc MyProc1*() = ## Comment behind procedure
+  discard
+
+proc MyProc2*() =
+  ## Comment below procedure
+  discard
+
+
+template MyTemplate1*() = discard ## Comment behind template
+
+template MyTemplate2*() = discard
+  ## Comment below template
+
+
+const
+  MyConst1* = 1 ## Comment behind constant
+  MyConst2* = 2
+    ## Comment below constant
+
+
+var
+  MyVar1* = 1 ## Comment behind variable
+  MyVar2* = 2
+    ## Comment below variable
+
+
+type
+  MyObject1* = object
+    ## Comment below declaration
+    field1*: int ## Comment behind field
+    field2*: int ## Comment behind field
+    field3*: int
+      ## Comment below field
+    field4*: int
+      ## Comment below field
+
+  MyObject2* = object ## Comment behind declaration
+    field1*: int
+
+
+type
+  MyTuple1* = tuple
+    ## Comment below declaration
+    field1: int ## Comment behind field
+    field2: int ## Comment behind field
+    field3: int
+      ## Comment below field
+    field4: int
+      ## Comment below field
+
+  MyTuple2* = tuple ## Comment behind declaration
+    field1: int
+
+
+type
+  MyEnum1* = enum
+    ## Comment below declaration
+    value1, ## Comment behind value
+    value2,
+      ## Comment below value with comma
+    value3
+      ## Comment below value without comma
+
+  MyEnum2* = enum ## Comment behind declaration
+    value4
+
+  MyEnum3* = enum
+    value5  ## only document the enum value
+
+# bug #18847
+proc close*() =   ## asdfasdfsdfa
+  discard         ## adsfasdfads
diff --git a/tests/parser/tdomulttest.nim b/tests/parser/tdomulttest.nim
new file mode 100644
index 000000000..9e1afd034
--- /dev/null
+++ b/tests/parser/tdomulttest.nim
@@ -0,0 +1,17 @@
+discard """
+  output: "555\ntest\nmulti lines\n99999999\nend"
+"""
+
+proc foo(bar, baz: proc (x: int): int) =
+  echo bar(555)
+  echo baz(99999999)
+
+foo do (x: int) -> int:
+  return x
+
+do (x: int) -> int:
+  echo("test")
+  echo("multi lines")
+  return x
+
+echo("end")
diff --git a/tests/parser/tdotlikeoperators.nim b/tests/parser/tdotlikeoperators.nim
new file mode 100644
index 000000000..c2d23bd15
--- /dev/null
+++ b/tests/parser/tdotlikeoperators.nim
@@ -0,0 +1,30 @@
+discard """
+  matrix: "-d:nimPreviewDotLikeOps"
+"""
+# test for https://github.com/nim-lang/RFCs/issues/341
+import std/json
+import std/jsonutils
+import std/macros
+
+macro fn1(a: untyped): string = newLit a.lispRepr
+
+doAssert fn1(a.?b.c) == """(DotExpr (Infix (Ident ".?") (Ident "a") (Ident "b")) (Ident "c"))"""
+
+template `.?`(a: JsonNode, b: untyped{ident}): JsonNode =
+  a[astToStr(b)]
+
+proc identity[T](a: T): T = a
+proc timesTwo[T](a: T): T = a * 2
+
+template main =
+  let a = (a1: 1, a2: "abc", a3: (a4: 2.5))
+  let j = a.toJson
+  doAssert j.?a1.getInt == 1
+  doAssert j.?a3.?a4.getFloat == 2.5
+  doAssert j.?a3.?a4.getFloat.timesTwo == 5.0
+  doAssert j.?a3.identity.?a4.getFloat.timesTwo == 5.0
+  doAssert j.identity.?a3.identity.?a4.identity.getFloat.timesTwo == 5.0
+  doAssert j.identity.?a3.?a4.identity.getFloat.timesTwo == 5.0
+
+static: main()
+main()
diff --git a/tests/parser/tdoublenotnil.nim b/tests/parser/tdoublenotnil.nim
new file mode 100644
index 000000000..c61008c54
--- /dev/null
+++ b/tests/parser/tdoublenotnil.nim
@@ -0,0 +1,3 @@
+when false:
+  type Foo = Bar not nil not nil #[tt.Error
+                         ^ invalid indentation]#
diff --git a/tests/parser/tifexprs.nim b/tests/parser/tifexprs.nim
new file mode 100644
index 000000000..3a7e2bddc
--- /dev/null
+++ b/tests/parser/tifexprs.nim
@@ -0,0 +1,12 @@
+discard """
+  output: '''
+1
+'''
+"""
+
+var a, b: int
+let x = if a > b:
+    0
+    else: 1
+
+echo x
diff --git a/tests/parser/tifextracolon.nim b/tests/parser/tifextracolon.nim
new file mode 100644
index 000000000..171569111
--- /dev/null
+++ b/tests/parser/tifextracolon.nim
@@ -0,0 +1,8 @@
+# issue #21982
+
+if true:
+  if true:
+    discard default int:
+else: #[tt.Error
+^ invalid indentation]#
+  discard
diff --git a/tests/parser/tinvcolonlocation1.nim b/tests/parser/tinvcolonlocation1.nim
new file mode 100644
index 000000000..7fca5deb7
--- /dev/null
+++ b/tests/parser/tinvcolonlocation1.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "expected: ':', but got: 'echo'"
+  file: "tinvcolonlocation1.nim"
+  line: 8
+  column: 7
+"""
+try #<- missing ':'
+  echo "try"
+except:
+  echo "except"
+finally:
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation2.nim b/tests/parser/tinvcolonlocation2.nim
new file mode 100644
index 000000000..e3de393b8
--- /dev/null
+++ b/tests/parser/tinvcolonlocation2.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "expected: ':', but got: 'keyword finally'"
+  file: "tinvcolonlocation2.nim"
+  line: 11
+  column: 8
+"""
+try:
+  echo "try"
+except #<- missing ':'
+  echo "except"
+finally:
+#<-- error will be here above, at the beginning of finally,
+#    since compiler tries to consome echo and part of except
+#    expression
+  echo "finally"
diff --git a/tests/parser/tinvcolonlocation3.nim b/tests/parser/tinvcolonlocation3.nim
new file mode 100644
index 000000000..46252f24e
--- /dev/null
+++ b/tests/parser/tinvcolonlocation3.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "expected: ':', but got: 'echo'"
+  file: "tinvcolonlocation3.nim"
+  line: 12
+  column: 7
+"""
+try:
+  echo "try"
+except:
+  echo "except"
+finally #<- missing ':'
+  echo "finally"
diff --git a/tests/parser/tinvifstmt.nim b/tests/parser/tinvifstmt.nim
new file mode 100644
index 000000000..0455bce60
--- /dev/null
+++ b/tests/parser/tinvifstmt.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 9
+  column: 3
+"""
+
+if true:
+    echo "a"
+  elif:
+    echo "b"
+ else:
+   echo "c"
diff --git a/tests/tinvwhen.nim b/tests/parser/tinvwhen.nim
index 8dc8cbf50..7a47f69a4 100755..100644
--- a/tests/tinvwhen.nim
+++ b/tests/parser/tinvwhen.nim
@@ -1,8 +1,13 @@
-# This was parsed even though it should not!

-

-proc chdir(path: CString): cint {.importc: "chdir", header: "dirHeader".}

-

-proc getcwd(buf: CString, buflen: cint): CString

-    when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation

-    elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}

-    else: {.error: "os library not ported to your OS. Please help!".}

+discard """
+  errormsg: "invalid indentation"
+  file: "tinvwhen.nim"
+  line: 11
+"""
+# This was parsed even though it should not!
+
+proc chdir(path: cstring): cint {.importc: "chdir", header: "dirHeader".}
+
+proc getcwd(buf: cstring, buflen: cint): cstring
+    when defined(unix): {.importc: "getcwd", header: "<unistd.h>".} #ERROR_MSG invalid indentation
+    elif defined(windows): {.importc: "getcwd", header: "<direct.h>"}
+    else: {.error: "os library not ported to your OS. Please help!".}
diff --git a/tests/parser/tletcolon.nim b/tests/parser/tletcolon.nim
new file mode 100644
index 000000000..a2dde148a
--- /dev/null
+++ b/tests/parser/tletcolon.nim
@@ -0,0 +1,75 @@
+discard """
+  output: '''boo
+3
+44 3
+more body code
+yes
+yes
+block expression works'''
+"""
+
+template x(body): untyped =
+  body
+  44
+
+template y(val, body): untyped =
+  body
+  val
+
+proc mana =
+  let foo = x:
+    echo "boo"
+  var foo2: int
+  foo2 = y 3:
+    echo "3"
+  echo foo, " ", foo2
+
+mana()
+let other = x:
+  echo "more body code"
+  if true:
+    echo "yes"
+  else:
+    echo "no"
+let outer = y(5):
+  echo "yes"
+
+
+# bug #6609
+type
+  TextureInternalFormat = enum RED, RGB, RGBA
+
+const channels = 4
+
+let format =
+    if channels == 1:
+        TextureInternalFormat.RED
+    elif channels == 3:
+        TextureInternalFormat.RGB
+    elif channels == 4:
+        TextureInternalFormat.RGBA
+    else:
+        echo "Texture Format Unknown, assuming RGB"  #This echo causes an error
+        TextureInternalFormat.RGB
+
+# Block as expressions #3827
+block:
+  let x = block:
+    var y = 2
+    echo "block expression works"
+    y*y
+  doAssert x == 4
+
+
+# bug 10861
+macro foo(a: untyped): untyped = 
+  a             
+
+let c1 = foo:
+  1 + 1
+
+const c2 = foo:
+  1 + 1
+
+const c3 = 
+  foo: 1 + 1
diff --git a/tests/parser/tmultiline_comments.nim b/tests/parser/tmultiline_comments.nim
new file mode 100644
index 000000000..7a3bb5304
--- /dev/null
+++ b/tests/parser/tmultiline_comments.nim
@@ -0,0 +1,64 @@
+discard """
+  output: '''3'''
+"""
+
+proc main* =
+  ##[Mutltie akdlsf comment with #[nesting].
+  Yay, that is so cool.
+  ]##
+  echo "foo bar"
+  for s in ["one", "two", #["three",]# "four"]:
+    echo s
+
+var foo #[ Test the new inline comments ]#: int = 3
+##[ A
+novel documentation comment
+#[Nesting works to some extend]
+##[ Nested doc comment! ]##
+]#
+]##
+echo $foo
+
+  #[Comment here.
+  Multiple lines
+  are not a problem.]#
+
+  #[  #[ Multiline comment in already
+     commented out code. ]#
+  proc p[T](x: T) = discard
+  ]#
+
+proc bar =
+  ##[Long documentation comment
+  here.
+  ]##
+
+
+proc write(a: auto, x: varargs[string, `$`]) =
+  stdout.write ($a)
+  for o in x:
+    stdout.write(o)
+
+proc writeln(a: auto, x: varargs[string, `$`]) =
+  write a, x
+  stdout.write "\n"
+
+proc write() = write(stdout)
+proc writeln() =
+  stdout.write "\n"
+
+#[  #[ Multiline comment in already
+   commented out code. ]#
+proc p[T](x: T) = discard
+]#
+
+var hello = #[(x in bar)^^ "Hello" # greetings
+]#"Hello"
+proc maino =
+  write hello, " Test Me "
+  writeln()
+  write 3
+  block:
+    write()
+    write " times more"
+  #[ test ]#  writeln " Again"
diff --git a/tests/parser/toprprec.nim b/tests/parser/toprprec.nim
new file mode 100644
index 000000000..e6a43d42e
--- /dev/null
+++ b/tests/parser/toprprec.nim
@@ -0,0 +1,37 @@
+discard """
+  output: "done"
+"""
+# Test operator precedence:
+
+template `@@` (x: untyped): untyped =
+  `self`.x
+
+template `@!` (x: untyped): untyped = x
+template `===` (x: untyped): untyped = x
+
+type
+  TO = object
+    x: int
+  TA = tuple[a, b: int, obj: TO]
+
+proc init(self: var TA): string =
+  @@a = 3
+  === @@b = 4
+  @@obj.x = 4
+  @! === result = "abc"
+  result = @@b.`$`
+
+assert 3+5*5-2 == 28- -26-28
+
+proc `^-` (x, y: int): int =
+  # now right-associative!
+  result = x - y
+
+assert 34 ^- 6 ^- 2 == 30
+assert 34 - 6 - 2 == 26
+
+
+var s: TA
+assert init(s) == "4"
+
+echo "done"
diff --git a/tests/parser/tpostexprblocks.nim b/tests/parser/tpostexprblocks.nim
new file mode 100644
index 000000000..6cd4a8350
--- /dev/null
+++ b/tests/parser/tpostexprblocks.nim
@@ -0,0 +1,668 @@
+discard """
+nimout: '''
+StmtList
+  Ident "foo010"
+  Call
+    Ident "foo020"
+  Call
+    Ident "foo030"
+    Ident "x"
+  Command
+    Ident "foo040"
+    Ident "x"
+  Call
+    Ident "foo050"
+    StmtList
+      DiscardStmt
+        Empty
+  Call
+    Ident "foo060"
+    StmtList
+      DiscardStmt
+        Empty
+  Call
+    Ident "foo070"
+    StrLit "test"
+    StmtList
+      DiscardStmt
+        Empty
+  Call
+    Ident "foo080"
+    StrLit "test"
+    StmtList
+      DiscardStmt
+        Empty
+  Command
+    Ident "foo090"
+    StrLit "test"
+    StmtList
+      DiscardStmt
+        Empty
+  Command
+    Ident "foo100"
+    Call
+      StrLit "test"
+      StmtList
+        DiscardStmt
+          Empty
+  Command
+    Ident "foo101"
+    Call
+      IntLit 10
+      StmtList
+        DiscardStmt
+          Empty
+  Command
+    Ident "foo110"
+    IntLit 1
+    Par
+      Infix
+        Ident "+"
+        IntLit 2
+        IntLit 3
+    StmtList
+      DiscardStmt
+        Empty
+  Command
+    Ident "foo120"
+    IntLit 1
+    Call
+      Par
+        Infix
+          Ident "+"
+          IntLit 2
+          IntLit 3
+      StmtList
+        DiscardStmt
+          Empty
+  Call
+    Ident "foo130"
+    Do
+      Empty
+      Empty
+      Empty
+      FormalParams
+        Empty
+        IdentDefs
+          Ident "x"
+          Empty
+          Empty
+      Empty
+      Empty
+      StmtList
+        DiscardStmt
+          Empty
+  Call
+    Ident "foo140"
+    Do
+      Empty
+      Empty
+      Empty
+      FormalParams
+        Empty
+        IdentDefs
+          Ident "x"
+          Ident "int"
+          Empty
+      Empty
+      Empty
+      StmtList
+        DiscardStmt
+          Empty
+  Call
+    Ident "foo150"
+    Do
+      Empty
+      Empty
+      Empty
+      FormalParams
+        Ident "int"
+        IdentDefs
+          Ident "x"
+          Ident "int"
+          Empty
+      Empty
+      Empty
+      StmtList
+        DiscardStmt
+          Empty
+  Command
+    Ident "foo160"
+    Call
+      Ident "x"
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Empty
+          IdentDefs
+            Ident "y"
+            Empty
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+  Call
+    Ident "foo170"
+    StmtList
+      DiscardStmt
+        Empty
+    Else
+      StmtList
+        DiscardStmt
+          Empty
+  Call
+    Ident "foo180"
+    StmtList
+      DiscardStmt
+        Empty
+    StmtList
+      DiscardStmt
+        Empty
+    Else
+      StmtList
+        DiscardStmt
+          Empty
+  Command
+    Ident "foo190"
+    Call
+      Ident "x"
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Empty
+          IdentDefs
+            Ident "y"
+            Empty
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Ident "int"
+          IdentDefs
+            Ident "z"
+            Empty
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Ident "int"
+          IdentDefs
+            Ident "w"
+            Ident "int"
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+      StmtList
+        DiscardStmt
+          Empty
+      Else
+        StmtList
+          DiscardStmt
+            Empty
+  Call
+    Ident "foo200"
+    Ident "x"
+    Call
+      Ident "bar"
+      StmtList
+        DiscardStmt
+          Empty
+      Else
+        StmtList
+          DiscardStmt
+            Empty
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Ident "foo210"
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Call
+        Ident "foo220"
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Call
+        Ident "foo230"
+        Ident "x"
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Command
+        Ident "foo240"
+        Ident "x"
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Call
+        Ident "foo250"
+        StmtList
+          DiscardStmt
+            Empty
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Call
+        Ident "foo260"
+        StmtList
+          DiscardStmt
+            Empty
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Call
+        Ident "foo270"
+        StmtList
+          DiscardStmt
+            Empty
+        Else
+          StmtList
+            DiscardStmt
+              Empty
+  VarSection
+    IdentDefs
+      Ident "a"
+      Empty
+      Command
+        Ident "foo280"
+        Call
+          Ident "x"
+          Do
+            Empty
+            Empty
+            Empty
+            FormalParams
+              Empty
+              IdentDefs
+                Ident "y"
+                Empty
+                Empty
+            Empty
+            Empty
+            StmtList
+              DiscardStmt
+                Empty
+          Else
+            StmtList
+              DiscardStmt
+                Empty
+  Asgn
+    Ident "a"
+    Ident "foo290"
+  Asgn
+    Ident "a"
+    Call
+      Ident "foo300"
+  Asgn
+    Ident "a"
+    Call
+      Ident "foo310"
+      Ident "x"
+  Asgn
+    Ident "a"
+    Command
+      Ident "foo320"
+      Ident "x"
+  Asgn
+    Ident "a"
+    Call
+      Ident "foo330"
+      StmtList
+        DiscardStmt
+          Empty
+  Asgn
+    Ident "a"
+    Call
+      Ident "foo340"
+      StmtList
+        DiscardStmt
+          Empty
+  Asgn
+    Ident "a"
+    Call
+      Ident "foo350"
+      StmtList
+        DiscardStmt
+          Empty
+      Else
+        StmtList
+          DiscardStmt
+            Empty
+  Asgn
+    Ident "a"
+    Command
+      Ident "foo360"
+      Call
+        DotExpr
+          Ident "x"
+          Ident "bar"
+        Do
+          Empty
+          Empty
+          Empty
+          FormalParams
+            Empty
+            IdentDefs
+              Ident "y"
+              Empty
+              Empty
+          Empty
+          Empty
+          StmtList
+            DiscardStmt
+              Empty
+        Else
+          StmtList
+            DiscardStmt
+              Empty
+  Command
+    DotExpr
+      Ident "foo370"
+      Ident "add"
+    Call
+      Ident "quote"
+      StmtList
+        DiscardStmt
+          Empty
+  Call
+    DotExpr
+      Ident "foo380"
+      Ident "add"
+    BracketExpr
+      Call
+        Ident "quote"
+        StmtList
+          DiscardStmt
+            Empty
+      IntLit 0
+  Command
+    Ident "foo390"
+    Call
+      Ident "x"
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Empty
+          IdentDefs
+            Ident "y"
+            Empty
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Ident "int"
+          IdentDefs
+            Ident "z"
+            Empty
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+      Do
+        Empty
+        Empty
+        Empty
+        FormalParams
+          Ident "int"
+          IdentDefs
+            Ident "w"
+            Ident "int"
+            Empty
+        Empty
+        Empty
+        StmtList
+          DiscardStmt
+            Empty
+      StmtList
+        DiscardStmt
+          Empty
+      OfBranch
+        Ident "a"
+        StmtList
+          DiscardStmt
+            Empty
+      OfBranch
+        TupleConstr
+          Ident "a"
+          Ident "b"
+        StmtList
+          DiscardStmt
+            Empty
+      ElifBranch
+        Ident "a"
+        StmtList
+          DiscardStmt
+            Empty
+      ElifBranch
+        TupleConstr
+          Ident "a"
+          Ident "b"
+        StmtList
+          DiscardStmt
+            Empty
+      ExceptBranch
+        Ident "a"
+        StmtList
+          DiscardStmt
+            Empty
+      ExceptBranch
+        TupleConstr
+          Ident "a"
+          Ident "b"
+        StmtList
+          DiscardStmt
+            Empty
+      Finally
+        StmtList
+          DiscardStmt
+            Empty
+
+  Call
+    Ident "foo"
+    Finally
+      StmtList
+        DiscardStmt
+          Empty
+'''
+"""
+
+import macros
+
+dumpTree:
+  # simple calls
+  foo010
+  foo020()
+  foo030(x)
+  foo040 x
+
+  foo050:
+    discard
+
+  foo060 do:
+    discard
+
+  foo070("test"):
+    discard
+
+  foo080("test") do:
+    discard
+
+  foo090 "test":
+    discard
+
+  foo100 "test" do:
+    discard
+
+  foo101 10 do:
+    discard
+
+  # more complicated calls
+  foo110 1, (2+3):
+    discard
+
+  foo120 1, (2+3) do:
+    discard
+
+  foo130 do (x):
+    discard
+
+  foo140 do (x: int):
+    discard
+
+  foo150 do (x: int) -> int:
+    discard
+
+  foo160 x do (y):
+    discard
+
+  # extra blocks
+  foo170:
+    discard
+  else:
+    discard
+
+  foo180 do:
+    discard
+  do:
+    discard
+  else:
+    discard
+
+  foo190 x do (y):
+    discard
+  do (z) -> int:
+    discard
+  do (w: int) -> int:
+    discard
+  do:
+    discard
+  else:
+    discard
+
+  # call with blocks as a param
+  foo200(x, bar do:
+    discard
+  else:
+    discard
+  )
+
+  # introduce a variable
+  var a = foo210
+  var a = foo220()
+  var a = foo230(x)
+  var a = foo240 x
+
+  var a = foo250:
+    discard
+
+  var a = foo260 do:
+    discard
+
+  var a = foo270 do:
+    discard
+  else:
+    discard
+
+  var a = foo280 x do (y):
+    discard
+  else:
+    discard
+
+  # assignments
+  a = foo290
+  a = foo300()
+  a = foo310(x)
+  a = foo320 x
+
+  a = foo330:
+    discard
+
+  a = foo340 do:
+    discard
+
+  a = foo350 do:
+    discard
+  else:
+    discard
+
+  a = foo360 x.bar do (y):
+    discard
+  else:
+    discard
+
+  foo370.add quote do:
+    discard
+
+  # some edge cases
+  foo380.add((quote do:
+    discard
+  )[0])
+
+  foo390 x do (y):
+    discard
+  do (z) -> int:
+    discard
+  do (w: int) -> int:
+    discard
+  do:
+    discard
+  of a:
+    discard
+  of (a, b):
+    discard
+  elif a:
+    discard
+  elif (a, b):
+    discard
+  except a:
+    discard
+  except (a, b):
+    discard
+  finally:
+    discard
+
+  foo:
+  finally:
+    discard
diff --git a/tests/parser/tprecedence.nim b/tests/parser/tprecedence.nim
new file mode 100644
index 000000000..9be79543b
--- /dev/null
+++ b/tests/parser/tprecedence.nim
@@ -0,0 +1,63 @@
+discard """
+  output: '''holla
+true
+defabc 4
+0'''
+"""
+
+# Test top level semicolon works properly:
+import os; echo "holla"
+
+# Test the new predence rules
+
+proc `\+` (x, y: int): int = result = x + y
+proc `\*` (x, y: int): int = result = x * y
+
+echo 5 \+ 1 \* 9 == 6*9
+
+proc foo[S, T](x: S, y: T): T = x & y
+
+proc bar[T](x: T): T = x
+
+echo "def".foo[:string, string]("abc"), " ", 4.bar[:int]
+
+# bug #9574
+proc isFalse(a: int): bool = false
+
+assert not isFalse(3)
+
+# bug #9633
+
+type
+  MyField = object
+    b: seq[string]
+
+  MyObject = object
+    f: MyField
+
+proc getX(x: MyObject): lent MyField {.inline.} =
+  x.f
+
+let a = MyObject()
+echo a.getX.b.len
+
+
+# bug  #10458
+template t(x: untyped): untyped = "x"
+
+let
+  aaa = t 2 + 4
+  ccc = t (1, 1) + 6
+  ddd = t [0, 1, 2] + 5
+
+# bug #10896
+const
+  test =
+    proc(): int = 1
+
+# bug #8759
+block:
+  template `=>`(a, b): untyped = (a, b)
+  template `+=`(a, b): untyped = a * b
+
+  doAssert ("abc" => 3 += 5) == ("abc", 15)
diff --git a/tests/parser/tprocexprasstmt.nim b/tests/parser/tprocexprasstmt.nim
new file mode 100644
index 000000000..22fb4a7c8
--- /dev/null
+++ b/tests/parser/tprocexprasstmt.nim
@@ -0,0 +1,14 @@
+func r(): auto =
+  func(): int = 2
+doAssert r()() == 2
+
+block: # issue #11726
+  let foo = block:
+    var x: int
+    proc = inc x # "identifier expected, but got '='"
+
+  template paint(): untyped =
+    proc (s: string): string = s
+
+  let s = paint()
+  doAssert s("abc") == "abc"
diff --git a/tests/parser/tproctype_pragmas.nim b/tests/parser/tproctype_pragmas.nim
new file mode 100644
index 000000000..8c7acd0cf
--- /dev/null
+++ b/tests/parser/tproctype_pragmas.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''39
+40'''
+"""
+
+# bug 1802
+# Ensure proc pragmas are attached properly:
+
+proc makeStdcall(s: string): (proc(i: int) {.stdcall.}) =
+  (proc (x: int) {.stdcall.} = echo x)
+
+proc makeNimcall(s: string): (proc(i: int)) {.stdcall.} =
+  (proc (x: int) {.nimcall.} = echo x)
+
+let stdc: proc (y: int) {.stdcall.} = makeStdcall("bu")
+let nimc: proc (y: int) {.closure.} = makeNimcall("ba")
+
+stdc(39)
+nimc(40)
diff --git a/tests/parser/tstatementoperators.nim b/tests/parser/tstatementoperators.nim
new file mode 100644
index 000000000..d2b85bb4b
--- /dev/null
+++ b/tests/parser/tstatementoperators.nim
@@ -0,0 +1,12 @@
+discard """
+  nimout: '''
+Infix
+  Ident "from"
+  Ident "a"
+  Ident "b"
+'''
+"""
+
+from macros import dumpTree
+
+dumpTree(a from b)
\ No newline at end of file
diff --git a/tests/parser/tstmtlists.nim b/tests/parser/tstmtlists.nim
new file mode 100644
index 000000000..158c93340
--- /dev/null
+++ b/tests/parser/tstmtlists.nim
@@ -0,0 +1,180 @@
+discard """
+  output: '''
+2
+2
+2
+2
+2
+2
+2
+2
+2
+2
+hello
+1
+hello
+2
+hello
+3
+hello
+4
+hello
+5
+hello
+6
+hello
+7
+hello
+8
+hello
+9
+hello
+10
+hello
+1
+hello
+2
+hello
+3
+hello
+4
+hello
+5
+hello
+6
+hello
+7
+hello
+8
+hello
+9
+hello
+10
+lucky
+lucky
+'''
+"""
+
+block: (
+  discard;
+  echo 1 + 1;
+  )
+
+block: (
+  discard; #Haha
+    #haha
+  echo 1 + 1;
+)
+
+block: (
+  discard;
+  #Hmm
+  echo 1 +
+    1;
+)
+
+block: (
+  discard
+  echo "2"
+)
+
+block: (
+  discard;
+  echo 1 +
+    1
+)
+
+block: (
+  discard
+  echo 1 +
+    1
+)
+
+block: (
+  discard;
+  discard
+)
+
+block: (
+  discard
+  echo 1 + 1;
+  )
+
+block: (
+  discard
+  echo 1 + 1;
+)
+
+block: (
+  discard
+  echo 1 +
+    1;
+)
+
+block: (
+  discard;
+    )
+
+block: ( discard; echo 1 + #heh
+                         1;
+)
+
+for i in 1..10:
+    echo "hello"
+    echo i
+
+for i in 1..10: (
+    echo "hello";
+    echo i;
+)
+
+proc square(inSeq: seq[float]): seq[float] = (
+  result = newSeq[float](len(inSeq));
+  for i, v in inSeq: (
+    result[i] = v * v;
+  )
+)
+
+proc square2(inSeq: seq[float]): seq[float] =
+  result = newSeq[float](len(inSeq));
+  for i, v in inSeq: (
+    result[i] = v * v;
+  )
+
+proc cstringCheck(tracked: int; n: int) =
+  if true == false and (let a = high(int); let b = high(int);
+      a.int8 == 8 and a.int8 notin {3..9}):
+    echo(tracked, n)
+
+template dim: int =
+  (if int.high == 0:
+    int.high
+  else:
+    int.high)
+
+template dim2: int =
+  (if int.high == 0:
+    int.high
+   else:
+    int.high)
+
+template dim3: int =
+  (
+   if int.high == 0:
+     int.high
+   else:
+     int.high)
+
+# lenient indentation:
+
+echo (if 0 == 1:
+  "0 == 1"
+else:
+  "lucky")
+
+# bug #16426
+echo (when 0 == 1:
+  "0 == 1"
+else:
+  "lucky")
+
diff --git a/tests/parser/ttry.nim b/tests/parser/ttry.nim
new file mode 100644
index 000000000..190b0b8dc
--- /dev/null
+++ b/tests/parser/ttry.nim
@@ -0,0 +1,27 @@
+# bug #21144
+block:
+  try:
+    let c = try:
+        10
+      except ValueError as exc:
+        10
+  except ValueError as exc:
+    discard
+
+if true:
+  block:
+    let c = try:
+          10
+        except ValueError as exc:
+          10
+    except OSError:
+      99
+
+
+try:
+  let c = try:
+    10
+  except ValueError as exc:
+    10
+except ValueError as exc:
+  discard
\ No newline at end of file
diff --git a/tests/parser/ttupleunpack.nim b/tests/parser/ttupleunpack.nim
new file mode 100644
index 000000000..993501fbb
--- /dev/null
+++ b/tests/parser/ttupleunpack.nim
@@ -0,0 +1,94 @@
+proc returnsTuple(): (int, int, int) = (4, 2, 3)
+
+proc main2 =
+  let (x, _, z) = returnsTuple()
+
+proc main() =
+
+  proc foo(): tuple[x, y, z: int] =
+    return (4, 2, 3)
+
+  var (x, _, y) = foo()
+  doAssert x == 4
+  doAssert y == 3
+
+  var (a, _, _) = foo()
+  doAssert a == 4
+
+  var (aa, _, _) = foo()
+  doAssert aa == 4
+
+  iterator bar(): tuple[x, y, z: int] =
+    yield (1,2,3)
+
+  for x, y, _ in bar():
+    doAssert x == 1
+    doAssert y == 2
+
+main()
+main2()
+
+block: # nested unpacking
+  block: # simple let
+    let (a, (b, c), d) = (1, (2, 3), 4)
+    doAssert (a, b, c, d) == (1, 2, 3, 4)
+    let foo = (a, (b, c), d)
+    let (a2, (b2, c2), d2) = foo
+    doAssert (a, b, c, d) == (a2, b2, c2, d2)
+
+  block: # var and assignment
+    var (x, (y, z), t) = ('a', (true, @[123]), "abc")
+    doAssert (x, y, z, t) == ('a', true, @[123], "abc")
+    (x, (y, z), t) = ('b', (false, @[456]), "def")
+    doAssert (x, y, z, t) == ('b', false, @[456], "def")
+
+  block: # very nested
+    let (_, (_, (_, (_, (_, a))))) = (1, (2, (3, (4, (5, 6)))))
+    doAssert a == 6
+
+  block: # const
+    const (a, (b, c), d) = (1, (2, 3), 4)
+    doAssert (a, b, c, d) == (1, 2, 3, 4)
+    const foo = (a, (b, c), d)
+    const (a2, (b2, c2), d2) = foo
+    doAssert (a, b, c, d) == (a2, b2, c2, d2)
+  
+  block: # evaluation semantics preserved between literal and not literal
+    var s: seq[string]
+    block: # literal
+      let (a, (b, c), d) = ((s.add("a"); 1), ((s.add("b"); 2), (s.add("c"); 3)), (s.add("d"); 4))
+      doAssert (a, b, c, d) == (1, 2, 3, 4)
+      doAssert s == @["a", "b", "c", "d"]
+    block: # underscore
+      s = @[]
+      let (a, (_, c), _) = ((s.add("a"); 1), ((s.add("b"); 2), (s.add("c"); 3)), (s.add("d"); 4))
+      doAssert (a, c) == (1, 3)
+      doAssert s == @["a", "b", "c", "d"]
+    block: # temp
+      s = @[]
+      let foo = ((s.add("a"); 1), ((s.add("b"); 2), (s.add("c"); 3)), (s.add("d"); 4))
+      let (a, (b, c), d) = foo
+      doAssert (a, b, c, d) == (1, 2, 3, 4)
+      doAssert s == @["a", "b", "c", "d"]
+
+block: # unary assignment unpacking
+  var a: int
+  (a,) = (1,)
+  doAssert a == 1
+
+block: # type annotations
+  block: # basic
+    let (a, b): (int, int) = (1, 2)
+    doAssert (a, b) == (1, 2)
+  block: # type inference
+    let (a, b): (byte, float) = (1, 2)
+    doAssert (a, b) == (1.byte, 2.0)
+  block: # type mismatch
+    doAssert not (compiles do:
+      let (a, b): (int, string) = (1, 2))
+  block: # nested
+    let (a, (b, c)): (int, (int, int)) = (1, (2, 3))
+    doAssert (a, b, c) == (1, 2, 3)
+  block: # nested type inference
+    let (a, (b, c)): (byte, (float, cstring)) = (1, (2, "abc"))
+    doAssert (a, b, c) == (1.byte, 2.0, cstring"abc")
diff --git a/tests/parser/ttypeclasses.nim b/tests/parser/ttypeclasses.nim
new file mode 100644
index 000000000..e6e7a48b8
--- /dev/null
+++ b/tests/parser/ttypeclasses.nim
@@ -0,0 +1,46 @@
+type
+    R = ref
+    V = var
+    D = distinct
+    P = ptr
+    T = type
+    S = static
+    OBJ = object
+    TPL = tuple
+    SEQ = seq
+
+var i: int
+var x: ref int
+var y: distinct int
+var z: ptr int
+const C = @[1, 2, 3]
+
+static:
+  doAssert x is ref
+  doAssert y is distinct
+  doAssert z is ptr
+  doAssert C is static
+  doAssert C[1] is static[int]
+  doAssert C[0] is static[SomeInteger]
+  doAssert C isnot static[string]
+  doAssert C is SEQ|OBJ
+  doAssert C isnot OBJ|TPL
+  doAssert int is int
+  doAssert int is T
+  doAssert int is SomeInteger
+  doAssert seq[int] is type
+  doAssert seq[int] is type[seq]
+  doAssert seq[int] isnot type[seq[float]]
+  doAssert i isnot type[int]
+  doAssert type(i) is type[int]
+  doAssert x isnot T
+  doAssert y isnot S
+  doAssert z isnot enum
+  doAssert x isnot object
+  doAssert y isnot tuple
+  doAssert z isnot seq
+
+  # XXX: These cases don't work properly at the moment:
+  # doAssert type[int] isnot int
+  # doAssert type(int) isnot int
+
diff --git a/tests/parser/ttypecommandcomma.nim b/tests/parser/ttypecommandcomma.nim
new file mode 100644
index 000000000..7ca59a799
--- /dev/null
+++ b/tests/parser/ttypecommandcomma.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 8
+  column: 19
+"""
+
+type
+  Foo = call(1, 2), 3:
+    4
\ No newline at end of file
diff --git a/tests/parser/ttypecommandindent1.nim b/tests/parser/ttypecommandindent1.nim
new file mode 100644
index 000000000..9aa274e2a
--- /dev/null
+++ b/tests/parser/ttypecommandindent1.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 9
+  column: 3
+"""
+
+type
+  Foo = call x, y, z:
+  abc
diff --git a/tests/parser/ttypecommandindent2.nim b/tests/parser/ttypecommandindent2.nim
new file mode 100644
index 000000000..0883df90f
--- /dev/null
+++ b/tests/parser/ttypecommandindent2.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 10
+  column: 5
+"""
+
+type
+  Foo = call x, y, z:
+      abc
+    do:
+        def
diff --git a/tests/parser/ttypecommandindent3.nim b/tests/parser/ttypecommandindent3.nim
new file mode 100644
index 000000000..f9fdcc1e4
--- /dev/null
+++ b/tests/parser/ttypecommandindent3.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "expression expected, but found 'keyword do'"
+  line: 10
+  column: 1
+"""
+
+type
+  Foo = call x, y, z:
+    abc
+do:
+    def
diff --git a/tests/parser/ttypeexprobject.nim b/tests/parser/ttypeexprobject.nim
new file mode 100644
index 000000000..6895f1731
--- /dev/null
+++ b/tests/parser/ttypeexprobject.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "invalid indentation"
+  line: 10
+  column: 14
+"""
+
+type
+  A = (object | tuple | int)
+  B = int | object | tuple
+  C = object | tuple | int # issue #8846
diff --git a/tests/parser/ttypeexprs.nim b/tests/parser/ttypeexprs.nim
new file mode 100644
index 000000000..e40efc7d9
--- /dev/null
+++ b/tests/parser/ttypeexprs.nim
@@ -0,0 +1,25 @@
+proc foo[T: ptr int | ptr string](x: T) = discard
+var x = "abc"
+foo(addr x)
+
+let n = 3'u32
+type Double = (
+  when n.sizeof == 4: uint64
+  elif n.sizeof == 2: uint32
+  else: uint16
+)
+
+type
+  A = (ref | ptr | pointer)
+  B = pointer | ptr | ref
+  C = ref | ptr | pointer
+
+template `+`(a, b): untyped = (b, a)
+template `*`(a, b): untyped = (a, b)
+
+doAssert (ref int + ref float * ref string + ref bool) is
+  (ref bool, ((ref float, ref string), ref int))
+type X = ref int + ref float * ref string + ref bool
+doAssert X is (ref bool, ((ref float, ref string), ref int))
+
+type SomePointer = proc | ref | ptr | pointer
diff --git a/tests/parser/ttypemodifiers.nim b/tests/parser/ttypemodifiers.nim
new file mode 100644
index 000000000..9a1ccb1a5
--- /dev/null
+++ b/tests/parser/ttypemodifiers.nim
@@ -0,0 +1,526 @@
+discard """
+nimout: '''
+StmtList
+  TypeSection
+    TypeDef
+      Ident "BarePtr"
+      Empty
+      PtrTy
+    TypeDef
+      Ident "GenericPtr"
+      Empty
+      PtrTy
+        Bracket
+          Ident "int"
+    TypeDef
+      Ident "PrefixPtr"
+      Empty
+      PtrTy
+        Ident "int"
+    TypeDef
+      Ident "PtrTuple"
+      Empty
+      PtrTy
+        TupleConstr
+          Ident "int"
+          Ident "string"
+    TypeDef
+      Ident "BareRef"
+      Empty
+      RefTy
+    TypeDef
+      Ident "GenericRef"
+      Empty
+      RefTy
+        Bracket
+          Ident "int"
+    TypeDef
+      Ident "RefTupleCl"
+      Empty
+      RefTy
+        TupleTy
+    TypeDef
+      Ident "RefTupleType"
+      Empty
+      RefTy
+        TupleConstr
+          Ident "int"
+          Ident "string"
+    TypeDef
+      Ident "RefTupleVars"
+      Empty
+      RefTy
+        TupleConstr
+          Ident "a"
+          Ident "b"
+    TypeDef
+      Ident "BareStatic"
+      Empty
+      Ident "static"
+    TypeDef
+      Ident "GenericStatic"
+      Empty
+      BracketExpr
+        Ident "static"
+        Ident "int"
+    TypeDef
+      Ident "PrefixStatic"
+      Empty
+      Command
+        Ident "static"
+        Ident "int"
+    TypeDef
+      Ident "StaticTupleCl"
+      Empty
+      Command
+        Ident "static"
+        TupleClassTy
+    TypeDef
+      Ident "StaticTuple"
+      Empty
+      Command
+        Ident "static"
+        TupleConstr
+          Ident "int"
+          Ident "string"
+    TypeDef
+      Ident "BareType"
+      Empty
+      Ident "type"
+    TypeDef
+      Ident "GenericType"
+      Empty
+      BracketExpr
+        Ident "type"
+        Ident "float"
+    TypeDef
+      Ident "TypeTupleGen"
+      Empty
+      BracketExpr
+        Ident "type"
+        TupleClassTy
+    TypeDef
+      Ident "TypeTupleCl"
+      Empty
+      Command
+        Ident "type"
+        TupleClassTy
+    TypeDef
+      Ident "TypeInstance"
+      Empty
+      Command
+        Ident "type"
+        BracketExpr
+          Ident "Foo"
+          RefTy
+    TypeDef
+      Ident "bareTypeDesc"
+      Empty
+      Ident "typedesc"
+    TypeDef
+      Ident "TypeOfVar"
+      Empty
+      Call
+        Ident "type"
+        Ident "a"
+    TypeDef
+      Ident "TypeOfVarAlt"
+      Empty
+      Command
+        Ident "type"
+        Par
+          Ident "a"
+    TypeDef
+      Ident "TypeOfTuple1"
+      Empty
+      Call
+        Ident "type"
+        Ident "a"
+    TypeDef
+      Ident "TypeOfTuple2"
+      Empty
+      Call
+        Ident "type"
+        Ident "a"
+        Ident "b"
+    TypeDef
+      Ident "TypeOfTuple1A"
+      Empty
+      Command
+        Ident "type"
+        TupleConstr
+          Ident "a"
+    TypeDef
+      Ident "TypeOfTuple2A"
+      Empty
+      Command
+        Ident "type"
+        TupleConstr
+          Ident "a"
+          Ident "b"
+    TypeDef
+      Ident "TypeTuple"
+      Empty
+      Command
+        Ident "type"
+        TupleConstr
+          Ident "int"
+          Ident "string"
+    TypeDef
+      Ident "GenericTypedesc"
+      Empty
+      BracketExpr
+        Ident "typedesc"
+        Ident "int"
+    TypeDef
+      Ident "T"
+      Empty
+      Ident "type"
+  ProcDef
+    Ident "foo"
+    Empty
+    Empty
+    FormalParams
+      Ident "type"
+      IdentDefs
+        Ident "bareType"
+        Ident "type"
+        Empty
+      IdentDefs
+        Ident "genType"
+        BracketExpr
+          Ident "type"
+          Ident "int"
+        Empty
+      IdentDefs
+        Ident "typeInt"
+        Command
+          Ident "type"
+          Ident "int"
+        Empty
+      IdentDefs
+        Ident "typeIntAlt"
+        Call
+          Ident "type"
+          Ident "int"
+        Empty
+      IdentDefs
+        Ident "typeOfVar"
+        Call
+          Ident "type"
+          Ident "a"
+        Empty
+      IdentDefs
+        Ident "typeDotType"
+        DotExpr
+          Ident "foo"
+          Ident "type"
+        Empty
+      IdentDefs
+        Ident "typeTupleCl"
+        Command
+          Ident "type"
+          TupleClassTy
+        Empty
+      IdentDefs
+        Ident "bareStatic"
+        Ident "static"
+        Empty
+      IdentDefs
+        Ident "genStatic"
+        BracketExpr
+          Ident "static"
+          Ident "int"
+        Empty
+      IdentDefs
+        Ident "staticInt"
+        Command
+          Ident "static"
+          Ident "int"
+        Empty
+      IdentDefs
+        Ident "staticVal1"
+        Command
+          Ident "static"
+          IntLit 10
+        Empty
+      IdentDefs
+        Ident "staticVal2"
+        Call
+          Ident "static"
+          StrLit "str"
+        Empty
+      IdentDefs
+        Ident "staticVal3"
+        Command
+          Ident "static"
+          StrLit "str"
+        Empty
+      IdentDefs
+        Ident "staticVal4"
+        CallStrLit
+          Ident "static"
+          RStrLit "str"
+        Empty
+      IdentDefs
+        Ident "staticDotVal"
+        DotExpr
+          IntLit 10
+          Ident "static"
+        Empty
+      IdentDefs
+        Ident "bareRef"
+        RefTy
+        Empty
+      IdentDefs
+        Ident "refTuple1"
+        RefTy
+          Par
+            Ident "int"
+        Empty
+      IdentDefs
+        Ident "refTuple1A"
+        RefTy
+          TupleConstr
+            Ident "int"
+        Empty
+      IdentDefs
+        Ident "refTuple2"
+        RefTy
+          TupleConstr
+            Ident "int"
+            Ident "string"
+        Empty
+      IdentDefs
+        Ident "genRef"
+        RefTy
+          Bracket
+            Ident "int"
+        Empty
+      IdentDefs
+        Ident "refInt"
+        RefTy
+          Ident "int"
+        Empty
+      IdentDefs
+        Ident "refCall"
+        RefTy
+          Par
+            Ident "a"
+        Empty
+      IdentDefs
+        Ident "macroCall1"
+        Command
+          Ident "foo"
+          Ident "bar"
+        Empty
+      IdentDefs
+        Ident "macroCall2"
+        Call
+          Ident "foo"
+          Ident "bar"
+        Empty
+      IdentDefs
+        Ident "macroCall3"
+        Call
+          DotExpr
+            Ident "foo"
+            Ident "bar"
+          Ident "baz"
+        Empty
+      IdentDefs
+        Ident "macroCall4"
+        Call
+          BracketExpr
+            Ident "foo"
+            Ident "bar"
+          Ident "baz"
+        Empty
+      IdentDefs
+        Ident "macroCall5"
+        Command
+          Ident "foo"
+          Command
+            Ident "bar"
+            Ident "baz"
+        IntLit 10
+    Empty
+    Empty
+    StmtList
+      Asgn
+        Ident "staticTen"
+        Command
+          Ident "static"
+          IntLit 10
+      Asgn
+        Ident "staticA"
+        Call
+          Ident "static"
+          Ident "a"
+      Asgn
+        Ident "staticCall"
+        Command
+          Ident "static"
+          Call
+            Ident "foo"
+            IntLit 1
+      Asgn
+        Ident "staticStrCall"
+        Command
+          Ident "static"
+          CallStrLit
+            Ident "foo"
+            RStrLit "x"
+      Asgn
+        Ident "staticChainCall"
+        Command
+          Ident "static"
+          Command
+            Ident "foo"
+            Ident "bar"
+      Asgn
+        Ident "typeTen"
+        Command
+          Ident "type"
+          IntLit 10
+      Asgn
+        Ident "typeA"
+        Call
+          Ident "type"
+          Ident "a"
+      Asgn
+        Ident "typeCall"
+        Command
+          Ident "type"
+          Call
+            Ident "foo"
+            IntLit 1
+      Asgn
+        Ident "typeStrCall"
+        Command
+          Ident "type"
+          CallStrLit
+            Ident "foo"
+            RStrLit "x"
+      Asgn
+        Ident "typeChainCall"
+        Command
+          Ident "type"
+          Command
+            Ident "foo"
+            Ident "bar"
+      Asgn
+        Ident "normalChainCall"
+        Command
+          Ident "foo"
+          Command
+            Ident "bar"
+            Ident "baz"
+      Asgn
+        Ident "normalTupleCall2"
+        Call
+          Ident "foo"
+          Ident "a"
+          Ident "b"
+      StaticStmt
+        StmtList
+          Ident "singleStaticStmt"
+      StaticStmt
+        StmtList
+          Ident "staticStmtList1"
+          Ident "staticStmtList2"
+'''
+"""
+
+import macros
+
+dumpTree:
+  type
+    BarePtr       = ptr
+    GenericPtr    = ptr[int]
+    PrefixPtr     = ptr int
+    PtrTuple      = ptr (int, string)
+    BareRef       = ref
+    GenericRef    = ref[int]
+    RefTupleCl    = ref tuple
+    RefTupleType  = ref (int, string)
+    RefTupleVars  = ref (a, b)
+    BareStatic    = static                # Used to be Error: invalid indentation
+    GenericStatic = static[int]
+    PrefixStatic  = static int
+    StaticTupleCl = static tuple
+    StaticTuple   = static (int, string)
+    BareType      = type
+    GenericType   = type[float]
+    TypeTupleGen  = type[tuple]
+    TypeTupleCl   = type tuple            # Used to be Error: invalid indentation
+    TypeInstance  = type Foo[ref]
+    bareTypeDesc  = typedesc
+    TypeOfVar     = type(a)
+    TypeOfVarAlt  = type (a)              # Used to be Error: invalid indentation
+    TypeOfTuple1  = type(a,)
+    TypeOfTuple2  = type(a,b)
+    TypeOfTuple1A = type (a,)             # Used to be Error: invalid indentation
+    TypeOfTuple2A = type (a,b)            # Used to be Error: invalid indentation
+    TypeTuple     = type (int, string)    # Used to be Error: invalid indentation
+    GenericTypedesc = typedesc[int]
+    T = type
+
+  proc foo(
+    bareType        : type,
+    genType         : type[int],
+    typeInt         : type int,
+    typeIntAlt      : type(int),
+    typeOfVar       : type(a),
+    typeDotType     : foo.type,
+    typeTupleCl     : type tuple,         # Used to be Error: ')' expected
+    bareStatic      : static,             # Used to be Error: expression expected, but found ','
+    genStatic       : static[int],
+    staticInt       : static int,
+    staticVal1      : static 10,
+    staticVal2      : static("str"),
+    staticVal3      : static "str",
+    staticVal4      : static"str",        # Used to be Error: expression expected, but found 'str'
+    staticDotVal    : 10.static,
+    bareRef         : ref,
+    refTuple1       : ref (int),
+    refTuple1A      : ref (int,),
+    refTuple2       : ref (int,string),
+    genRef          : ref[int],
+    refInt          : ref int,
+    refCall         : ref(a),
+    macroCall1      : foo bar,
+    macroCall2      : foo(bar),
+    macroCall3      : foo.bar(baz),
+    macroCall4      : foo[bar](baz),
+    macroCall5      : foo bar baz = 10
+  ): type =
+    staticTen       = static 10
+    staticA         = static(a)
+    # staticAspace    = static (a)          # With newTypedesc: Error: invalid indentation
+    # staticAtuple    = static (a,)         # With newTypedesc: Error: invalid indentation
+    # staticTuple     = static (a,b)        # With newTypedesc: Error: invalid indentation
+    # staticTypeTuple = static (int,string) # With newTypedesc: Error: invalid indentation
+    staticCall      = static foo(1)
+    staticStrCall   = static foo"x"
+    staticChainCall = static foo bar
+
+    typeTen         = type 10
+    typeA           = type(a)
+    # typeAspace    = type (a)            # Error: invalid indentation
+    # typeAtuple    = type (a,)           # Error: invalid indentation
+    # typeTuple     = type (a,b)          # Error: invalid indentation
+    # typeTypeTuple = type (int,string)   # Error: invalid indentation
+    typeCall        = type foo(1)
+    typeStrCall     = type foo"x"
+    typeChainCall   = type foo bar
+
+    normalChainCall = foo bar baz
+    # normalTupleCall1 = foo(a,)          # Error: invalid indentation
+    normalTupleCall2 = foo(a,b)
+    # normalTupleCall3 = foo (a,b)        # Error: invalid indentation
+
+    static: singleStaticStmt
+    static:
+      staticStmtList1
+      staticStmtList2
diff --git a/tests/parser/ttypeof.nim b/tests/parser/ttypeof.nim
new file mode 100644
index 000000000..24f98059e
--- /dev/null
+++ b/tests/parser/ttypeof.nim
@@ -0,0 +1,26 @@
+discard """
+  output: '''12
+int
+int
+int'''
+"""
+
+import typetraits
+
+# bug #1805
+
+proc foob(x: int): string = "foo"
+proc barb(x: string): int = 12
+
+echo(foob(10).barb()) # works
+echo(type(10).name()) # doesn't work
+
+echo(name(type(10))) # works
+echo((type(10)).name()) # works
+
+
+# test that 'addr' still works
+proc poo(x, y: ptr int) = discard
+
+var someInt: int
+poo(addr someInt, addr someInt)
diff --git a/tests/parser/ttypesectioncalls.nim b/tests/parser/ttypesectioncalls.nim
new file mode 100644
index 000000000..003444fc5
--- /dev/null
+++ b/tests/parser/ttypesectioncalls.nim
@@ -0,0 +1,328 @@
+discard """
+nimout: '''
+StmtList
+  TypeSection
+    TypeDef
+      Ident "A"
+      Empty
+      Call
+        Ident "call"
+        IntLit 1
+  TypeSection
+    TypeDef
+      Ident "B"
+      Empty
+      Command
+        Ident "call"
+        IntLit 2
+    TypeDef
+      Ident "C"
+      Empty
+      Call
+        Ident "call"
+        StmtList
+          IntLit 3
+    TypeDef
+      Ident "D"
+      Empty
+      Call
+        Ident "call"
+        StmtList
+          IntLit 4
+  TypeSection
+    TypeDef
+      Ident "E"
+      Empty
+      Call
+        Ident "call"
+        IntLit 5
+        IntLit 6
+    TypeDef
+      Ident "F"
+      Empty
+      Command
+        Ident "call"
+        IntLit 7
+        IntLit 8
+    TypeDef
+      Ident "G"
+      Empty
+      Call
+        Ident "call"
+        IntLit 9
+        StmtList
+          IntLit 10
+    TypeDef
+      Ident "H"
+      Empty
+      Call
+        Ident "call"
+        IntLit 11
+        StmtList
+          IntLit 12
+    TypeDef
+      Ident "I"
+      Empty
+      Command
+        Ident "call"
+        IntLit 13
+        StmtList
+          IntLit 14
+    TypeDef
+      Ident "J"
+      Empty
+      Command
+        Ident "call"
+        IntLit 15
+        StmtList
+          IntLit 16
+  TypeSection
+    TypeDef
+      Ident "K"
+      Empty
+      Call
+        Ident "call"
+        IntLit 17
+        IntLit 18
+        IntLit 19
+    TypeDef
+      Ident "L"
+      Empty
+      Command
+        Ident "call"
+        IntLit 20
+        IntLit 21
+        IntLit 22
+    TypeDef
+      Ident "M"
+      Empty
+      Call
+        Ident "call"
+        IntLit 23
+        IntLit 24
+        StmtList
+          IntLit 25
+    TypeDef
+      Ident "N"
+      Empty
+      Command
+        Ident "call"
+        IntLit 26
+        IntLit 27
+        StmtList
+          IntLit 28
+    TypeDef
+      Ident "O"
+      Empty
+      Command
+        Ident "call"
+        IntLit 29
+        IntLit 30
+        StmtList
+          IntLit 31
+  TypeSection
+    TypeDef
+      Ident "P"
+      Empty
+      Command
+        Ident "call"
+        TupleConstr
+          IntLit 32
+          IntLit 33
+        Infix
+          Ident "+"
+          Infix
+            Ident "*"
+            IntLit 34
+            IntLit 35
+          IntLit 36
+        StmtList
+          IntLit 37
+    TypeDef
+      Ident "R"
+      Empty
+      Command
+        Ident "call"
+        Infix
+          Ident "@"
+          TupleConstr
+            IntLit 38
+            IntLit 39
+          Infix
+            Ident "shl"
+            IntLit 40
+            IntLit 41
+        Infix
+          Ident "-"
+          Infix
+            Ident "*"
+            IntLit 42
+            IntLit 43
+          IntLit 44
+        StmtList
+          IntLit 45
+    TypeDef
+      Ident "S"
+      Empty
+      Command
+        Ident "call"
+        IntLit 46
+        StmtList
+          IntLit 47
+        StmtList
+          IntLit 48
+    TypeDef
+      Ident "T"
+      Empty
+      Call
+        Ident "call"
+        StmtList
+          IntLit 49
+        StmtList
+          IntLit 50
+        StmtList
+          IntLit 51
+a: IntLit 1
+a: IntLit 2
+a: StmtList
+  IntLit 3
+a: StmtList
+  IntLit 4
+a: IntLit 5
+b: IntLit 6
+a: IntLit 7
+b: IntLit 8
+a: IntLit 9
+b: StmtList
+  IntLit 10
+a: IntLit 11
+b: StmtList
+  IntLit 12
+a: IntLit 13
+b: StmtList
+  IntLit 14
+a: IntLit 15
+b: StmtList
+  IntLit 16
+a: IntLit 17
+b: IntLit 18
+c: IntLit 19
+a: IntLit 20
+b: IntLit 21
+c: IntLit 22
+a: IntLit 23
+b: IntLit 24
+c: StmtList
+  IntLit 25
+a: IntLit 26
+b: IntLit 27
+c: StmtList
+  IntLit 28
+a: IntLit 29
+b: IntLit 30
+c: StmtList
+  IntLit 31
+a: TupleConstr
+  IntLit 32
+  IntLit 33
+b: Infix
+  Ident "+"
+  Infix
+    Ident "*"
+    IntLit 34
+    IntLit 35
+  IntLit 36
+c: StmtList
+  IntLit 37
+a: Infix
+  Ident "@"
+  TupleConstr
+    IntLit 38
+    IntLit 39
+  Infix
+    Ident "shl"
+    IntLit 40
+    IntLit 41
+b: Infix
+  Ident "-"
+  Infix
+    Ident "*"
+    IntLit 42
+    IntLit 43
+  IntLit 44
+c: StmtList
+  IntLit 45
+a: IntLit 46
+b: StmtList
+  IntLit 47
+c: StmtList
+  IntLit 48
+a: StmtList
+  IntLit 49
+b: StmtList
+  IntLit 50
+c: StmtList
+  IntLit 51
+'''
+"""
+import macros
+
+macro call(a): untyped =
+  echo "a: ", a.treeRepr
+  result = ident"int"
+macro call(a, b): untyped =
+  echo "a: ", a.treeRepr
+  echo "b: ", b.treeRepr
+  result = ident"int"
+macro call(a, b, c): untyped =
+  echo "a: ", a.treeRepr
+  echo "b: ", b.treeRepr
+  echo "c: ", c.treeRepr
+  result = ident"int"
+
+macro sections(x): untyped =
+  echo x.treeRepr
+  result = newStmtList(x)
+  for ts in x:
+    for td in ts:
+      let t = td[0]
+      result.add quote do:
+        doAssert `t` is int
+
+sections:
+  type A = call(1)
+  type
+    B = call 2
+    C = call: 3
+    D = call(): 4
+  type
+    E = call(5, 6)
+    F = call 7, 8
+    G = call(9): 10
+    H = call(11):
+      12
+    I = call 13: 14
+    J = call 15:
+      16
+  type
+    K = call(17, 18, 19)
+    L = call 20, 21, 22
+    M = call(23, 24): 25
+    N = call 26, 27: 28
+    O = call 29, 30:
+      31
+  type
+    P = call (32, 33), 34 * 35 + 36:
+      37
+    R = call (38, 39) @ 40 shl 41, 42 * 43 - 44:
+      45
+    S = call 46:
+      47
+    do:
+      48
+    T = call:
+      49
+    do:
+      50
+    do:
+      51
diff --git a/tests/parser/twhen_in_enum.nim b/tests/parser/twhen_in_enum.nim
new file mode 100644
index 000000000..3890b686e
--- /dev/null
+++ b/tests/parser/twhen_in_enum.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "identifier expected, but got 'keyword when'"
+"""
+
+# bug #2123
+type num = enum
+    NUM_NONE = 0
+    NUM_ALL = 1
+    when defined(macosx): NUM_OSX = 10 # only this differs for real
+    NUM_XTRA = 20
+
diff --git a/tests/parser/twrongcmdsyntax.nim b/tests/parser/twrongcmdsyntax.nim
new file mode 100644
index 000000000..c2962bed4
--- /dev/null
+++ b/tests/parser/twrongcmdsyntax.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: '''in expression '4 2': identifier expected, but found '4'''
+  line: 6
+"""
+
+echo 4 +2
diff --git a/tests/pragmas/cfunction.c b/tests/pragmas/cfunction.c
new file mode 100644
index 000000000..bf49d6a29
--- /dev/null
+++ b/tests/pragmas/cfunction.c
@@ -0,0 +1,4 @@
+
+int cfunction(void) {
+  return NUMBER_HERE;
+}
diff --git a/tests/pragmas/custom_pragma.nim b/tests/pragmas/custom_pragma.nim
new file mode 100644
index 000000000..d2fc969d0
--- /dev/null
+++ b/tests/pragmas/custom_pragma.nim
@@ -0,0 +1,5 @@
+# imported by tcustom_pragmas to test scoping
+
+template serializationKey*(s: string) {.pragma.}
+template defaultValue*(V: typed) {.pragma.}
+template alternativeKey*(s: string = "", V: typed) {.pragma.}
diff --git a/tests/pragmas/foobar.nim b/tests/pragmas/foobar.nim
new file mode 100644
index 000000000..46032e187
--- /dev/null
+++ b/tests/pragmas/foobar.nim
@@ -0,0 +1,3 @@
+import macros
+macro async*(body: untyped): untyped =
+  return newStmtList()
diff --git a/tests/pragmas/monoff1.nim b/tests/pragmas/monoff1.nim
new file mode 100644
index 000000000..85d6c57b3
--- /dev/null
+++ b/tests/pragmas/monoff1.nim
@@ -0,0 +1 @@
+proc on*() = discard
diff --git a/tests/pragmas/mpushexperimental.nim b/tests/pragmas/mpushexperimental.nim
new file mode 100644
index 000000000..569861c1d
--- /dev/null
+++ b/tests/pragmas/mpushexperimental.nim
@@ -0,0 +1,30 @@
+
+import macros
+
+macro enumerate(x: ForLoopStmt): untyped =
+  expectKind x, nnkForStmt
+  # we strip off the first for loop variable and use
+  # it as an integer counter:
+  result = newStmtList()
+  result.add newVarStmt(x[0], newLit(0))
+  var body = x[^1]
+  if body.kind != nnkStmtList:
+    body = newTree(nnkStmtList, body)
+  body.add newCall(bindSym"inc", x[0])
+  var newFor = newTree(nnkForStmt)
+  for i in 1..x.len-3:
+    newFor.add x[i]
+  # transform enumerate(X) to 'X'
+  newFor.add x[^2][1]
+  newFor.add body
+  result.add newFor
+
+proc main*[T](x: T) =
+  {.push experimental: "forLoopMacros".}
+
+  for a, b in enumerate(items([1, 2, 3])):
+    echo a, " ", b
+
+  for a2, b2 in enumerate([1, 2, 3, 5]):
+    echo a2, " ", b2
+  {.pop.}
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/t12558.nim b/tests/pragmas/t12558.nim
new file mode 100644
index 000000000..14fc74cee
--- /dev/null
+++ b/tests/pragmas/t12558.nim
@@ -0,0 +1,15 @@
+discard """
+  nimout: '''@["1", "2", "3"]'''
+"""
+
+import sequtils
+
+{.push compile_time.}
+
+proc foo =
+  echo map_it([1, 2, 3], $it)
+
+{.pop.}
+
+static:
+  foo()
diff --git a/tests/pragmas/t12640.nim b/tests/pragmas/t12640.nim
new file mode 100644
index 000000000..c85185699
--- /dev/null
+++ b/tests/pragmas/t12640.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:refc"
+  nimout: '''1
+2
+3
+[1, 2, 3]'''
+
+  output: '''1
+2
+3
+[1, 2, 3]'''
+"""
+
+# todo fixme it doesn't work with ORC
+proc doIt(a: openArray[int]) =
+  echo a
+
+proc foo() = 
+  var bug {.global, compiletime.}: seq[int]
+  bug = @[1, 2 ,3]
+  for i in 0 .. high(bug): echo bug[i]
+  doIt(bug)
+
+static:
+  foo()
+foo()
diff --git a/tests/pragmas/t13306.nim b/tests/pragmas/t13306.nim
new file mode 100644
index 000000000..36713dd04
--- /dev/null
+++ b/tests/pragmas/t13306.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "'testEpo' can have side effects"
+  line: 8
+"""
+
+import times
+
+func testEpo(x: float): float = epochTime() + x
+
+echo testEpo(1.0)
diff --git a/tests/pragmas/t22713.nim b/tests/pragmas/t22713.nim
new file mode 100644
index 000000000..3d3384632
--- /dev/null
+++ b/tests/pragmas/t22713.nim
@@ -0,0 +1,12 @@
+import std/macros
+
+
+template myPragma(x: int) {.pragma.}
+
+type
+  A = object
+    x: int64
+
+  B {.myPragma(sizeof(A)).} = object
+
+doAssert B.getCustomPragmaVal(myPragma) == 8
\ No newline at end of file
diff --git a/tests/pragmas/t4384.nim b/tests/pragmas/t4384.nim
new file mode 100644
index 000000000..e6b193f79
--- /dev/null
+++ b/tests/pragmas/t4384.nim
@@ -0,0 +1,3 @@
+macro testMacro(body: untyped): untyped = discard
+macro testMacro(s: string, body: untyped): untyped = discard
+proc foo() {.testMacro: "foo".} = discard
diff --git a/tests/pragmas/t5149.nim b/tests/pragmas/t5149.nim
new file mode 100644
index 000000000..2d242a8d5
--- /dev/null
+++ b/tests/pragmas/t5149.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "{.exportc.} not allowed for type aliases"
+  line: 9
+"""
+
+type
+  X* = object
+    a: int
+  Y* {.exportc.} = X
+
+proc impl*(x: X) =
+  echo "it works"
diff --git a/tests/pragmas/t6448.nim b/tests/pragmas/t6448.nim
new file mode 100644
index 000000000..6efb56e08
--- /dev/null
+++ b/tests/pragmas/t6448.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: '''ambiguous call'''
+  line: 10
+  disabled: "32bit"
+"""
+
+import foobar
+import asyncdispatch, macros
+
+proc bar() {.async.} =
+  echo 42
+
+proc foo() {.async.} =
+  await bar()
+
+asyncCheck foo()
+runForever()
diff --git a/tests/pragmas/t8741.nim b/tests/pragmas/t8741.nim
new file mode 100644
index 000000000..bf97b0e29
--- /dev/null
+++ b/tests/pragmas/t8741.nim
@@ -0,0 +1,29 @@
+discard """
+  cmd: "nim check --hint:processing:off $file"
+  errormsg: "3 is not two"
+  nimout: '''t8741.nim(13, 9) Error: invalid pragma: foobar
+t8741.nim(29, 15) template/generic instantiation of `onlyTwo` from here
+t8741.nim(25, 12) Error: 3 is not two
+'''
+"""
+
+for a {.gensym, inject.} in @[1,2,3]:
+  discard
+
+for a {.foobar.} in @[1,2,3]:
+  discard
+
+type Foo[N: static[int]] = distinct int
+
+proc isTwo(n: int): bool =
+  n == 2
+
+proc onlyTwo[N: static[int]](a: Foo[N]): int =
+  when isTwo(N):
+    int(a)
+  else:
+    {.error: $(N) & " is not two".}
+
+when isMainModule:
+  let foo: Foo[3] = Foo[3](5)
+  echo onlyTwo(foo)
diff --git a/tests/pragmas/tbitsize.nim b/tests/pragmas/tbitsize.nim
new file mode 100644
index 000000000..39aee445f
--- /dev/null
+++ b/tests/pragmas/tbitsize.nim
@@ -0,0 +1,22 @@
+discard """
+ccodeCheck: "\\i @'unsigned int flag:1;' .*"
+"""
+
+type
+  bits* = object
+    flag* {.bitsize: 1.}: cuint
+    opts* {.bitsize: 4.}: cint
+
+var
+  b: bits
+
+doAssert b.flag == 0
+b.flag = 1
+doAssert b.flag == 1
+b.flag = 2
+doAssert b.flag == 0
+
+b.opts = 7
+doAssert b.opts == 7
+b.opts = 9
+doAssert b.opts == -7
diff --git a/tests/pragmas/tcompile_missing_file.nim b/tests/pragmas/tcompile_missing_file.nim
new file mode 100644
index 000000000..fd90bd57d
--- /dev/null
+++ b/tests/pragmas/tcompile_missing_file.nim
@@ -0,0 +1,5 @@
+discard """
+  joinable: false
+  errormsg: "cannot find: noexist.c"
+"""
+{.compile: "noexist.c".}
diff --git a/tests/pragmas/tcompile_pragma.nim b/tests/pragmas/tcompile_pragma.nim
new file mode 100644
index 000000000..5b99352dd
--- /dev/null
+++ b/tests/pragmas/tcompile_pragma.nim
@@ -0,0 +1,10 @@
+discard """
+  output: '''34'''
+  joinable: false
+"""
+
+{.compile("cfunction.c", "-DNUMBER_HERE=34").}
+
+proc cfunction(): cint {.importc.}
+
+echo cfunction()
diff --git a/tests/pragmas/tcustom_pragma.nim b/tests/pragmas/tcustom_pragma.nim
new file mode 100644
index 000000000..11a6df813
--- /dev/null
+++ b/tests/pragmas/tcustom_pragma.nim
@@ -0,0 +1,540 @@
+{.experimental: "notnil".}
+
+import macros, asyncmacro, asyncfutures
+
+block:
+  template myAttr() {.pragma.}
+
+  proc myProc():int {.myAttr.} = 2
+  const hasMyAttr = myProc.hasCustomPragma(myAttr)
+  static:
+    doAssert(hasMyAttr)
+
+block:
+  template myAttr(a: string) {.pragma.}
+
+  type
+    MyObj = object
+      myField1, myField2 {.myAttr: "hi".}: int
+
+    MyGenericObj[T] = object
+      myField1, myField2 {.myAttr: "hi".}: int
+
+    MyOtherObj = MyObj
+
+
+  var o: MyObj
+  static:
+    doAssert o.myField2.hasCustomPragma(myAttr)
+    doAssert(not o.myField1.hasCustomPragma(myAttr))
+    doAssert(not o.myField1.hasCustomPragma(MyObj))
+    doAssert(not o.myField1.hasCustomPragma(MyOtherObj))
+
+  var ogen: MyGenericObj[int]
+  static:
+    doAssert ogen.myField2.hasCustomPragma(myAttr)
+    doAssert(not ogen.myField1.hasCustomPragma(myAttr))
+    doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj))
+    doAssert(not ogen.myField1.hasCustomPragma(MyGenericObj))
+
+
+import custom_pragma
+block: # A bit more advanced case
+  type
+    Subfield {.defaultValue: "catman".} = object
+      `c`* {.serializationKey: "cc".}: float
+
+    MySerializable = object
+      a {.serializationKey"asdf", defaultValue: 5.} : int
+      b {.custom_pragma.defaultValue"hello".} : int
+      field: Subfield
+      d {.alternativeKey("df", 5).}: float
+      e {.alternativeKey(V = 5).}: seq[bool]
+
+  proc myproc(x: int, s: string) {.alternativeKey(V = 5), serializationKey"myprocSS".} =
+    echo x, s
+
+
+  var s: MySerializable
+
+  const aDefVal = s.a.getCustomPragmaVal(defaultValue)
+  static: doAssert(aDefVal == 5)
+
+  const aSerKey = s.a.getCustomPragmaVal(serializationKey)
+  static: doAssert(aSerKey == "asdf")
+
+  const cSerKey = getCustomPragmaVal(s.field.c, serializationKey)
+  static: doAssert(cSerKey == "cc")
+
+  const procSerKey = getCustomPragmaVal(myproc, serializationKey)
+  static: doAssert(procSerKey == "myprocSS")
+
+  static: doAssert(hasCustomPragma(myproc, alternativeKey))
+
+  const hasFieldCustomPragma = s.field.hasCustomPragma(defaultValue)
+  static: doAssert(hasFieldCustomPragma == false)
+
+  # pragma on an object
+  static:
+    doAssert Subfield.hasCustomPragma(defaultValue)
+    doAssert(Subfield.getCustomPragmaVal(defaultValue) == "catman")
+
+    doAssert hasCustomPragma(type(s.field), defaultValue)
+
+  proc foo(s: var MySerializable) =
+    static: doAssert(s.a.getCustomPragmaVal(defaultValue) == 5)
+
+  foo(s)
+
+block: # ref types
+  type
+    Node = object of RootObj
+      left {.serializationKey:"l".}, right {.serializationKey:"r".}: NodeRef
+    NodeRef = ref Node
+    NodePtr = ptr Node
+
+    SpecialNodeRef = ref object of NodeRef
+      data {.defaultValue"none".}: string
+
+    MyFile {.defaultValue: "closed".} = ref object
+      path {.defaultValue: "invalid".}: string
+
+    TypeWithoutPragma = object
+
+  var s = NodeRef()
+
+  const
+    leftSerKey = getCustomPragmaVal(s.left, serializationKey)
+    rightSerKey = getCustomPragmaVal(s.right, serializationKey)
+  static:
+    doAssert leftSerKey == "l"
+    doAssert rightSerKey == "r"
+
+  var specS = SpecialNodeRef()
+
+  const
+    dataDefVal = hasCustomPragma(specS.data, defaultValue)
+    specLeftSerKey = hasCustomPragma(specS.left, serializationKey)
+  static:
+    doAssert dataDefVal == true
+    doAssert specLeftSerKey == true
+
+  var ptrS = NodePtr(nil)
+  const
+    ptrRightSerKey = getCustomPragmaVal(ptrS.right, serializationKey)
+  static:
+    doAssert ptrRightSerKey == "r"
+
+  var f = MyFile()
+  const
+    fileDefVal = f.getCustomPragmaVal(defaultValue)
+    filePathDefVal = f.path.getCustomPragmaVal(defaultValue)
+  static:
+    doAssert fileDefVal == "closed"
+    doAssert filePathDefVal == "invalid"
+
+  static:
+    doAssert TypeWithoutPragma.hasCustomPragma(defaultValue) == false
+
+block:
+  type
+    VariantKind = enum
+      variInt,
+      variFloat
+      variString
+      variNestedCase
+    Variant = object
+      case kind: VariantKind
+      of variInt: integer {.serializationKey: "int".}: BiggestInt
+      of variFloat: floatp: BiggestFloat
+      of variString: str {.serializationKey: "string".}: string
+      of variNestedCase:
+        case nestedKind: VariantKind
+        of variInt..variNestedCase: nestedItem {.defaultValue: "Nimmers of the world, unite!".}: int
+
+  let vari = Variant(kind: variInt)
+
+  const
+    hasIntSerKey = vari.integer.hasCustomPragma(serializationKey)
+    strSerKey = vari.str.getCustomPragmaVal(serializationKey)
+    nestedItemDefVal = vari.nestedItem.getCustomPragmaVal(defaultValue)
+
+  static:
+    doAssert hasIntSerKey
+    doAssert strSerKey == "string"
+    doAssert nestedItemDefVal == "Nimmers of the world, unite!"
+
+block:
+  template simpleAttr {.pragma.}
+
+  type Annotated {.simpleAttr.} = object
+
+  proc generic_proc[T]() =
+    doAssert Annotated.hasCustomPragma(simpleAttr)
+
+#--------------------------------------------------------------------------
+# Pragma on proc type
+
+type
+  MyAnnotatedProcType {.defaultValue(4).} = proc(x: int)
+
+let a {.defaultValue(4).}: proc(x: int)  = nil
+var b: MyAnnotatedProcType = nil
+var c: proc(x: int): void {.defaultValue(5).}  = nil
+var d {.defaultValue(44).}: MyAnnotatedProcType = nil
+static:
+  doAssert hasCustomPragma(a, defaultValue)
+  doAssert hasCustomPragma(MyAnnotatedProcType, defaultValue)
+  doAssert hasCustomPragma(b, defaultValue)
+  doAssert hasCustomPragma(typeof(c), defaultValue)
+  doAssert getCustomPragmaVal(d, defaultValue) == 44
+  doAssert getCustomPragmaVal(typeof(d), defaultValue) == 4
+
+# bug #8371
+template thingy {.pragma.}
+
+type
+  Cardinal = enum
+    north, east, south, west
+  Something = object
+    a: float32
+    case cardinal: Cardinal
+    of north:
+      b {.thingy.}: int
+    of east:
+      c: int
+    of south: discard
+    else: discard
+
+var foo: Something
+foo.cardinal = north
+doAssert foo.b.hasCustomPragma(thingy) == true
+
+proc myproc(s: string): int =
+  {.thingy.}:
+    s.len
+
+doAssert myproc("123") == 3
+
+let xx = compiles:
+  proc myproc_bad(s: string): int =
+    {.not_exist.}:
+      s.len
+doAssert: xx == false
+
+macro checkSym(s: typed{nkSym}): untyped =
+  let body = s.getImpl.body
+  doAssert body[1].kind == nnkPragmaBlock
+  doAssert body[1][0].kind == nnkPragma
+  doAssert body[1][0][0] == bindSym"thingy"
+
+checkSym(myproc)
+
+# var and let pragmas
+block:
+  template myAttr() {.pragma.}
+  template myAttr2(x: int) {.pragma.}
+  template myAttr3(x: string) {.pragma.}
+
+  type
+    MyObj2 = ref object
+    MyObjNotNil = MyObj2 not nil
+
+  let a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
+  let b {.myAttr,myAttr2(2),myAttr3:"test".} = 0
+  var x {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
+  var y {.myAttr,myAttr2(2),myAttr3:"test".}: int
+  var z {.myAttr,myAttr2(2),myAttr3:"test".} = 0
+  var z2 {.myAttr.}: MyObjNotNil
+
+  template check(s: untyped) =
+    doAssert s.hasCustomPragma(myAttr)
+    doAssert s.hasCustomPragma(myAttr2)
+    doAssert s.getCustomPragmaVal(myAttr2) == 2
+    doAssert s.hasCustomPragma(myAttr3)
+    doAssert s.getCustomPragmaVal(myAttr3) == "test"
+
+  check(a)
+  check(b)
+  check(x)
+  check(y)
+  check(z)
+
+# pragma with multiple fields
+block:
+  template myAttr(first: string, second: int, third: float) {.pragma.}
+  let a {.myAttr("one", 2, 3.0).} = 0
+  let ps = a.getCustomPragmaVal(myAttr)
+  doAssert ps.first == ps[0] and ps.first == "one"
+  doAssert ps.second == ps[1] and ps.second == 2
+  doAssert ps.third == ps[2] and ps.third == 3.0
+
+# pragma with implicit&explicit generic types
+block:
+  template fooBar[T](x: T; c: static[int] = 42; m: char) {.pragma.}
+  var e {.fooBar("foo", 123, 'u').}: int
+  doAssert(hasCustomPragma(e, fooBar))
+  doAssert(getCustomPragmaVal(e, fooBar).c == 123)
+
+block:
+  macro expectedAst(expectedRepr: static[string], input: untyped): untyped =
+    doAssert input.treeRepr & "\n" == expectedRepr
+    return input
+
+  macro expectedAstRepr(expectedRepr: static[string], input: untyped): untyped =
+    doAssert input.repr == expectedRepr
+    return input
+
+  const procTypeAst = """
+ProcTy
+  FormalParams
+    Empty
+    IdentDefs
+      Ident "x"
+      Ident "int"
+      Empty
+  Pragma
+    Ident "async"
+"""
+
+  type
+    Foo = proc (x: int) {.expectedAst(procTypeAst), async.}
+
+  static: doAssert Foo is proc(x: int): Future[void]
+
+  const asyncProcTypeAst = """
+proc (s: string): Future[void] {..}"""
+  # using expectedAst would show `OpenSymChoice` for Future[void], which is fragile.
+  type
+    Bar = proc (s: string) {.async, expectedAstRepr(asyncProcTypeAst).}
+
+  static: doAssert Bar is proc(x: string): Future[void]
+
+  const typeAst = """
+TypeDef
+  PragmaExpr
+    Ident "Baz"
+    Pragma
+  Empty
+  ObjectTy
+    Empty
+    Empty
+    RecList
+      IdentDefs
+        Ident "x"
+        Ident "string"
+        Empty
+"""
+
+  type
+    Baz {.expectedAst(typeAst).} = object
+      x: string
+
+  static: doAssert Baz.x is string
+
+  const procAst = """
+ProcDef
+  Ident "bar"
+  Empty
+  Empty
+  FormalParams
+    Ident "string"
+    IdentDefs
+      Ident "s"
+      Ident "string"
+      Empty
+  Empty
+  Empty
+  StmtList
+    ReturnStmt
+      Ident "s"
+"""
+
+  proc bar(s: string): string {.expectedAst(procAst).} =
+    return s
+
+  static: doAssert bar("x") == "x"
+
+#------------------------------------------------------
+# bug #13909
+
+template dependency*(id: string, weight = 0.0) {.pragma.}
+
+type
+  MyObject* = object
+    provider*: proc(obj: string): pointer {.dependency("Data/" & obj, 16.1), noSideEffect.}
+
+proc myproc(obj: string): string {.dependency("Data/" & obj, 16.1).} =
+  result = obj
+
+# bug 12523
+template myCustomPragma {.pragma.}
+
+type
+  RefType = ref object
+    field {.myCustomPragma.}: int
+
+  ObjType = object
+    field {.myCustomPragma.}: int
+  RefType2 = ref ObjType
+
+block:
+  let x = RefType()
+  for fieldName, fieldSym in fieldPairs(x[]):
+    doAssert hasCustomPragma(fieldSym, myCustomPragma)
+
+block:
+  let x = RefType2()
+  for fieldName, fieldSym in fieldPairs(x[]):
+    doAssert hasCustomPragma(fieldSym, myCustomPragma)
+
+# bug 8457
+block:
+  template world {.pragma.}
+
+  type
+    Hello = ref object
+      a: float32
+      b {.world.}: int
+
+  discard Hello(a: 1.0, b: 12)
+
+# test routines
+block:
+  template prag {.pragma.}
+  proc hello {.prag.} = discard
+  iterator hello2: int {.prag.} = discard
+  template hello3(x: int): int {.prag.} = x
+  macro hello4(x: int): int {.prag.} = x
+  func hello5(x: int): int {.prag.} = x
+  doAssert hello.hasCustomPragma(prag)
+  doAssert hello2.hasCustomPragma(prag)
+  doAssert hello3.hasCustomPragma(prag)
+  doAssert hello4.hasCustomPragma(prag)
+  doAssert hello5.hasCustomPragma(prag)
+
+# test push doesn't break
+block:
+  template prag {.pragma.}
+  {.push prag.}
+  proc hello = discard
+  iterator hello2: int = discard
+  template hello3(x: int): int = x
+  macro hello4(x: int): int = x
+  func hello5(x: int): int = x
+  type
+    Foo = enum a
+    Bar[T] = ref object of RootObj
+      x: T
+      case y: bool
+      of false: discard
+      else:
+        when true: discard
+  for a in [1]: discard a
+  {.pop.}
+
+# issue #11511
+when false:
+  template myAttr {.pragma.}
+
+  type TObj = object
+      a {.myAttr.}: int
+
+  macro hasMyAttr(t: typedesc): untyped =
+    let objTy = t.getType[1].getType
+    let recList = objTy[2]
+    let sym = recList[0]
+    assert sym.kind == nnkSym and sym.eqIdent("a")
+    let hasAttr = sym.hasCustomPragma(myAttr)
+    newLit(hasAttr)
+
+  doAssert hasMyAttr(TObj)
+
+
+# bug #11415
+template noserialize() {.pragma.}
+
+type
+  Point[T] = object
+    x, y: T
+
+  ReplayEventKind = enum
+    FoodAppeared, FoodEaten, DirectionChanged
+
+  ReplayEvent = object
+    case kind: ReplayEventKind
+    of FoodEaten, FoodAppeared: # foodPos is in multiple branches
+      foodPos {.noserialize.}: Point[float]
+    of DirectionChanged:
+      playerPos: float
+let ev = ReplayEvent(
+    kind: FoodEaten,
+    foodPos: Point[float](x: 5.0, y: 1.0)
+  )
+
+doAssert ev.foodPos.hasCustomPragma(noserialize)
+
+
+when false:
+  # misc
+  {.pragma: haha.}
+  {.pragma: hoho.}
+  template hehe(key, val: string, haha) {.pragma.}
+
+  type A {.haha, hoho, haha, hehe("hi", "hu", "he").} = int
+
+  assert A.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he")
+
+  template hehe(key, val: int) {.pragma.}
+
+  var bb {.haha, hoho, hehe(1, 2), haha, hehe("hi", "hu", "he").} = 3
+
+  # left-to-right priority/override order for getCustomPragmaVal
+  assert bb.getCustomPragmaVal(hehe) == (key: "hi", val: "hu", haha: "he")
+
+{.experimental: "dynamicBindSym".}
+
+# const
+block:
+  template myAttr() {.pragma.}
+  template myAttr2(x: int) {.pragma.}
+  template myAttr3(x: string) {.pragma.}
+
+  type
+    MyObj2 = ref object
+
+  const a {.myAttr,myAttr2(2),myAttr3:"test".}: int = 0
+  const b {.myAttr,myAttr2(2),myAttr3:"test".} = 0
+
+  macro forceHasCustomPragma(x: untyped, y: typed): untyped =
+    var x = bindSym(x.repr)
+    for c in x:
+      if c.symKind == nskConst:
+        x = c
+        break
+    result = getAst(hasCustomPragma(x, y))
+
+  macro forceGetCustomPragmaVal(x: untyped, y: typed): untyped =
+    var x = bindSym(x.repr)
+    for c in x:
+      if c.symKind == nskConst:
+        x = c
+        break
+    result = getAst(getCustomPragmaVal(x, y))
+
+  template check(s: untyped) =
+    doAssert forceHasCustomPragma(s, myAttr)
+    doAssert forceHasCustomPragma(s, myAttr2)
+    doAssert forceGetCustomPragmaVal(s, myAttr2) == 2
+    doAssert forceHasCustomPragma(s, myAttr3)
+    doAssert forceGetCustomPragmaVal(s, myAttr3) == "test"
+
+  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/tdeprecated.nim b/tests/pragmas/tdeprecated.nim
new file mode 100644
index 000000000..a5d07f727
--- /dev/null
+++ b/tests/pragmas/tdeprecated.nim
@@ -0,0 +1,10 @@
+# bug #6436
+proc foo(size: int, T: typedesc): seq[T]  {.deprecated.}=
+  result = newSeq[T](size)
+
+proc foo[T](size: int): seq[T]=
+  result = newSeq[T](size)
+
+let bar = foo[int](3) # Warning foo is deprecated
+
+doAssert bar == @[0, 0, 0]
diff --git a/tests/pragmas/thintprocessing.nim b/tests/pragmas/thintprocessing.nim
new file mode 100644
index 000000000..c608bc6e4
--- /dev/null
+++ b/tests/pragmas/thintprocessing.nim
@@ -0,0 +1,18 @@
+discard """
+  disabled: windows
+  matrix: "--hint:processing"
+  nimout: '''
+compile start
+..
+warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed]
+compile end
+'''
+"""
+
+static:
+  echo "compile start"
+
+import warn_module
+
+static:
+  echo "compile end"
diff --git a/tests/pragmas/tinvalid_user_pragma.nim b/tests/pragmas/tinvalid_user_pragma.nim
new file mode 100644
index 000000000..3081db842
--- /dev/null
+++ b/tests/pragmas/tinvalid_user_pragma.nim
@@ -0,0 +1,9 @@
+discard """
+cmd: "nim check $file"
+"""
+
+{.pragma test: foo.} #[tt.Error
+^ invalid pragma:  {.pragma, test: foo.} ]#
+
+{.pragma: 1.} #[tt.Error
+^ invalid pragma:  {.pragma: 1.} ]#
diff --git a/tests/pragmas/tinvalidcustompragma.nim b/tests/pragmas/tinvalidcustompragma.nim
new file mode 100644
index 000000000..a31695809
--- /dev/null
+++ b/tests/pragmas/tinvalidcustompragma.nim
@@ -0,0 +1,23 @@
+discard """
+  cmd: "nim check $file"
+"""
+
+# issue #21652
+type Foo = object
+template foo() {.tags:[Foo].} = #[tt.Error
+                     ^ invalid pragma: tags: [Foo]]#
+  discard
+
+{.foobar.} #[tt.Error
+  ^ invalid pragma: foobar]#
+type A = enum a {.foobar.} #[tt.Error
+                  ^ invalid pragma: foobar]#
+for b {.foobar.} in [1]: discard #[tt.Error
+        ^ invalid pragma: foobar]#
+template foobar {.pragma.}
+{.foobar.} #[tt.Error
+  ^ cannot attach a custom pragma to 'tinvalidcustompragma'; custom pragmas are not supported for modules]#
+type A = enum a {.foobar.} #[tt.Error
+                  ^ cannot attach a custom pragma to 'a'; custom pragmas are not supported for enum fields]#
+for b {.foobar.} in [1]: discard #[tt.Error
+        ^ cannot attach a custom pragma to 'b'; custom pragmas are not supported for `for` loop variables]#
diff --git a/tests/pragmas/tlocks.nim b/tests/pragmas/tlocks.nim
new file mode 100644
index 000000000..5d6fcdd9c
--- /dev/null
+++ b/tests/pragmas/tlocks.nim
@@ -0,0 +1,12 @@
+type SomeBase* = ref object of RootObj
+type SomeDerived* = ref object of SomeBase
+  memberProc*: proc ()
+
+method testMethod(g: SomeBase) {.base, locks: "unknown".} = discard
+method testMethod(g: SomeDerived) =
+  if g.memberProc != nil:
+    g.memberProc()
+
+# ensure int literals still work
+proc plain*() {.locks: 0.} =
+  discard
diff --git a/tests/pragmas/tnoreturn.nim b/tests/pragmas/tnoreturn.nim
new file mode 100644
index 000000000..6a58055fe
--- /dev/null
+++ b/tests/pragmas/tnoreturn.nim
@@ -0,0 +1,27 @@
+discard """
+matrix: "--mm:refc"
+ccodeCheck: "\\i @'__attribute__((noreturn))' .*"
+action: compile
+"""
+
+proc noret1*(i: int) {.noreturn.} =
+  echo i
+
+
+proc noret2*(i: int): void {.noreturn.} =
+  echo i
+
+if true: noret1(1)
+if true: noret2(2)
+
+var p {.used.}: proc(i: int): int
+doAssert(not compiles(
+  p = proc(i: int): int {.noreturn.} = i # noreturn lambda returns int
+))
+
+
+doAssert(not compiles(
+  block:
+    noret1(5)
+    echo 1 # statement after noreturn
+))
diff --git a/tests/pragmas/tonoff1.nim b/tests/pragmas/tonoff1.nim
new file mode 100644
index 000000000..20ba7def2
--- /dev/null
+++ b/tests/pragmas/tonoff1.nim
@@ -0,0 +1,8 @@
+# issue #23002
+
+import monoff1
+
+proc test() =
+  {.warning[ProveInit]: on.}
+
+test()
diff --git a/tests/pragmas/tonoff2.nim b/tests/pragmas/tonoff2.nim
new file mode 100644
index 000000000..9dff5ef11
--- /dev/null
+++ b/tests/pragmas/tonoff2.nim
@@ -0,0 +1,14 @@
+discard """
+    action: compile
+"""
+
+# issue #22841
+
+import unittest
+
+proc on() =
+    discard
+
+suite "some suite":
+    test "some test":
+        discard
diff --git a/tests/pragmas/tpragmas_misc.nim b/tests/pragmas/tpragmas_misc.nim
new file mode 100644
index 000000000..adb7e73c3
--- /dev/null
+++ b/tests/pragmas/tpragmas_misc.nim
@@ -0,0 +1,75 @@
+##[
+tests for misc pragmas that don't need a separate file
+]##
+
+block:
+  static: doAssert not defined(tpragmas_misc_def)
+  {.undef(tpragmas_misc_def).} # works even if not set
+  static: doAssert not defined(tpragmas_misc_def)
+  {.define(tpragmas_misc_def).}
+  static: doAssert defined(tpragmas_misc_def)
+  {.undef(tpragmas_misc_def).}
+  static: doAssert not defined(tpragmas_misc_def)
+
+block: # (partial fix) bug #15920
+  block: # var template pragmas don't work in templates
+    template foo(expr) =
+      expr
+    proc fun1()=
+      let a {.foo.} = 1
+    template fun2()=
+      let a {.foo.} = 1
+    fun1() # ok
+    fun2() # WAS bug
+
+  template foo2() = discard # distractor (template or other symbol kind)
+  block:
+    template foo2(expr) =
+      expr
+    proc fun1()=
+      let a {.foo2.} = 1
+    template fun2()=
+      let a {.foo2.} = 1
+    fun1() # ok
+    fun2() # bug: Error: invalid pragma: foo2
+
+  block: # template pragmas don't work for templates, #18212
+    # adapted from $nim/lib/std/private/since.nim
+    # case without overload
+    template since3(version: (int, int), body: untyped) {.dirty.} =
+      when (NimMajor, NimMinor) >= version:
+        body
+    when true: # bug
+      template fun3(): int {.since3: (1, 3).} = 12
+
+  block: # ditto, w
+    # case with overload
+    template since2(version: (int, int), body: untyped) {.dirty.} =
+      when (NimMajor, NimMinor) >= version:
+        body
+    template since2(version: (int, int, int), body: untyped) {.dirty.} =
+      when (NimMajor, NimMinor, NimPatch) >= version:
+        body
+    when true: # bug
+      template fun3(): int {.since2: (1, 3).} = 12
+
+when true: # D20210801T100514:here
+  from macros import genSym
+  block:
+    template fn() =
+      var ret {.gensym.}: int # must special case template pragmas so it doesn't get confused
+      discard ret
+    fn()
+    static: discard genSym()
+
+block: # issue #10994
+  macro foo(x): untyped = x
+  template bar {.pragma.}
+
+  proc a {.bar.} = discard # works
+  proc b {.bar, foo.} = discard # doesn't
+
+block: # issue #22525
+  macro catch(x: typed) = x
+  proc thing {.catch.} = discard
+  thing()
diff --git a/tests/pragmas/tpragmas_reorder.nim b/tests/pragmas/tpragmas_reorder.nim
new file mode 100644
index 000000000..c4b1a6b0a
--- /dev/null
+++ b/tests/pragmas/tpragmas_reorder.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--experimental:codeReordering"
+"""
+
+runnableExamples:
+  import strtabs
+  var t = newStringTable()
+  t["name"] = "John"
+  t["city"] = "Monaco"
+  doAssert t.len == 2
+  doAssert t.hasKey "name"
+  doAssert "name" in t
+
+include "system/inclrtl"
+
+{.pragma: rtlFunc, rtl.}
+
+proc hasKey*(): bool {.rtlFunc.} =
+  discard
\ No newline at end of file
diff --git a/tests/pragmas/tpush.nim b/tests/pragmas/tpush.nim
new file mode 100644
index 000000000..9c6b85c4e
--- /dev/null
+++ b/tests/pragmas/tpush.nim
@@ -0,0 +1,144 @@
+discard """
+  targets: "c js"
+"""
+
+# test the new pragmas
+
+{.push warnings: off, hints: off.}
+proc noWarning() =
+  var
+    x: int
+  echo(x)
+
+{.pop.}
+
+proc WarnMe() =
+  var
+    x: int
+  echo(x)
+
+# bug #11852
+proc foo(x: string, y: int, res: int) =
+  {.push checks: off}
+  var a: ptr char = unsafeAddr(x[y])
+  {.pop.}
+  if x.len > y:
+    doAssert ord(a[]) == 51
+  else:
+    doAssert x.len + 48 == res
+
+foo("", 0, 48)
+foo("abc", 40, 51)
+
+# bug #22362
+{.push staticBoundChecks: on.}
+proc main(): void =
+  {.pop.}
+  discard
+  {.push staticBoundChecks: on.}
+
+main()
+
+
+proc timnFoo[T](obj: T) {.noSideEffect.} = discard # BUG
+
+{.push exportc.}
+proc foo1() =
+  var s1 = "bar"
+  timnFoo(s1)
+  var s2 = @[1]
+  timnFoo(s2)
+{.pop.}
+
+
+block: # bug #22913
+  block:
+    type r = object
+
+    template std[T](x: T) =
+      let ttt {.used.} = x
+      result = $ttt
+
+    proc bar[T](x: T): string =
+      std(x)
+
+    {.push exportc: "$1".}
+    proc foo(): r =
+      let s = bar(123)
+    {.pop.}
+
+    discard foo()
+
+  block:
+    type r = object
+    {.push exportc: "$1".}
+    proc foo2(): r =
+      let s = $result
+    {.pop.}
+
+    discard foo2()
+
+block: # bug #23019
+  proc f(x: bool)
+
+  proc a(x: int) =
+    if false: f(true)
+
+  proc f(x: bool) =
+    if false: a(0)
+
+  proc k(r: int|int) {.inline.} =  # seems to require being generic and inline
+    if false: a(0)
+
+
+  # {.push tags: [].}
+  {.push raises: [].}
+
+  {.push warning[ObservableStores]:off.}  # can be any warning, off or on
+  let w = 0
+  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/tpushexperimental.nim b/tests/pragmas/tpushexperimental.nim
new file mode 100644
index 000000000..301419f60
--- /dev/null
+++ b/tests/pragmas/tpushexperimental.nim
@@ -0,0 +1,13 @@
+discard """
+  output: '''0 1
+1 2
+2 3
+0 1
+1 2
+2 3
+3 5'''
+"""
+
+import mpushexperimental
+
+main(12)
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/pragmas/treorder.nim b/tests/pragmas/treorder.nim
new file mode 100644
index 000000000..09a98ef6a
--- /dev/null
+++ b/tests/pragmas/treorder.nim
@@ -0,0 +1,75 @@
+discard """
+output:'''0
+1
+2
+3'''
+"""
+
+import macros
+# {.reorder: on .}
+{.experimental: "codeReordering".}
+
+echo foo(-1)
+echo callWithFoo(0)
+echo(CA+CD)
+echo useTypes(TA(x:TB(x:1)), 2)
+second(0)
+
+template callWithFoo(arg: untyped): untyped =
+  foo(arg)
+
+proc first(i: int): void
+
+proc second(i: int): void =
+  make(first)
+  first(i)
+
+proc useTypes(a: TA, d: TD): int =
+  result = a.x.x+d
+
+type
+  TDoubleCyclic = ref object
+    x: TCyclicA
+    y: TCyclicB
+
+type
+  TCyclicA = ref object
+    x: TDoubleCyclic
+
+type
+  TCyclicB = ref object
+    x: TDoubleCyclic
+
+const
+  CA = 1
+  CB = CC
+
+type
+  TA = object
+    x: TB
+  TC = type(CC)
+  TD = type(CA)
+
+const
+  CC = 1
+  CD = CB
+
+type
+  TB = object
+    x: TC
+
+proc foo(x: int): int =
+  result = bar(x)
+
+proc bar(x: int): int =
+  result = x+1
+
+macro make(arg: untyped): untyped =
+  ss &= arg.repr
+  ss &= " "
+  discard
+
+proc first(i: int): void =
+  make(second)
+
+var ss {.compileTime.}: string = ""
diff --git a/tests/pragmas/tsym_as_pragma.nim b/tests/pragmas/tsym_as_pragma.nim
new file mode 100644
index 000000000..788311244
--- /dev/null
+++ b/tests/pragmas/tsym_as_pragma.nim
@@ -0,0 +1,8 @@
+
+# bug #3171
+
+template newDataWindow(): untyped =
+    let eventClosure = proc (closure: pointer): bool {.closure, cdecl.} =
+        discard
+
+newDataWindow()
diff --git a/tests/pragmas/ttypedef_macro.nim b/tests/pragmas/ttypedef_macro.nim
new file mode 100644
index 000000000..dd4c87757
--- /dev/null
+++ b/tests/pragmas/ttypedef_macro.nim
@@ -0,0 +1,66 @@
+import macros
+
+macro makeref(s): untyped =
+  expectKind s, nnkTypeDef
+  result = newTree(nnkTypeDef, s[0], s[1], newTree(nnkRefTy, s[2]))
+
+type
+  Obj {.makeref.} = object
+    a: int
+
+doAssert Obj is ref
+doAssert Obj(a: 3)[].a == 3
+
+macro multiply(amount: static int, s): untyped =
+  let name = $s[0].basename
+  result = newNimNode(nnkTypeSection)
+  for i in 1 .. amount:
+    result.add(newTree(nnkTypeDef, ident(name & $i), s[1], s[2]))
+
+type
+  Foo = object
+  Bar {.multiply: 2.} = object
+    x, y, z: int
+  Baz = object
+
+let bar1 = Bar1(x: 1, y: 2, z: 3)
+let bar2 = Bar2(x: bar1.x, y: bar1.y, z: bar1.z)
+doAssert Bar1 isnot Bar2
+doAssert not declared(Bar)
+doAssert not declared(Bar3)
+
+# https://github.com/nim-lang/RFCs/issues/219
+
+macro inferKind(td): untyped =
+  let name = $td[0].basename
+  var rhs = td[2]
+  while rhs.kind in {nnkPtrTy, nnkRefTy}: rhs = rhs[0]
+  if rhs.kind != nnkObjectTy:
+    result = td
+  else:
+    for n in rhs[^1]:
+      if n.kind == nnkRecCase and n[0][^2].eqIdent"_":
+        let kindTypeName = ident(name & "Kind")
+        let en = newTree(nnkEnumTy, newEmptyNode())
+        for i in 1 ..< n.len:
+          let branch = n[i]
+          if branch.kind == nnkOfBranch:
+            for j in 0 ..< branch.len - 1:
+              en.add(branch[j])
+        n[0][^2] = kindTypeName
+        return newTree(nnkTypeSection,
+          newTree(nnkTypeDef, kindTypeName, newEmptyNode(), en),
+          td)
+
+type Node {.inferKind.} = ref object
+  case kind: _
+  of opValue: value: int
+  of opAdd, opSub, opMul, opCall: kids: seq[Node]
+
+doAssert opValue is NodeKind
+let node = Node(kind: opMul, kids: @[
+  Node(kind: opValue, value: 3),
+  Node(kind: opValue, value: 5)
+])
+doAssert node.kind == opMul
+doAssert node.kids[0].value * node.kids[1].value == 15
diff --git a/tests/pragmas/tused.nim b/tests/pragmas/tused.nim
new file mode 100644
index 000000000..d0c533f9a
--- /dev/null
+++ b/tests/pragmas/tused.nim
@@ -0,0 +1,43 @@
+discard """
+  nimout: '''
+compile start
+tused.nim(17, 8) Hint: 'echoSub' is declared but not used [XDeclaredButNotUsed]
+compile end'''
+  output: "8\n8"
+  joinable: false
+"""
+
+# not joinable because paths in nimout differ when imported
+static:
+  echo "compile start"
+
+template implementArithOpsOld(T) =
+  proc echoAdd(a, b: T) =
+    echo a + b
+  proc echoSub(a, b: T) =
+    echo a - b
+
+template implementArithOpsNew(T) =
+  proc echoAdd(a, b: T) {.used.} =
+    echo a + b
+  proc echoSub(a, b: T) {.used.} =
+    echo a - b
+
+block:
+  # should produce warning for the unused 'echoSub'
+  implementArithOpsOld(int)
+  echoAdd 3, 5
+
+block:
+  # no warning produced for the unused 'echoSub'
+  implementArithOpsNew(int)
+  echoAdd 3, 5
+
+# issue #9896
+type
+  MyEnum {.used.} = enum
+    Val1, Val2, Val3
+
+
+static:
+  echo "compile end"
diff --git a/tests/pragmas/tuserpragma.nim b/tests/pragmas/tuserpragma.nim
new file mode 100644
index 000000000..784baa176
--- /dev/null
+++ b/tests/pragmas/tuserpragma.nim
@@ -0,0 +1,7 @@
+
+{.pragma: rtl, cdecl, exportc.}
+
+proc myproc(x, y: int): int {.rtl} =
+  nil
+
+
diff --git a/tests/pragmas/tuserpragma2.nim b/tests/pragmas/tuserpragma2.nim
new file mode 100644
index 000000000..c3f31cd5e
--- /dev/null
+++ b/tests/pragmas/tuserpragma2.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "can raise an unlisted exception: ref Exception"
+  file: "tuserpragma2.nim"
+  line: 11
+"""
+{.push warningAsError[Effect]: on.}
+# bug #7216
+{.pragma: my_pragma, raises: [].}
+
+proc test1 {.my_pragma.} =
+  raise newException(Exception, "msg")
+{.pop.}
diff --git a/tests/pragmas/tuserpragmaargs.nim b/tests/pragmas/tuserpragmaargs.nim
new file mode 100644
index 000000000..791d703ac
--- /dev/null
+++ b/tests/pragmas/tuserpragmaargs.nim
@@ -0,0 +1,5 @@
+var foo {.exportc: "abc".} = 123
+{.pragma: importc2, importc.}
+var bar {.importc2: "abc".}: int #[tt.Error
+                  ^ user pragma cannot have arguments]#
+echo bar
diff --git a/tests/pragmas/tvar_macro.nim b/tests/pragmas/tvar_macro.nim
new file mode 100644
index 000000000..3fb6e3e53
--- /dev/null
+++ b/tests/pragmas/tvar_macro.nim
@@ -0,0 +1,128 @@
+import macros
+
+block: # test usage
+  macro modify(sec) =
+    result = copy sec
+    result[0][0] = ident(repr(result[0][0]) & "Modified")
+
+  block:
+    let foo {.modify.} = 3
+    doAssert fooModified == 3
+
+  block: # in section 
+    let
+      a = 1
+      b {.modify.} = 2
+      c = 3
+    doAssert (a, bModified, c) == (1, 2, 3)
+
+block: # with single argument
+  macro appendToName(name: static string, sec) =
+    result = sec
+    result[0][0] = ident(repr(result[0][0]) & name)
+
+  block:
+    let foo {.appendToName: "Bar".} = 3
+    doAssert fooBar == 3
+
+  block:
+    let
+      a = 1
+      b {.appendToName("").} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 2, 3)
+
+macro appendToNameAndAdd(name: static string, incr: static int, sec) =
+  result = sec
+  result[0][0] = ident(repr(result[0][0]) & name)
+  result[0][2] = infix(result[0][2], "+", newLit(incr))
+
+block: # with multiple arguments
+  block:
+    let foo {.appendToNameAndAdd("Bar", 5).} = 3
+    doAssert fooBar == 8
+
+  block:
+    let
+      a = 1
+      b {.appendToNameAndAdd("", 15).} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 17, 3)
+
+block: # in other kinds of sections
+  block:
+    const
+      a = 1
+      b {.appendToNameAndAdd("", 15).} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 17, 3)
+    doAssert static(b) == b
+
+  block:
+    var
+      a = 1
+      b {.appendToNameAndAdd("", 15).} = 2
+      c = 3
+    doAssert (a, b, c) == (1, 17, 3)
+    b += a
+    c += b
+    doAssert (a, b, c) == (1, 18, 21)
+
+block: # with other pragmas
+  macro appendToNameAndAdd(name: static string, incr, sec) =
+    result = sec
+    result[0][0][0] = ident(repr(result[0][0][0]) & name)
+    result[0][0][1].add(ident"deprecated")
+    result[0][2] = infix(result[0][2], "+", incr)
+
+  var
+    a = 1
+    foo {.exportc: "exportedFooBar", appendToNameAndAdd("Bar", {'0'..'9'}), used.} = {'a'..'z', 'A'..'Z'}
+    b = 2
+  
+  doAssert (a, b) == (1, 2)
+
+  let importedFooBar {.importc: "exportedFooBar", nodecl.}: set[char]
+
+  doAssert importedFooBar == fooBar #[tt.Warning
+                             ^ fooBar is deprecated
+  ]#
+  
+
+block: # with stropping
+  macro `cast`(def) =
+    let def = def[0]
+    let
+      lhs = def[0]
+      typ = def[1]
+      ex = def[2]
+      addrTyp = if typ.kind == nnkEmpty: typ else: newTree(nnkPtrTy, typ)
+    result = quote do:
+      let tmp: `addrTyp` = unsafeAddr(`ex`)
+      template `lhs`: untyped = tmp[]
+  
+  macro assign(def) =
+    result = getAst(`cast`(def))
+
+  block:
+    let s = @["foo", "bar"]
+    let a {.`assign`.} = s[0]
+    doAssert a == "foo"
+    doAssert a[0].addr == s[0][0].addr
+
+  block:
+    let
+      s = @["foo", "bar"]
+      a {.`cast`.} = s[0]
+    doAssert a == "foo"
+    doAssert a[0].addr == s[0][0].addr
+
+block: # bug #15920
+  macro foo(def) =
+    result = def
+  proc fun1()=
+    let a {.foo.} = 1
+  template fun2()=
+    let a {.foo.} = 1
+  fun1() # ok
+  fun2() # BUG
diff --git a/tests/pragmas/twarning_off.nim b/tests/pragmas/twarning_off.nim
new file mode 100644
index 000000000..ccf07b9c4
--- /dev/null
+++ b/tests/pragmas/twarning_off.nim
@@ -0,0 +1,15 @@
+discard """
+  nimout: '''
+compile start
+warn_module.nim(6, 6) Hint: 'test' is declared but not used [XDeclaredButNotUsed]
+compile end
+'''
+"""
+
+static:
+  echo "compile start"
+
+import warn_module
+
+static:
+  echo "compile end"
diff --git a/tests/pragmas/warn_module.nim b/tests/pragmas/warn_module.nim
new file mode 100644
index 000000000..0d1e5f419
--- /dev/null
+++ b/tests/pragmas/warn_module.nim
@@ -0,0 +1,7 @@
+
+{.warning[UnusedImport]: off.}
+
+import hashes
+
+proc test(a: float): float =
+  a
diff --git a/tests/proc/mdefaultprocparam.nim b/tests/proc/mdefaultprocparam.nim
new file mode 100644
index 000000000..4a17277c0
--- /dev/null
+++ b/tests/proc/mdefaultprocparam.nim
@@ -0,0 +1,5 @@
+
+
+proc p*(f = (proc(): string = "hi")) =
+  echo f()
+
diff --git a/tests/proc/t15949.nim b/tests/proc/t15949.nim
new file mode 100644
index 000000000..6467ed5d3
--- /dev/null
+++ b/tests/proc/t15949.nim
@@ -0,0 +1,16 @@
+# bug #15949 and RFC #480
+
+proc procWarn(a, b = 1): (int, int) = (a, b) #[tt.Warning
+              ^ a, b all have default value '1', this may be unintentional, either use ';' (semicolon) or explicitly write each default value [ImplicitDefaultValue]]#
+
+proc procGood(a = 1, b = 1): (int, int) = (a, b)
+
+doAssert procGood() == (1, 1)
+doAssert procGood(b = 3) == (1, 3)
+doAssert procGood(a = 2) == (2, 1)
+doAssert procGood(a = 5, b = 6) == (5, 6)
+
+# The type (and default value propagation breaks in the below example
+# as semicolon is used instead of comma.
+proc procBad(a; b = 1): (int, int) = (a, b) #[tt.Error
+             ^ parameter 'a' requires a type]#
diff --git a/tests/proc/t17157.nim b/tests/proc/t17157.nim
new file mode 100644
index 000000000..020e93fce
--- /dev/null
+++ b/tests/proc/t17157.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "'untyped' is only allowed in templates and macros or magic procs"
+"""
+
+template something(op: proc (v: untyped): void): void =
+  discard
diff --git a/tests/proc/t19795.nim b/tests/proc/t19795.nim
new file mode 100644
index 000000000..677ec0a63
--- /dev/null
+++ b/tests/proc/t19795.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--mm:arc"
+"""
+
+# bug #19795
+# bug #21085
+
+type Vector = seq[int]
+
+var vect: Vector = newSeq[int](5)
+doAssert vect == @[0, 0, 0, 0, 0]
+
+# Needed to get the problem. Could also use "var".
+let vectCopy = vect
+
+# Then some procedure definition is needed to get the problem.
+proc p(): int = 3
+
+doAssert vect == @[0, 0, 0, 0, 0]
\ No newline at end of file
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/tcolonisproc.nim b/tests/proc/tcolonisproc.nim
new file mode 100644
index 000000000..c10dabcf1
--- /dev/null
+++ b/tests/proc/tcolonisproc.nim
@@ -0,0 +1,19 @@
+discard """
+output: '''
+1
+2
+'''
+"""
+
+proc p(a, b: int, c: proc ()) =
+  c()
+
+when false:
+  # language spec changed:
+  p(1, 3):
+    echo 1
+    echo 3
+
+p(1, 1, proc() =
+  echo 1
+  echo 2)
diff --git a/tests/proc/tdefaultprocparam.nim b/tests/proc/tdefaultprocparam.nim
new file mode 100644
index 000000000..90edfa8c9
--- /dev/null
+++ b/tests/proc/tdefaultprocparam.nim
@@ -0,0 +1,90 @@
+discard """
+output: '''
+hi
+hi
+topLevel|topLevel|
+topLevel2|topLevel2|
+inProc|inProc|
+inProc2|inProc2|
+topLevel|9
+topLevel2|10
+inProc|7
+inProc2|8
+must have been the wind..
+I'm there
+must have been the wind..
+I'm there
+symbol'a'symbol'a'
+symbol'b'symbol'b'
+symbol'a'symbol'b'
+symbol'a'9
+symbol'b'9
+symbol'a'0
+'''
+"""
+import mdefaultprocparam
+
+p()
+
+proc testP =
+  p()
+
+testP()
+
+proc p2(s: string, count = s): string = s & count
+
+proc testP2 =
+  echo p2 """inProc|"""
+  echo p2 """inProc2|"""
+
+echo p2 """topLevel|"""
+echo p2 """topLevel2|"""
+
+testP2()
+
+import macros
+macro dTT(a: typed) = echo a.treeRepr
+
+proc p3(s: string, count = len(s)): string = s & $count
+
+proc testP3 =
+  echo p3 """inProc|"""
+  echo p3 """inProc2|"""
+
+echo p3 """topLevel|"""
+echo p3 """topLevel2|"""
+
+testP3()
+
+proc cut(s: string, c = len(s)): string =
+  s[0..<s.len-c]
+
+echo "must have been the wind.." & cut "I'm gone"
+echo cut("I'm gone", 4) & "there"
+
+proc testCut =
+  echo "must have been the wind.." & cut "I'm gone"
+  echo cut("I'm gone", 4) & "there"
+
+testCut()
+
+var a = "symbol'a'"
+var b = "symbol'b'"
+
+block:
+  echo p2(a)
+block:
+  echo p2(b)
+block:
+  echo p2(a, b)
+block:
+  echo p3(a)
+  echo p3(b)
+  echo p3(a, 0)
+
+# bug #12252
+proc foo(a = 0, b = a.high, c = high(typeof(a))) = 
+  discard
+
+foo()
+
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/tfunc_type.nim b/tests/proc/tfunc_type.nim
new file mode 100644
index 000000000..93697acb1
--- /dev/null
+++ b/tests/proc/tfunc_type.nim
@@ -0,0 +1,14 @@
+
+discard """
+  errormsg: "func keyword is not allowed in type descriptions, use proc with {.noSideEffect.} pragma instead"
+"""
+
+type
+  MyObject = object
+    fn: func(a: int): int
+
+proc myproc(a: int): int =
+  echo "bla"
+  result = a
+
+var x = MyObject(fn: myproc)
\ No newline at end of file
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/tillegalreturntype.nim b/tests/proc/tillegalreturntype.nim
new file mode 100644
index 000000000..1076f7f75
--- /dev/null
+++ b/tests/proc/tillegalreturntype.nim
@@ -0,0 +1,21 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+tillegalreturntype.nim(11, 11) Error: return type 'typed' is only valid for macros and templates
+tillegalreturntype.nim(14, 11) Error: return type 'untyped' is only valid for macros and templates
+tillegalreturntype.nim(17, 41) Error: return type 'auto' cannot be used in forward declarations
+'''
+"""
+
+proc x(): typed =
+  discard
+
+proc y(): untyped =
+  discard
+
+proc test_proc[T, U](arg1: T, arg2: U): auto
+
+proc test_proc[T, U](arg1: T, arg2: U): auto =
+    echo "Proc has been called"
+    return arg1 / arg2
diff --git a/tests/proc/tinferlambdareturn.nim b/tests/proc/tinferlambdareturn.nim
new file mode 100644
index 000000000..e9e592871
--- /dev/null
+++ b/tests/proc/tinferlambdareturn.nim
@@ -0,0 +1,36 @@
+import std/[sugar, sequtils]
+
+block: # issue #23200
+  proc dosomething(iter: int -> (iterator: int)) =
+    discard
+  proc dosomething(iter: int -> seq[int]) =
+    discard
+  proc makeSeq(x: int): seq[int] =
+    @[x]
+  # Works fine with 1.6.12 and 1.6.14
+  dosomething(makeSeq)
+  # Works with 1.6.12, fails with 1.6.14
+  dosomething((y) => makeSeq(y))
+  dosomething(proc (y: auto): auto = makeSeq(y))
+  proc foo(y: auto): auto = makeSeq(y)
+  dosomething(foo)
+
+block: # issue #18866
+  proc somefn[T](list: openarray[T], op: proc (v: T): float) =
+    discard op(list[0])
+
+  type TimeD = object
+    year:  Natural
+    month: 1..12
+    day:   1..31
+
+  doAssert not compiles(@[TimeD()].somefn(proc (v: auto): auto =
+    v
+  ))
+  @[TimeD()].somefn(proc (v: auto): auto =
+    v.year.float
+  )
+  proc foo(v: auto): auto = v
+  doAssert not compiles(@[TimeD()].somefn(foo))
+  proc bar(v: auto): auto = v.year.float
+  @[TimeD()].somefn(bar)
diff --git a/tests/proc/tlambdadonotation.nim b/tests/proc/tlambdadonotation.nim
new file mode 100644
index 000000000..3160c0972
--- /dev/null
+++ b/tests/proc/tlambdadonotation.nim
@@ -0,0 +1,78 @@
+discard """
+output: '''
+issue #11812
+issue #10899
+123
+issue #11367
+event consumed!
+'''
+"""
+
+echo "issue #11812"
+
+proc run(a: proc()) = a()
+
+proc main() =
+  var test: int
+  run(proc() = test = 0)
+  run do:
+    test = 0
+
+main()
+
+
+echo "issue #10899"
+
+proc foo(x: proc {.closure.}) =
+  x()
+
+proc bar =
+  var x = 123
+  # foo proc = echo x     #[ ok ]#
+  foo: echo x             #[ SIGSEGV: Illegal storage access. (Attempt to read from nil?) ]#
+
+bar()
+
+echo "issue #11367"
+
+type
+
+  EventCB = proc()
+
+  Emitter = object
+    cb: EventCB
+
+  Subscriber = object
+    discard
+
+proc newEmitter(): Emitter =
+  result
+
+proc on_event(self: var Emitter, cb: EventCB) =
+  self.cb = cb
+
+proc emit(self: Emitter) =
+  self.cb()
+
+proc newSubscriber(): Subscriber =
+  result
+
+proc consume(self: Subscriber) =
+  echo "event consumed!"
+
+proc main2() =
+  var emitter = newEmitter()
+  var subscriber = newSubscriber()
+
+  proc foo() =
+    subscriber.consume()
+
+  emitter.on_event() do ():
+    subscriber.consume()
+
+  # this works
+  # emitter.on_event(foo)
+
+  emitter.emit()
+
+main2()
diff --git a/tests/proc/tlambdapragma.nim b/tests/proc/tlambdapragma.nim
new file mode 100644
index 000000000..daa952b1e
--- /dev/null
+++ b/tests/proc/tlambdapragma.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "invalid pragma: exportc"
+"""
+
+let _ = proc () {.exportc.} =
+  # this would previously cause a codegen error
+  discard
diff --git a/tests/proc/tnamedparams.nim b/tests/proc/tnamedparams.nim
new file mode 100644
index 000000000..d0774f0d8
--- /dev/null
+++ b/tests/proc/tnamedparams.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "type mismatch: got <input: string, filename: string, line: int literal(1), col: int literal(23)>"
+  file: "tnamedparams.nim"
+  line: 8
+"""
+import pegs
+
+discard parsePeg(
+      input = "input",
+      filename = "filename",
+      line = 1,
+      col = 23)
diff --git a/tests/proc/tnamedparams2.nim b/tests/proc/tnamedparams2.nim
new file mode 100644
index 000000000..9acdeed87
--- /dev/null
+++ b/tests/proc/tnamedparams2.nim
@@ -0,0 +1,15 @@
+import pegs
+
+discard parsePeg(
+      pattern = "input",
+      filename = "filename",
+      line = 1,
+      col = 23)
+
+# bug #12196
+type
+  Renderer = object
+
+var xs0, x0, xs1, x1: int
+proc init(xs=xs0; x=x0; renderer: Renderer; r: byte) = discard
+init(xs=xs1, x=x1, r=3, renderer=Renderer())
diff --git a/tests/proc/tnamedparams3.nim b/tests/proc/tnamedparams3.nim
new file mode 100644
index 000000000..e736c338c
--- /dev/null
+++ b/tests/proc/tnamedparams3.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <int literal(5), b: bool>"
+  line: 10
+"""
+
+# bug #2993
+proc test(i: int, a, b: bool) = discard
+#test(5, b = false)             #Missing param a
+
+5.test(b = false)             #Missing param a
diff --git a/tests/proc/tparamsindefault.nim b/tests/proc/tparamsindefault.nim
new file mode 100644
index 000000000..3fe917f2b
--- /dev/null
+++ b/tests/proc/tparamsindefault.nim
@@ -0,0 +1,120 @@
+discard """
+output: '''
+@[1, 2, 3]@[1, 2, 3]
+a
+a
+1
+3 is an int
+2 is an int
+miau is a string
+f1 1 1 1
+f1 2 3 3
+f1 10 20 30
+f2 100 100 100
+f2 200 300 300
+f2 300 400 400
+f3 10 10 20
+f3 10 15 25
+true true
+false true
+world
+typedescDefault
+'''
+"""
+
+template reject(x) =
+  assert(not compiles(x))
+
+block:
+  # https://github.com/nim-lang/Nim/issues/7756
+  proc foo[T](x: seq[T], y: seq[T] = x) =
+    echo x, y
+
+  let a = @[1, 2, 3]
+  foo(a)
+
+block:
+  # https://github.com/nim-lang/Nim/issues/1201
+  proc issue1201(x: char|int = 'a') = echo x
+
+  issue1201()
+  issue1201('a')
+  issue1201(1)
+
+  # https://github.com/nim-lang/Nim/issues/7000
+  proc test(a: int|string = 2) =
+    when a is int:
+        echo a, " is an int"
+    elif a is string:
+        echo a, " is a string"
+
+  test(3) # works
+  test() # works
+  test("miau")
+
+block:
+  # https://github.com/nim-lang/Nim/issues/3002 and similar
+  proc f1(a: int, b = a, c = b) =
+    echo "f1 ", a, " ", b, " ", c
+
+  proc f2(a: int, b = a, c: int = b) =
+    echo "f2 ", a, " ", b, " ", c
+
+  proc f3(a: int, b = a, c = a + b) =
+    echo "f3 ", a, " ", b, " ", c
+
+  f1 1
+  f1(2, 3)
+  f1 10, 20, 30
+  100.f2
+  200.f2 300
+  300.f2(400)
+
+  10.f3()
+  10.f3(15)
+
+  reject:
+    # This is a type mismatch error:
+    proc f4(a: int, b = a, c: float = b) = discard
+
+  reject:
+    # undeclared identifier
+    proc f5(a: int, b = c, c = 10) = discard
+
+  reject:
+    # undeclared identifier
+    proc f6(a: int, b = b) = discard
+
+  reject:
+    # undeclared identifier
+    proc f7(a = a) = discard
+
+block:
+  proc f(a: var int, b: ptr int, c = addr(a)) =
+    echo addr(a) == b, " ",  b == c
+
+  var x = 10
+  f(x, addr(x))
+  f(x, nil, nil)
+
+block:
+  # https://github.com/nim-lang/Nim/issues/1046
+  proc pySubstr(s: string, start: int, endd = s.len()): string =
+    var
+      revStart = start
+      revEnd = endd
+
+    if start < 0:
+      revStart = s.len() + start
+    if endd < 0:
+      revEnd = s.len() + endd
+
+    return s[revStart ..  revEnd-1]
+
+  echo pySubstr("Hello world", -5)
+
+
+# bug #11660
+
+func typedescDefault(T: typedesc; arg: T = 0) = debugEcho "typedescDefault"
+typedescDefault(int)
diff --git a/tests/proc/tproc.nim b/tests/proc/tproc.nim
new file mode 100644
index 000000000..d7f861991
--- /dev/null
+++ b/tests/proc/tproc.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''
+Hello
+1
+'''
+"""
+
+
+block t8357:
+  type T = ref int
+
+  let r = new(string)
+  r[] = "Hello"
+  echo r[]
+
+
+block t8683:
+  proc foo[T](bar: proc (x, y: T): int = system.cmp, baz: int) =
+    echo "1"
+  proc foo[T](bar: proc (x, y: T): int = system.cmp) =
+    echo "2"
+
+  foo[int](baz = 5)
+
+
+block tnestprc:
+  proc Add3(x: int): int =
+    proc add(x, y: int): int {.noconv.} =
+      result = x + y
+    result = add(x, 3)
+  doAssert Add3(7) == 10
diff --git a/tests/proc/tprocredef.nim b/tests/proc/tprocredef.nim
new file mode 100644
index 000000000..0cd6ec770
--- /dev/null
+++ b/tests/proc/tprocredef.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "redefinition of \'foo\'"
+  file: "tprocredef.nim"
+  line: 8
+"""
+
+proc foo(a: int, b: string) = discard
+proc foo(a: int, b: string) = discard
diff --git a/tests/proc/tprocvar.nim b/tests/proc/tprocvar.nim
new file mode 100644
index 000000000..14f24efdc
--- /dev/null
+++ b/tests/proc/tprocvar.nim
@@ -0,0 +1,39 @@
+discard """
+  output: '''
+papbpcpdpe7
+'''
+"""
+
+block genericprocvar:
+  proc foo[T](thing: T) =
+    discard thing
+  var a: proc (thing: int) {.nimcall.} = foo[int]
+
+
+block tprocvar2:
+  proc pa() {.cdecl.} = write(stdout, "pa")
+  proc pb() {.cdecl.} = write(stdout, "pb")
+  proc pc() {.cdecl.} = write(stdout, "pc")
+  proc pd() {.cdecl.} = write(stdout, "pd")
+  proc pe() {.cdecl.} = write(stdout, "pe")
+
+  const algos = [pa, pb, pc, pd, pe]
+  var x: proc (a, b: int): int {.cdecl.}
+
+  proc ha(c, d: int): int {.cdecl.} =
+    echo(c + d)
+    result = c + d
+
+  for a in items(algos):
+    a()
+
+  x = ha
+  discard x(3, 4)
+
+
+block tprocvars:
+  proc doSomething(v: int, x: proc(v:int):int): int = return x(v)
+  proc doSomething(v: int, x: proc(v:int)) = x(v)
+
+  doAssert doSomething(10, proc(v: int): int = return v div 2) == 5
+
diff --git a/tests/proc/tprocvarmismatch.nim b/tests/proc/tprocvarmismatch.nim
new file mode 100644
index 000000000..4d6be9be6
--- /dev/null
+++ b/tests/proc/tprocvarmismatch.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "type mismatch"
+  line: 17
+  file: "tprocvarmismatch.nim"
+"""
+
+type
+  TCallback = proc (a, b: int)
+
+proc huh(x, y: var int) =
+  x = 0
+  y = x+1
+
+proc so(c: TCallback) =
+  c(2, 4)
+
+so(huh)
+
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/tunderscoreparam.nim b/tests/proc/tunderscoreparam.nim
new file mode 100644
index 000000000..8d60603f1
--- /dev/null
+++ b/tests/proc/tunderscoreparam.nim
@@ -0,0 +1,122 @@
+discard """
+  targets: "c cpp js"
+"""
+
+import std/[assertions, sequtils]
+
+proc test() =
+  block:
+    proc ok(_, _, a: int): int =
+      doAssert not compiles(_)
+      a
+    doassert ok(4, 2, 5) == 5
+
+  block:
+    proc ok(_: int, _: int, a: int): int = a
+    doAssert ok(4, 2, 5) == 5
+
+  block:
+    proc ok(_: int, _: float, a: int): int = a
+    doAssert ok(1, 2.0, 5) == 5
+
+  block:
+    proc ok(_: int, _: float, _: string, a: int): int = a
+    doAssert ok(1, 2.6, "5", 5) == 5
+    
+  block:
+    proc ok[T](_, _, a: T): T =
+      doAssert not compiles(_)
+      a
+    doAssert ok(4, 2, 5) == 5
+    doAssert ok("a", "b", "c") == "c"
+    doAssert not compiles(ok(1, 2, "a"))
+  
+  block:
+    let ok = proc (_, _, a: int): int =
+      doAssert not compiles(_)
+      a
+    doAssert ok(4, 2, 5) == 5
+  
+  block:
+    proc foo(lam: proc (_, _, a: int): int): int =
+      lam(4, 2, 5)
+    doAssert foo(proc (_, _, a: auto): auto =
+      doAssert not compiles(_)
+      a) == 5
+    
+  block:
+    iterator fn(_, _: int, c: int): int = yield c
+    doAssert toSeq(fn(1,2,3)) == @[3]
+
+  block:
+    template ok(_, _, a: int): int = a
+    doAssert ok(4, 2, 5) == 5
+
+  block:
+    doAssert not (compiles do:
+      template bad(_: int): int = _
+      discard bad(3))
+
+  block:
+    template ok(_: int, _: int, a: int): int = a
+    doAssert ok(4, 2, 5) == 5
+
+  block:
+    template ok(_: int, _: float, a: int): int = a
+    doAssert ok(1, 2.0, 5) == 5
+
+  block:
+    template ok(_: int, _: float, _: string, a: int): int = a
+    doAssert ok(1, 2.6, "5", 5) == 5
+  
+  block:
+    template main2() =
+      iterator fn(_, _: int, c: int): int = yield c
+    main2()
+
+  block:
+    template main =
+      proc foo(_: int) =
+        let a = _
+    doAssert not compiles(main())
+  
+  block: # generic params
+    doAssert not (compiles do:
+      proc foo[_](t: typedesc[_]): seq[_] = @[default(_)]
+      doAssert foo[int]() == 0)
+  
+  block:
+    proc foo[_, _](): int = 123
+    doAssert foo[int, bool]() == 123
+  
+  block:
+    proc foo[T; U](_: typedesc[T]; _: typedesc[U]): (T, U) = (default(T), default(U))
+    doAssert foo(int, bool) == (0, false)
+
+proc closureTest() =
+  var x = 0
+
+  block:
+    proc foo(_, _: int) = x += 5
+
+    foo(1, 2)
+    doAssert x == 5
+
+  block:
+    proc foo(_: int, _: float) = x += 5
+
+    foo(1, 2)
+    doAssert x == 10
+
+  block:
+    proc foo(_: int, _: float, _: string) = x += 5
+
+    foo(1, 2, "5")
+    doAssert x == 15
+
+static: test()
+test()
+
+when not defined(js):
+  static: closureTest()
+closureTest()
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/proc/typed.nim b/tests/proc/typed.nim
new file mode 100644
index 000000000..2e8117634
--- /dev/null
+++ b/tests/proc/typed.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "'typed' is only allowed in templates and macros"
+  line: 6
+"""
+
+proc fun(x:typed)=discard
+fun(10)
diff --git a/tests/proc/untyped.nim b/tests/proc/untyped.nim
new file mode 100644
index 000000000..4a87f2b07
--- /dev/null
+++ b/tests/proc/untyped.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "'untyped' is only allowed in templates and macros or magic procs"
+  line: 14
+"""
+
+# magic procs are allowed with `untyped`
+proc declaredInScope2*(x: untyped): bool {.magic: "DefinedInScope", noSideEffect, compileTime.}
+proc bar(): bool =
+  var x = 1
+  declaredInScope2(x)
+static: doAssert bar()
+
+# but not non-magic procs
+proc fun(x:untyped)=discard
+fun(10)
diff --git a/tests/range/compilehelpers.nim b/tests/range/compilehelpers.nim
new file mode 100644
index 000000000..08f97a5bf
--- /dev/null
+++ b/tests/range/compilehelpers.nim
@@ -0,0 +1,5 @@
+template accept(e) =
+  static: assert(compiles(e))
+
+template reject(e) =
+  static: assert(not compiles(e))
diff --git a/tests/range/t19678.nim b/tests/range/t19678.nim
new file mode 100644
index 000000000..88f7eff89
--- /dev/null
+++ b/tests/range/t19678.nim
@@ -0,0 +1,17 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t19678.nim(13, 13) Error: range of string is invalid
+
+
+
+'''
+"""
+
+case "5":
+  of "0" .. "9":
+    discard
+  else:
+    discard
+
diff --git a/tests/range/tcompiletime_range_checks.nim b/tests/range/tcompiletime_range_checks.nim
new file mode 100644
index 000000000..2d3f292ec
--- /dev/null
+++ b/tests/range/tcompiletime_range_checks.nim
@@ -0,0 +1,52 @@
+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(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
+tcompiletime_range_checks.nim(41, 30) Error: 101 can't be converted to UnsignedRange
+tcompiletime_range_checks.nim(42, 32) Error: -9223372036854775808 can't be converted to SemiOutOfBounds
+tcompiletime_range_checks.nim(44, 22) Error: nan can't be converted to int32
+tcompiletime_range_checks.nim(46, 23) Error: 1e+100 can't be converted to uint64
+tcompiletime_range_checks.nim(49, 22) Error: 18446744073709551615 can't be converted to int64
+tcompiletime_range_checks.nim(50, 22) Error: 18446744073709551615 can't be converted to int32
+tcompiletime_range_checks.nim(51, 22) Error: 18446744073709551615 can't be converted to int16
+tcompiletime_range_checks.nim(52, 21) Error: 18446744073709551615 can't be converted to int8
+  '''
+"""
+
+type
+  UnsignedRange* = range[0'u64 .. 100'u64]
+  SemiOutOfBounds* = range[0x7ffffffffffffe00'u64 .. 0x8000000000000100'u64]
+  FullOutOfBounds* = range[0x8000000000000000'u64 .. 0x8000000000000200'u64]
+
+  FullNegativeRange* = range[-200 .. -100]
+  HalfNegativeRange* = range[-50 .. 50]
+  FullPositiveRange* = range[100 .. 200]
+
+let acceptA* = int32(0x7fffffff'i64)
+let acceptB* = (uint64(0'i64))
+let acceptD* = (HalfNegativeRange(25'u64))
+let acceptE* = (UnsignedRange(50'u64))
+let acceptF* = (SemiOutOfBounds(0x7ffffffffffffe00'i64))
+let acceptH* = (SemiOutOfBounds(0x8000000000000000'u64))
+
+let rejectA* = int32(0x80000000'i64)
+let rejectB* = (uint64(-1'i64))
+let rejectC* = (FullNegativeRange(0xff'u32))
+let rejectD* = (HalfNegativeRange(0xffffffffffffffff'u64)) # internal `intVal` is `-1` which would be in range.
+let rejectE* = (FullPositiveRange(300'u64))
+let rejectF* = (UnsignedRange(101'u64))
+let rejectG* = (SemiOutOfBounds(0x8000000000000000'i64))  #
+
+let rejectH* = (int32(NaN))
+let rejectI* = (int64(1e100))
+let rejectJ* = (uint64(1e100))
+
+# removed cross checks from tarithm.nim
+let rejectK* = (int64(0xFFFFFFFFFFFFFFFF'u64))
+let rejectL* = (int32(0xFFFFFFFFFFFFFFFF'u64))
+let rejectM* = (int16(0xFFFFFFFFFFFFFFFF'u64))
+let rejectN* = (int8(0xFFFFFFFFFFFFFFFF'u64))
diff --git a/tests/range/tenums.nim b/tests/range/tenums.nim
new file mode 100644
index 000000000..3cdf06fe2
--- /dev/null
+++ b/tests/range/tenums.nim
@@ -0,0 +1,33 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: "type mismatch: got <BC>"
+  nimout: '''
+tenums.nim(32, 20) Error: type mismatch: got <Letters>
+but expected one of:
+proc takesChristmasColor(color: ChristmasColors)
+  first type mismatch at position: 1
+  required type for color: ChristmasColors
+  but expression 'A' is of type: Letters
+
+expression: takesChristmasColor(A)
+tenums.nim(33, 20) Error: type mismatch: got <BC>
+but expected one of:
+proc takesChristmasColor(color: ChristmasColors)
+  first type mismatch at position: 1
+  required type for color: ChristmasColors
+  but expression 'BC(C)' is of type: BC
+
+expression: takesChristmasColor(BC(C))
+'''
+"""
+
+type
+  Colors = enum Red, Green, Blue
+  ChristmasColors = range[Red .. Green]
+  Letters = enum A, B, C
+  BC = range[B .. C]
+
+proc takesChristmasColor(color: ChristmasColors) = discard
+takesChristmasColor(Green)
+takesChristmasColor(A)
+takesChristmasColor(BC(C))
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/range/trange.nim b/tests/range/trange.nim
new file mode 100644
index 000000000..abfa7d474
--- /dev/null
+++ b/tests/range/trange.nim
@@ -0,0 +1,156 @@
+discard """
+  output: '''
+TSubRange: 5 from 1 to 10
+#FF3722
+'''
+"""
+
+
+block tbug499771:
+  type
+    TSubRange = range[1 .. 10]
+    TEnum = enum A, B, C
+  var sr: TSubRange = 5
+  echo("TSubRange: " & $sr & " from " & $low(TSubRange) & " to " &
+       $high(TSubRange))
+
+  const cset = {A} + {B}
+  doAssert A in cset
+  doAssert B in cset
+  doAssert C notin cset
+
+
+
+include compilehelpers
+block tmatrix3:
+  type
+    Matrix[M, N, T] = object
+      aij: array[M, array[N, T]]
+
+    Matrix2[T] = Matrix[range[0..1], range[0..1], T]
+
+    Matrix3[T] = Matrix[range[0..2], range[0..2], T]
+
+  proc mn(x: Matrix): Matrix.T = x.aij[0][0]
+
+  proc m2(x: Matrix2): Matrix2.T = x.aij[0][0]
+
+  proc m3(x: Matrix3): auto = x.aij[0][0]
+
+  var
+    matn: Matrix[range[0..3], range[0..2], int]
+    mat2: Matrix2[int]
+    mat3: Matrix3[float]
+
+  doAssert m3(mat3) == 0.0
+  doAssert mn(mat3) == 0.0
+  doAssert m2(mat2) == 0
+  doAssert mn(mat2) == 0
+  doAssert mn(matn) == 0
+
+  reject m3(mat2)
+  reject m3(matn)
+  reject m2(mat3)
+  reject m2(matn)
+
+
+
+block tn8vsint16:
+  type
+    n32 = range[0..high(int)]
+    n8 = range[0'i8..high(int8)]
+
+  proc `+`(a: n32, b: n32{nkIntLit}): n32 = discard
+
+  proc `-`(a: n8, b: n8): n8 = n8(system.`-`(a, b))
+
+  var x, y: n8
+  var z: int16
+
+  # ensure this doesn't call our '-' but system.`-` for int16:
+  doAssert z - n8(9) == -9
+
+
+
+import strutils
+block tcolors:
+  type TColor = distinct uint32
+
+  proc rgb(r, g, b: range[0..255]): TColor =
+    result = TColor(r or g shl 8 or b shl 16)
+  proc `$`(c: TColor): string =
+    result = "#" & toHex(uint32(c), 6)
+  echo rgb(34, 55, 255)
+
+  block:
+    type
+      TColor = distinct uint32
+      TColorComponent = distinct uint8
+
+    proc red(a: TColor): TColorComponent =
+      result = TColorComponent(uint32(a) and 0xff'u32)
+    proc green(a: TColor): TColorComponent =
+      result = TColorComponent(uint32(a) shr 8'u32 and 0xff'u32)
+    proc blue(a: TColor): TColorComponent =
+      result = TColorComponent(uint32(a) shr 16'u32 and 0xff'u32)
+    proc rgb(r, g, b: range[0..255]): TColor =
+      result = TColor(r or g shl 8 or b shl 8)
+
+    proc `+!` (a, b: TColorComponent): TColorComponent =
+      ## saturated arithmetic:
+      result = TColorComponent(min(int(uint8(a)) + int(uint8(b)), 255))
+
+    proc `+` (a, b: TColor): TColor =
+      ## saturated arithmetic for colors makes sense, I think:
+      return rgb(int(red(a) +! red(b)), int(green(a) +! green(b)), int(blue(a) +! blue(b)))
+
+    discard rgb(34, 55, 255)
+
+block:
+  type
+    R8  = range[0'u8 .. 10'u8]
+    R16 = range[0'u16 .. 10'u16]
+    R32 = range[0'u32 .. 10'u32]
+
+  var
+    x1 = R8(4)
+    x2 = R16(4)
+    x3 = R32(4)
+
+  doAssert $x1 & $x2 & $x3 == "444"
+
+block:
+  var x1: range[0'f..1'f] = 1
+  const x2: range[0'f..1'f] = 1
+  var x3: range[0'u8..1'u8] = 1
+  const x4: range[0'u8..1'u8] = 1
+
+  var x5: range[0'f32..1'f32] = 1'f64
+  const x6: range[0'f32..1'f32] = 1'f64
+
+  reject:
+    var x09: range[0'i8..1'i8] = 1.int
+  reject:
+    var x10: range[0'i64..1'i64] = 1'u64
+
+    const x11: range[0'f..1'f] = 2'f
+  reject:
+    const x12: range[0'f..1'f] = 2
+
+# ensure unsigned array indexing is remains lenient:
+var a: array[4'u, string]
+
+for i in 0..<a.len:
+  a[i] = "foo"
+
+# Check range to ordinal conversions
+block:
+  var
+    a: int16
+    b: range[0'i32..45'i32] = 3
+    c: uint16
+    d: range[0'u32..46'u32] = 3
+  a = b
+  c = d
+  doAssert a == b
+  doAssert c == d
diff --git a/tests/range/tsubrange.nim b/tests/range/tsubrange.nim
new file mode 100644
index 000000000..f778c55eb
--- /dev/null
+++ b/tests/range/tsubrange.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "cannot convert 60 to TRange"
+  line: 20
+"""
+
+type
+  TRange = range[0..40]
+
+proc p(r: TRange) =
+  discard
+
+var
+  r: TRange
+  y = 50
+r = y
+
+p y
+
+const
+  myConst: TRange = 60
diff --git a/tests/range/tsubrange2.nim b/tests/range/tsubrange2.nim
new file mode 100644
index 000000000..fbd1ca760
--- /dev/null
+++ b/tests/range/tsubrange2.nim
@@ -0,0 +1,15 @@
+discard """
+  outputsub: "value out of range: 50 notin 0 .. 40 [RangeDefect]"
+  exitcode: "1"
+"""
+
+type
+  TRange = range[0..40]
+
+proc p(r: TRange) =
+  discard
+
+var
+  r: TRange
+  y = 50
+p y
diff --git a/tests/range/tsubrange3.nim b/tests/range/tsubrange3.nim
new file mode 100644
index 000000000..55eb4618b
--- /dev/null
+++ b/tests/range/tsubrange3.nim
@@ -0,0 +1,17 @@
+discard """
+  outputsub: "value out of range: 50 notin 0 .. 40 [RangeDefect]"
+  exitcode: "1"
+"""
+
+type
+  TRange = range[0..40]
+
+proc p(r: TRange) =
+  discard
+
+var
+  r: TRange
+  y = 50
+r = y
+
+#p y
diff --git a/tests/readme.md b/tests/readme.md
new file mode 100644
index 000000000..f638ddc10
--- /dev/null
+++ b/tests/readme.md
@@ -0,0 +1,39 @@
+This directory contains the test cases.
+
+Each test must have a filename of the form: ``t*.nim``
+
+**Note:** [Testament](https://nim-lang.github.io/Nim/testament.html) is only aware of tests under a directory (eg `tests/foo/`) and will ignore
+top-level tests like `tests/tbar.nim`.
+
+# Specs
+
+Each test can contain a spec in a ``discard """ ... """`` block.
+
+**Check out the [``parseSpec`` procedure](https://github.com/nim-lang/Nim/blob/devel/testament/specs.nim#L315) in the ``specs`` module for a full and reliable reference**
+
+## action
+
+Specifies what action this test should take.
+
+**Default: run**
+
+Options:
+
+* ``compile`` - compiles the module and fails the test if compilations fails.
+* ``run`` - compiles and runs the module, fails the test if compilation or
+            execution of test code fails.
+* ``reject`` - compiles the module and fails the test if compilation succeeds.
+
+There are certain spec keys that imply ``run``, including ``output`` and
+``outputsub``.
+
+# Categories
+
+Each folder under this directory represents a test category, which can be
+tested by running `koch tests pcat <category>` (or `cat` to avoid parallel
+testing, which is slower).
+
+The folder ``dll`` contains simple DLL tests.
+
+The folder ``realtimeGC`` contains a test for validating that the realtime GC
+can run properly without linking against the nimrtl.dll/so.
diff --git a/tests/readme.txt b/tests/readme.txt
deleted file mode 100755
index c21b04acd..000000000
--- a/tests/readme.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-This directory contains the test cases.

-Each test must have a filename of the form: ``t*.nim``

-

-The testcases may contain the directives ``#ERROR``, ``#ERROR_IN``, 

-``#ERROR_MSG`` or ``#OUT``.

-``#ERROR`` is used to indicate that the compiler should report

-an error in the marked line (the line that contains the ``#ERROR``

-directive.)

-The format for ``#ERROR_IN`` is::

-

-     #ERROR_IN filename linenumber

-

-You can omit the extension of the filename (``.nim`` is then assumed).

-The format for ``#ERROR_MSG`` is::

-

-     #ERROR_MSG message

-

-This directive specifies the error message Nimrod shall produce.

-

-Tests which contain none of the ``#ERROR*`` directives should compile. 

-Thus they are executed after successful compilation and their output 

-is compared to the expected results (specified with the ``#OUT`` 

-directive). Tests which require user interaction are currently not 

-possible.

diff --git a/tests/realtimeGC/shared.nim b/tests/realtimeGC/shared.nim
new file mode 100644
index 000000000..8b5c05e47
--- /dev/null
+++ b/tests/realtimeGC/shared.nim
@@ -0,0 +1,59 @@
+import strutils
+
+# Global state, accessing with threads, no locks. Don't do this at
+# home.
+var gCounter: uint64
+var gTxStatus: bool
+var gRxStatus: bool
+var gConnectStatus: bool
+var gPttStatus: bool
+var gComm1Status: bool
+var gComm2Status: bool
+
+proc getTxStatus(): string =
+  result = if gTxStatus: "On" else: "Off"
+  gTxStatus = not gTxStatus
+
+proc getRxStatus(): string =
+  result = if gRxStatus: "On" else: "Off"
+  gRxStatus = not gRxStatus
+
+proc getConnectStatus(): string =
+  result = if gConnectStatus: "Yes" else: "No"
+  gConnectStatus = not gConnectStatus
+
+proc getPttStatus(): string =
+  result = if gPttStatus: "PTT: On" else: "PTT: Off"
+  gPttStatus = not gPttStatus
+
+proc getComm1Status(): string =
+  result = if gComm1Status: "On" else: "Off"
+  gComm1Status = not gComm1Status
+
+proc getComm2Status(): string =
+  result = if gComm2Status: "On" else: "Off"
+  gComm2Status = not gComm2Status
+
+proc status() {.exportc: "status", dynlib.} =
+  var tx_status = getTxStatus()
+  var rx_status = getRxStatus()
+  var connected = getConnectStatus()
+  var ptt_status = getPttStatus()
+  var str1: string = "[PilotEdge] Connected: $1  TX: $2  RX: $3" % [connected, tx_status, rx_status]
+  var a = getComm1Status()
+  var b = getComm2Status()
+  var str2: string = "$1  COM1: $2  COM2: $3" % [ptt_status, a, b]
+  # echo(str1)
+  # echo(str2)
+
+proc count() {.exportc: "count", dynlib.} =
+  var temp: uint64
+  for i in 0..100_000:
+    temp += 1
+  gCounter += 1
+  # echo("gCounter: ", gCounter)
+
+proc checkOccupiedMem() {.exportc: "checkOccupiedMem", dynlib.} =
+  if getOccupiedMem() > 10_000_000:
+    quit 1
+  discard
diff --git a/tests/realtimeGC/tmain.nim b/tests/realtimeGC/tmain.nim
new file mode 100644
index 000000000..ca0177e3d
--- /dev/null
+++ b/tests/realtimeGC/tmain.nim
@@ -0,0 +1,62 @@
+discard """
+  cmd: "nim $target --threads:on -d:release -d:useRealtimeGC $options $file"
+  joinable:false
+"""
+
+#[
+was: cmd: "nim $target --debuginfo $options $file"
+these dont' seem needed --debuginfo
+nor these from the previous main.nim.cfg: --app:console
+]#
+
+#[
+Test the realtime GC without linking nimrtl.dll/so.
+
+To build by hand and run the test for 35 minutes:
+`nim r --threads:on -d:runtimeSecs:2100 tests/realtimeGC/tmain.nim`
+]#
+
+import times, os, strformat, strutils
+from stdtest/specialpaths import buildDir
+# import threadpool
+
+const runtimeSecs {.intdefine.} = 5
+
+const file = "shared.nim"
+const dllname = buildDir / (DynlibFormat % "shared_D20210524T180506")
+
+static:
+  # D20210524T180826:here we compile the dependency on the fly
+  let nim = getCurrentCompilerExe()
+  let (output, exitCode) = gorgeEx(fmt"{nim} c -o:{dllname} --debuginfo --app:lib --threads:on -d:release -d:useRealtimeGC {file}")
+  doAssert exitCode == 0, output
+
+proc status() {.importc: "status", dynlib: dllname.}
+proc count() {.importc: "count", dynlib: dllname.}
+proc checkOccupiedMem() {.importc: "checkOccupiedMem", dynlib: dllname.}
+
+proc process() =
+  let startTime = getTime()
+  let runTime = cast[Time](runtimeSecs)
+  var accumTime: Time
+  while accumTime < runTime:
+    for i in 0..10:
+      count()
+    # echo("1. sleeping... ")
+    sleep(500)
+    for i in 0..10:
+      status()
+    # echo("2. sleeping... ")
+    sleep(500)
+    checkOccupiedMem()
+    accumTime = cast[Time]((getTime() - startTime))
+    # echo("--- Minutes left to run: ", int(int(runTime-accumTime)/60))
+
+proc main() =
+  process()
+  # parallel:
+  #   for i in 0..0:
+  #     spawn process()
+  # sync()
+
+main()
diff --git a/tests/rectest.nim b/tests/rectest.nim
index f08306cfd..54815e1f6 100755..100644
--- a/tests/rectest.nim
+++ b/tests/rectest.nim
@@ -1,6 +1,6 @@
-# Test the error message

-

-proc main() =

-  main()

-

-main()

+# Test the error message
+
+proc main() =
+  main()
+
+main()
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/sandwich/generic_library.nim b/tests/sandwich/generic_library.nim
new file mode 100644
index 000000000..43e7bd65f
--- /dev/null
+++ b/tests/sandwich/generic_library.nim
@@ -0,0 +1,6 @@
+
+proc libraryFunc*[T](x: T) =
+  mixin mixedIn, indirectlyMixedIn
+  echo mixedIn()
+  echo indirectlyMixedIn()
+
diff --git a/tests/sandwich/helper_module.nim b/tests/sandwich/helper_module.nim
new file mode 100644
index 000000000..d003bf044
--- /dev/null
+++ b/tests/sandwich/helper_module.nim
@@ -0,0 +1,3 @@
+
+proc indirectlyMixedIn*: int =
+  200
diff --git a/tests/sandwich/module_using_generic_library.nim b/tests/sandwich/module_using_generic_library.nim
new file mode 100644
index 000000000..bbb0d92a4
--- /dev/null
+++ b/tests/sandwich/module_using_generic_library.nim
@@ -0,0 +1,12 @@
+
+import
+  generic_library, helper_module
+
+proc mixedIn: int = 100
+
+proc makeUseOfLibrary*[T](x: T) =
+  bind mixedIn, indirectlyMixedIn
+  libraryFunc(x)
+
+when isMainModule:
+  makeUseOfLibrary "test"
diff --git a/tests/sandwich/tmain.nim b/tests/sandwich/tmain.nim
new file mode 100644
index 000000000..aa50bfb04
--- /dev/null
+++ b/tests/sandwich/tmain.nim
@@ -0,0 +1,9 @@
+discard """
+  output: '''100
+200'''
+"""
+
+import
+  module_using_generic_library
+
+makeUseOfLibrary "test"
diff --git a/tests/sdltest.nim b/tests/sdltest.nim
deleted file mode 100755
index ae7f1b41e..000000000
--- a/tests/sdltest.nim
+++ /dev/null
@@ -1,26 +0,0 @@
-# Test the SDL interface:

-

-import

-  SDL

-

-var

-  screen, greeting: PSDL_Surface

-  r: TSDL_Rect

-

-if SDL_Init(SDL_INIT_VIDEO) == 0:

-  screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE or SDL_ANYFORMAT)

-  if screen == nil:

-    write(stdout, "screen is nil!\n")

-  else:

-    greeting = SDL_LoadBmp("backgrnd.bmp")

-    if greeting == nil:

-      write(stdout, "greeting is nil!")

-    r.x = 0'i16

-    r.y = 0'i16

-    discard SDL_blitSurface(greeting, nil, screen, addr(r))

-    discard SDL_flip(screen)

-    SDL_Delay(3000)

-else:

-  write(stdout, "SDL_Init failed!\n")

-

-SDL_Quit()

diff --git a/tests/sets/m17385.nim b/tests/sets/m17385.nim
new file mode 100644
index 000000000..3919e067a
--- /dev/null
+++ b/tests/sets/m17385.nim
@@ -0,0 +1,11 @@
+import std/sets
+
+type
+  Diff*[T] = object
+    data: T
+
+proc test*[T](diff: Diff[T]) =
+  var bPopular = initHashSet[T]()
+  for element in bPopular.items():
+    echo element
+
diff --git a/tests/sets/t13764.nim b/tests/sets/t13764.nim
new file mode 100644
index 000000000..1634f113d
--- /dev/null
+++ b/tests/sets/t13764.nim
@@ -0,0 +1,6 @@
+discard """
+errormsg: "conversion from int literal(1000000) to range 0..255(int) is invalid"
+line: 6
+"""
+
+let a = {1_000_000} # Compiles
diff --git a/tests/sets/t15435.nim b/tests/sets/t15435.nim
new file mode 100644
index 000000000..5ead7e641
--- /dev/null
+++ b/tests/sets/t15435.nim
@@ -0,0 +1,29 @@
+# bug #15435
+discard """
+errormsg: "type mismatch: got <set[uint8], set[range 1..5(uint8)]>"
+nimout: '''t15435.nim(28, 13) Error: type mismatch: got <set[uint8], set[range 1..5(uint8)]>
+but expected one of:
+proc `<`[T](x, y: set[T]): bool
+  first type mismatch at position: 2
+  required type for y: set[T]
+  but expression 'x' is of type: set[range 1..5(uint8)]
+20 other mismatching symbols have been suppressed; compile with --showAllMismatches:on to see them
+
+expression: {1'u8, 5} < x'''
+"""
+
+
+
+
+
+
+## line 20
+var
+  x: set[range[1u8..5u8]]
+
+x.incl(1)
+x.incl(3)
+x.incl(5)
+
+if {1u8, 5} < x:
+  echo "successful"
diff --git a/tests/sets/t17385.nim b/tests/sets/t17385.nim
new file mode 100644
index 000000000..cc08b4882
--- /dev/null
+++ b/tests/sets/t17385.nim
@@ -0,0 +1,4 @@
+import m17385
+
+let a = Diff[int]()
+a.test()
diff --git a/tests/sets/t20997.nim b/tests/sets/t20997.nim
new file mode 100644
index 000000000..b320eee1a
--- /dev/null
+++ b/tests/sets/t20997.nim
@@ -0,0 +1,18 @@
+discard """
+  joinable: false
+"""
+
+{.passC: "-flto".}
+{.passL: "-flto".}
+
+template f(n: int) = discard card(default(set[range[0 .. (1 shl n) - 1]]))
+f( 7)
+f( 8)
+f( 9)
+f(10)
+f(11)
+f(12)
+f(13)
+f(14)
+f(15)
+f(16)
diff --git a/tests/sets/t2669.nim b/tests/sets/t2669.nim
new file mode 100644
index 000000000..0a92818fa
--- /dev/null
+++ b/tests/sets/t2669.nim
@@ -0,0 +1,6 @@
+discard """
+errormsg: "cannot convert 6 to range 1..5(int8)"
+line: 6
+"""
+
+var c: set[range[1i8..5i8]] = {1i8, 2i8, 6i8}
diff --git a/tests/sets/t5792.nim b/tests/sets/t5792.nim
new file mode 100644
index 000000000..297a1fc15
--- /dev/null
+++ b/tests/sets/t5792.nim
@@ -0,0 +1,17 @@
+discard """
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+type
+  T = enum
+    a
+    b
+    c
+  U = object
+    case k: T
+    of a:
+      x: int
+    of {b, c} - {a}:
+      y: int
+
+doAssert U(k: b, y: 1).y == 1
diff --git a/tests/sets/thugeset.nim b/tests/sets/thugeset.nim
new file mode 100644
index 000000000..1d82ebede
--- /dev/null
+++ b/tests/sets/thugeset.nim
@@ -0,0 +1,10 @@
+let x = 20_000
+let s = {x, 123} #[tt.Warning
+        ^ type 'int' is too big to be a `set` element, assuming a range of 0..65535, explicitly write this range to get rid of warning [AboveMaxSizeSet]]#
+doAssert x in s
+doAssert 20_000 in s
+{.push warningAsError[AboveMaxSizeSet]: on.}
+let s2 = {range[0..65535](x), 123}
+doAssert x in s
+doAssert 20_000 in s
+{.pop.}
diff --git a/tests/tnewsets.nim b/tests/sets/tnewsets.nim
index 415fe8f7e..f239d4aa2 100755..100644
--- a/tests/tnewsets.nim
+++ b/tests/sets/tnewsets.nim
@@ -1,6 +1,6 @@
-# new test for sets:

-

-const elem = ' '

-

-var s: set[char] = {elem}

-assert(elem in s and 'a' not_in s and 'c' not_in s )

+# new test for sets:
+
+const elem = ' '
+
+var s: set[char] = {elem}
+assert(elem in s and 'a' not_in s and 'c' not_in 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/tsets.nim b/tests/sets/tsets.nim
new file mode 100644
index 000000000..6125a3715
--- /dev/null
+++ b/tests/sets/tsets.nim
@@ -0,0 +1,133 @@
+discard """
+  targets: "c cpp"
+"""
+
+# Test builtin sets
+
+# xxx these tests are not very good, this should be revisited.
+
+when defined nimTestsTsetsGenerate:
+  # to generate enums for this test
+  var ret: string
+  for i in 0..<276:
+    ret.add "k" & $i & ", "
+  echo ret
+
+proc testSets(s: var set[char]) =
+  s = {'A', 'B', 'C', 'E'..'G'} + {'Z'} + s
+
+# test sets if the first element is different from 0:
+block:
+  type
+    TAZ = range['a'..'z']
+    TAZset = set[TAZ]
+    FakeTokType = 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, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, k124, k125, k126, k127, k128, k129, k130, k131, k132, k133, k134, k135, k136, k137, k138, k139, k140, k141, k142, k143, k144, k145, k146, k147, k148, k149, k150, k151, k152, k153, k154, k155, k156, k157, k158, k159, k160, k161, k162, k163, k164, k165, k166, k167, k168, k169, k170, k171, k172, k173, k174, k175, k176, k177, k178, k179, k180, k181, k182, k183, k184, k185, k186, k187, k188, k189, k190, k191, k192, k193, k194, k195, k196, k197, k198, k199, k200, k201, k202, k203, k204, k205, k206, k207, k208, k209, k210, k211, k212, k213, k214, k215, k216, k217, k218, k219, k220, k221, k222, k223, k224, k225, k226, k227, k228, k229, k230, k231, k232, k233, k234, k235, k236, k237, k238, k239, k240, k241, k242, k243, k244, k245, k246, k247, k248, k249
+    FakeTokTypeRange = range[k2..k101]
+    FakeTokTypes = set[FakeTokTypeRange]
+    Foo = object
+      field: set[Bar] #Bug: 6259
+    Bar = enum
+      bar1, bar2, bar3
+
+  const toktypes: FakeTokTypes = {FakeTokTypeRange(k2)..pred(k64), k72..k74}
+
+  var
+    s: set[char]
+    a: TAZset
+  s = {'0'..'9'}
+  testSets(s)
+  doAssert 'F' in s
+  a = {} #{'a'..'z'}
+  for x in low(TAZ) .. high(TAZ):
+    incl(a, x)
+    doAssert x in a
+
+  for x in low(FakeTokTypeRange) .. high(FakeTokTypeRange):
+    if x in tokTypes:
+      discard
+
+type
+  FakeMsgKind* = 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, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100, k101, k102, k103, k104, k105, k106, k107, k108, k109, k110, k111, k112, k113, k114, k115, k116, k117, k118, k119, k120, k121, k122, k123, k124, k125, k126, k127, k128, k129, k130, k131, k132, k133, k134, k135, k136, k137, k138, k139, k140, k141, k142, k143, k144, k145, k146, k147, k148, k149, k150, k151, k152, k153, k154, k155, k156, k157, k158, k159, k160, k161, k162, k163, k164, k165, k166, k167, k168, k169, k170, k171, k172, k173, k174, k175, k176, k177, k178, k179, k180, k181, k182, k183, k184, k185, k186, k187, k188, k189, k190, k191, k192, k193, k194, k195, k196, k197, k198, k199, k200, k201, k202, k203, k204, k205, k206, k207, k208, k209, k210, k211, k212, k213, k214, k215, k216, k217, k218, k219, k220, k221, k222, k223, k224, k225, k226, k227, k228, k229, k230, k231, k232, k233, k234, k235, k236, k237, k238, k239, k240, k241, k242, k243, k244, k245, k246, k247, k248, k249, k250, k251, k252, k253, k254, k255, k256, k257, k258, k259, k260, k261, k262, k263, k264, k265, k266, k267, k268, k269, k270, k271, k272, k273, k274, k275,
+
+doAssert pred(k260) == k259
+
+type
+  FakeMsgKind2 = range[k230..high(FakeMsgKind)]
+  FakeMsgKind3 = set[FakeMsgKind2]
+
+var gNotes: FakeMsgKind3 = {low(FakeMsgKind2)..high(FakeMsgKind2)} - {k233, k235}
+
+doAssert k233 notin gNotes
+
+# 7555
+doAssert {-1.int8, -2, -2}.card == 2
+doAssert {1, 2, 2, 3..5, 4..6}.card == 6
+
+# merely test the alias
+doAssert {-1.int8, -2, -2}.len == 2
+doAssert {1, 2, 2, 3..5, 4..6}.len == 6
+
+type Foo = enum
+  Foo1 = 0
+  Foo2 = 1
+  Foo3 = 3
+
+let x = { Foo1, Foo2 }
+# bug #8425
+
+block:
+  # bug #2880
+  type
+    FakeMsgKind = 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, k80, k81, k82, k83, k84, k85, k86, k87, k88, k89, k90, k91, k92, k93, k94, k95, k96, k97, k98, k99, k100
+
+  type
+    FakeMsgKind2 = range[FakeMsgKind.k50..high(FakeMsgKind)]
+    FakeMsgKind2s = set[FakeMsgKind2]
+
+  const
+    a1: array[0..0, FakeMsgKind2s] = [{low(FakeMsgKind2)..high(FakeMsgKind2)} - {FakeMsgKind.k99}]
+    a2 = a1[0]
+
+  var
+    s1: FakeMsgKind2s = a1[0]
+    s2: FakeMsgKind2s = a2
+
+  doAssert k99 notin s1
+  doAssert k99 notin s2
+
+block: # bug #23422
+  block:
+    var a: set[uint8] = {1'u8}
+
+    proc printLen(x: set[uint8]): int =
+      doAssert x.len == card(x)
+      result = card(x)
+
+    proc printLenVar(x: var set[uint8]): int =
+      doAssert x.len == card(x)
+      result = card(x)
+
+    doAssert a.len == 1
+    doAssert printLen(a) == 1
+    doAssert printLenVar(a) == card(a)
+
+  block:
+    type Fruit = enum
+      Apple, Banana, Melon
+
+    var a: set[Fruit] = {Apple}
+
+    proc printLen(x: set[Fruit]): int =
+      doAssert x.len == card(x)
+      result = card(x)
+
+    proc printLenVar(x: var set[Fruit]): int =
+      doAssert x.len == card(x)
+      result = card(x)
+
+    doAssert a.len == 1
+    doAssert printLen(a) == 1
+    doAssert printLenVar(a) == card(a)
diff --git a/tests/sets/tsets_various.nim b/tests/sets/tsets_various.nim
new file mode 100644
index 000000000..419bcfdcc
--- /dev/null
+++ b/tests/sets/tsets_various.nim
@@ -0,0 +1,286 @@
+discard """
+  targets: "c cpp js"
+"""
+
+import std/[sets, hashes]
+
+from std/sequtils import toSeq
+from std/algorithm import sorted
+from stdtest/testutils import whenVMorJs
+
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+block tsetpop:
+  var a = initHashSet[int]()
+  for i in 1..1000:
+    a.incl(i)
+  doAssert len(a) == 1000
+  for i in 1..1000:
+    discard a.pop()
+  doAssert len(a) == 0
+
+  var msg = ""
+  try:
+    echo a.pop()
+  except KeyError as e:
+    msg = e.msg
+  doAssert msg == "set is empty"
+
+
+
+block tsets_lt:
+  var s, s1: set[char]
+  s = {'a'..'d'}
+  s1 = {'a'..'c'}
+  doAssert s1 < s
+  doAssert s1 * s == {'a'..'c'}
+  doAssert s1 <= s
+
+
+
+block tsets2:
+  const
+    data = [
+      "34", "12",
+      "90", "0",
+      "1", "2",
+      "3", "4",
+      "5", "6",
+      "7", "8",
+      "9", "---00",
+      "10", "11", "19",
+      "20", "30", "40",
+      "50", "60", "70",
+      "80"]
+
+  block tableTest1:
+    var t = initHashSet[tuple[x, y: int]]()
+    t.incl((0,0))
+    t.incl((1,0))
+    doAssert(not t.containsOrIncl((0,1)))
+    t.incl((1,1))
+
+    for x in 0..1:
+      for y in 0..1:
+        doAssert((x,y) in t)
+    #doAssert($t ==
+    #  "{(x: 0, y: 0), (x: 0, y: 1), (x: 1, y: 0), (x: 1, y: 1)}")
+
+  block setTest2:
+    var t = initHashSet[string]()
+    t.incl("test")
+    t.incl("111")
+    t.incl("123")
+    t.excl("111")
+    t.incl("012")
+    t.incl("123") # test duplicates
+
+    doAssert "123" in t
+    doAssert "111" notin t # deleted
+
+    doAssert t.missingOrExcl("000")
+    doAssert "000" notin t
+    doAssert t.missingOrExcl("012") == false
+    doAssert "012" notin t
+
+    doAssert t.containsOrIncl("012") == false
+    doAssert t.containsOrIncl("012")
+    doAssert "012" in t # added back
+
+    for key in items(data): t.incl(key)
+    for key in items(data): doAssert key in t
+
+    for key in items(data): t.excl(key)
+    for key in items(data): doAssert key notin t
+
+  block orderedSetTest1:
+    var t = data.toOrderedSet
+    for key in items(data): doAssert key in t
+    var i = 0
+    # `items` needs to yield in insertion order:
+    for key in items(t):
+      doAssert key == data[i]
+      inc(i)
+
+
+
+block tsets3:
+  let
+    s1: HashSet[int] = toHashSet([1, 2, 4, 8, 16])
+    s2: HashSet[int] = toHashSet([1, 2, 3, 5, 8])
+    s3: HashSet[int] = toHashSet([3, 5, 7])
+
+  block union:
+    let
+      s1_s2 = union(s1, s2)
+      s1_s3 = s1 + s3
+      s2_s3 = s2 + s3
+
+    doAssert s1_s2.len == 7
+    doAssert s1_s3.len == 8
+    doAssert s2_s3.len == 6
+
+    for i in s1:
+      doAssert i in s1_s2
+      doAssert i in s1_s3
+    for i in s2:
+      doAssert i in s1_s2
+      doAssert i in s2_s3
+    for i in s3:
+      doAssert i in s1_s3
+      doAssert i in s2_s3
+
+    doAssert((s1 + s1) == s1)
+    doAssert((s2 + s1) == s1_s2)
+
+  block intersection:
+    let
+      s1_s2 = intersection(s1, s2)
+      s1_s3 = intersection(s1, s3)
+      s2_s3 = s2 * s3
+
+    doAssert s1_s2.len == 3
+    doAssert s1_s3.len == 0
+    doAssert s2_s3.len == 2
+
+    for i in s1_s2:
+      doAssert i in s1
+      doAssert i in s2
+    for i in s1_s3:
+      doAssert i in s1
+      doAssert i in s3
+    for i in s2_s3:
+      doAssert i in s2
+      doAssert i in s3
+
+    doAssert((s2 * s2) == s2)
+    doAssert((s3 * s2) == s2_s3)
+
+  block symmetricDifference:
+    let
+      s1_s2 = symmetricDifference(s1, s2)
+      s1_s3 = s1 -+- s3
+      s2_s3 = s2 -+- s3
+
+    doAssert s1_s2.len == 4
+    doAssert s1_s3.len == 8
+    doAssert s2_s3.len == 4
+
+    for i in s1:
+      doAssert i in s1_s2 xor i in s2
+      doAssert i in s1_s3 xor i in s3
+    for i in s2:
+      doAssert i in s1_s2 xor i in s1
+      doAssert i in s2_s3 xor i in s3
+    for i in s3:
+      doAssert i in s1_s3 xor i in s1
+      doAssert i in s2_s3 xor i in s2
+
+    doAssert((s3 -+- s3) == initHashSet[int]())
+    doAssert((s3 -+- s1) == s1_s3)
+
+  block difference:
+    let
+      s1_s2 = difference(s1, s2)
+      s1_s3 = difference(s1, s3)
+      s2_s3 = s2 - s3
+
+    doAssert s1_s2.len == 2
+    doAssert s1_s3.len == 5
+    doAssert s2_s3.len == 3
+
+    for i in s1:
+      doAssert i in s1_s2 xor i in s2
+      doAssert i in s1_s3 xor i in s3
+    for i in s2:
+      doAssert i in s2_s3 xor i in s3
+
+    doAssert((s2 - s2) == initHashSet[int]())
+
+  block disjoint:
+    doAssert(not disjoint(s1, s2))
+    doAssert disjoint(s1, s3)
+    doAssert(not disjoint(s2, s3))
+    doAssert(not disjoint(s2, s2))
+
+block: # https://github.com/nim-lang/Nim/issues/13496
+  template testDel(body) =
+    block:
+      body
+      t.incl(15)
+      t.incl(19)
+      t.incl(17)
+      t.incl(150)
+      t.excl(150)
+      doAssert t.len == 3
+      doAssert sortedItems(t) == @[15, 17, 19]
+      var s = newSeq[int]()
+      for v in t: s.add(v)
+      doAssert s.len == 3
+      doAssert sortedItems(s) == @[15, 17, 19]
+      when t is OrderedSet:
+        doAssert sortedPairs(t) == @[(a: 0, b: 15), (a: 1, b: 19), (a: 2, b: 17)]
+        doAssert toSeq(t) == @[15, 19, 17]
+
+  testDel(): (var t: HashSet[int])
+  testDel(): (var t: OrderedSet[int])
+
+block: # test correctness after a number of inserts/deletes
+  template testDel(body) =
+    block:
+      body
+      var expected: seq[int]
+      let n = 100
+      let n2 = n*2
+      for i in 0..<n:
+        t.incl(i)
+      for i in 0..<n:
+        if i mod 3 == 0:
+          t.excl(i)
+      for i in n..<n2:
+        t.incl(i)
+      for i in 0..<n2:
+        if i mod 7 == 0:
+          t.excl(i)
+
+      for i in 0..<n2:
+        if (i>=n or i mod 3 != 0) and i mod 7 != 0:
+          expected.add i
+
+      for i in expected: doAssert i in t
+      doAssert t.len == expected.len
+      doAssert sortedItems(t) == expected
+
+  testDel(): (var t: HashSet[int])
+  testDel(): (var t: OrderedSet[int])
+
+
+template main() =
+  # xxx move all tests inside this
+  block:
+    let a = {true, false}
+    doAssert $a == "{false, true}"
+    doAssert a.len == 2
+
+  block:
+    let a = {false .. true}
+    doAssert $a == "{false, true}"
+    doAssert a.len == 2
+
+  block:
+    let a = {false .. false}
+    doAssert $a == "{false}"
+    doAssert a.len == 1
+
+  block: # bug #16123
+    whenVMorJs: discard
+    do:
+      type CallType = proc() {.closure.}
+      var setA = initHashSet[CallType]()
+      let foo = proc() = discard
+      setA.incl(foo)
+      doAssert setA.contains(foo)
+
+static: main()
+main()
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/showoff/tdrdobbs_examples.nim b/tests/showoff/tdrdobbs_examples.nim
new file mode 100644
index 000000000..c61e177dc
--- /dev/null
+++ b/tests/showoff/tdrdobbs_examples.nim
@@ -0,0 +1,134 @@
+discard """
+  output: '''108
+11 -1 1936
+0.4
+true
+truefalse'''
+"""
+
+proc `++`(x: var int; y: int = 1; z: int = 0) =
+  x = x + y + z
+
+var g = 70
+++g
+g ++ 7
+g.`++`(10, 20)
+echo g
+
+
+#let lv = stdin.readline
+#var vv = stdin.readline
+#vv = "abc" # valid, reassignment allowed
+#lv = "abc" # fails at compile time
+
+#proc square(x: int): int = x*x
+
+template square(x: int): int =
+  # ensure 'x' is only evaluated once:
+  let y = x
+  y * y
+
+proc mostSignificantBit(n: int): int =
+  # naive algorithm:
+  var n = n
+  while n != 0:
+    n = n shr 1
+    result += 1
+  result -= 1
+
+const msb3999 = mostSignificantBit(3999)
+
+echo msb3999, " ", mostSignificantBit(0), " ", square(44)
+
+proc filter[T](a: openArray[T], predicate: proc (x: T): bool): seq[T] =
+  result = @[] # @[] constructs the empty seq
+  for x in a:
+    if predicate(x): result.add(x)
+
+proc map[T, S](a: openArray[T], fn: proc (x: T): S): seq[S] =
+  newSeq(result, a.len)
+  for i in 0 ..< a.len: result[i] = fn(a[i])
+
+
+type
+  FormulaKind = enum
+    fkVar,        ## element is a variable like 'X'
+    fkLit,        ## element is a literal like 0.1
+    fkAdd,        ## element is an addition operation
+    fkMul,        ## element is a multiplication operation
+    fkExp         ## element is an exponentiation operation
+
+type
+  Formula = ref object
+    case kind: FormulaKind
+    of fkVar: name: string
+    of fkLit: value: float
+    of fkAdd, fkMul, fkExp: left, right: Formula
+
+from math import pow
+
+proc evaluate(n: Formula, varToVal: proc (name: string): float): float =
+  case n.kind
+  of fkVar: varToVal(n.name)
+  of fkLit: n.value
+  of fkAdd: evaluate(n.left, varToVal) + evaluate(n.right, varToVal)
+  of fkMul: evaluate(n.left, varToVal) * evaluate(n.right, varToVal)
+  of fkExp: pow(evaluate(n.left, varToVal), evaluate(n.right, varToVal))
+
+echo evaluate(Formula(kind: fkLit, value: 0.4), nil)
+
+proc isPolyTerm(n: Formula): bool =
+  n.kind == fkMul and n.left.kind == fkLit and (let e = n.right;
+    e.kind == fkExp and e.left.kind == fkVar and e.right.kind == fkLit)
+
+proc isPolynomial(n: Formula): bool =
+  isPolyTerm(n) or
+    (n.kind == fkAdd and isPolynomial(n.left) and isPolynomial(n.right))
+
+let myFormula = Formula(kind: fkMul,
+                        left: Formula(kind: fkLit, value: 2.0),
+                        right: Formula(kind: fkExp,
+                          left: Formula(kind: fkVar, name: "x"),
+                          right: Formula(kind: fkLit, value: 5.0)))
+
+echo isPolyTerm(myFormula)
+
+proc pat2kind(pattern: string): FormulaKind =
+  case pattern
+  of "^": fkExp
+  of "*": fkMul
+  of "+": fkAdd
+  of "x": fkVar
+  of "c": fkLit
+  else:   fkVar # no error reporting for reasons of simplicity
+
+import macros
+
+proc matchAgainst(n, pattern: NimNode): NimNode {.compileTime.} =
+  template `@`(current, field: untyped): untyped =
+    newDotExpr(current, newIdentNode(astToStr(field)))
+
+  template `==@`(n, pattern: untyped): untyped =
+    newCall("==", n@kind, newIdentNode($pat2kind($pattern.ident)))
+
+  case pattern.kind
+  of CallNodes:
+    result = newCall("and",
+      n ==@ pattern[0],
+      matchAgainst(n@left, pattern[1]))
+    if pattern.len == 3:
+      result = newCall("and", result.copy,
+        matchAgainst(n@right, pattern[2]))
+  of nnkIdent:
+    result = n ==@ pattern
+  of nnkPar:
+    result = matchAgainst(n, pattern[0])
+  else:
+    error "invalid pattern"
+
+macro `=~` (n: Formula, pattern: untyped): bool =
+  result = matchAgainst(n, pattern)
+
+proc isPolyTerm2(n: Formula): bool = n =~ c * x^c
+
+echo isPolyTerm2(myFormula), isPolyTerm2(Formula(kind: fkLit, value: 0.7))
diff --git a/tests/showoff/tformatopt.nim b/tests/showoff/tformatopt.nim
new file mode 100644
index 000000000..420dd026b
--- /dev/null
+++ b/tests/showoff/tformatopt.nim
@@ -0,0 +1,57 @@
+discard """
+  output: '''(a: 3
+b: 4
+s: abc
+)'''
+"""
+
+import macros
+
+proc invalidFormatString() =
+  echo "invalidFormatString"
+
+template formatImpl(handleChar: untyped) =
+  var i = 0
+  while i < f.len:
+    if f[i] == '$':
+      case f[i+1]
+      of '1'..'9':
+        var j = 0
+        i += 1
+        while f[i] in {'0'..'9'}:
+          j = j * 10 + ord(f[i]) - ord('0')
+          i += 1
+        result.add(a[j-1])
+      else:
+        invalidFormatString()
+    else:
+      result.add(handleChar(f[i]))
+      i += 1
+
+proc `%`*(f: string, a: openArray[string]): string =
+  template identity(x: untyped): untyped = x
+  result = ""
+  formatImpl(identity)
+
+macro optFormat{`%`(f, a)}(f: string{lit}, a: openArray[string]): untyped =
+  result = newNimNode(nnkBracket)
+  let f = f.strVal
+  formatImpl(newLit)
+  result = nestList(newIdentNode("&"), result)
+
+template optAdd1{x = y; add(x, z)}(x, y, z: string) =
+  x = y & z
+
+proc `/&` [T: object](x: T): string =
+  result = "("
+  for name, value in fieldPairs(x):
+    result.add("$1: $2\n" % [name, $value])
+  result.add(")")
+
+type
+  MyObject = object
+    a, b: int
+    s: string
+
+let obj = MyObject(a: 3, b: 4, s: "abc")
+echo(/&obj)
diff --git a/tests/showoff/tgenericmacrotypes.nim b/tests/showoff/tgenericmacrotypes.nim
new file mode 100644
index 000000000..cc07f4355
--- /dev/null
+++ b/tests/showoff/tgenericmacrotypes.nim
@@ -0,0 +1,55 @@
+# issue #7974
+
+import macros
+
+macro genTypeA(arg: typed): untyped =
+  if arg.typeKind != ntyTypeDesc:
+    error("expected typedesc", arg)
+
+  result = arg.getTypeInst[1]
+
+macro genTypeB(arg: typed): untyped =
+  if arg.typeKind != ntyTypeDesc:
+    error("expected typedesc", arg)
+
+
+  let typeSym = arg.getTypeInst[1]
+  result =
+    nnkTupleTy.newTree(
+      nnkIdentDefs.newTree(
+        ident"a", typeSym, newEmptyNode()
+      )
+    )
+
+type
+  # this is the trivial case, MyTypeA[T] is basically just T, nothing else. But it works.
+  MyTypeA[T] = genTypeA(T)
+  # in this case I generate `tuple[a: T]`. This this is something the compiler does not want
+  MyTypeB[T] = genTypeB(T)
+
+# these are just alias types for int32 and float32, nothing really happens, but it works
+var a1: MyTypeA[int32]
+doAssert a1 is MyTypeA[int32]
+doAssert a1 is int32
+a1 = 0'i32
+var a2: MyTypeA[float32]
+doAssert a2 is MyTypeA[float32]
+doAssert a2 is float32
+a2 = 0'f32
+var a3: MyTypeA[float32]
+doAssert a3 is MyTypeA[float32]
+doAssert a3 is float32
+a3 = 0'f32
+
+var b1: MyTypeB[int32]   # cannot generate VM code fur tuple[a: int32]
+doAssert b1 is MyTypeB[int32]
+doAssert b1 is tuple[a: int32]
+b1 = (a: 0'i32)
+var b2: MyTypeB[float32]
+doAssert b2 is MyTypeB[float32]
+doAssert b2 is tuple[a: float32]
+b2 = (a: 0'f32)
+var b3: MyTypeB[float32]
+doAssert b3 is MyTypeB[float32]
+doAssert b3 is tuple[a: float32]
+b3 = (a: 0'f32)
diff --git a/tests/showoff/thello2.nim b/tests/showoff/thello2.nim
new file mode 100644
index 000000000..3ccb4e3be
--- /dev/null
+++ b/tests/showoff/thello2.nim
@@ -0,0 +1,11 @@
+discard """
+  output: '''(a: 3, b: 4, s: "abc")'''
+"""
+
+type
+  MyObject = object
+        a, b: int
+        s: string
+
+let obj = MyObject(a: 3, b: 4, s: "abc")
+echo obj
diff --git a/tests/showoff/thtml1.nim b/tests/showoff/thtml1.nim
new file mode 100644
index 000000000..fe0cd3b1e
--- /dev/null
+++ b/tests/showoff/thtml1.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "<br>"
+"""
+
+template htmlTag(tag: untyped) =
+  proc tag(): string = "<" & astToStr(tag) & ">"
+
+htmlTag(br)
+htmlTag(html)
+
+echo br()
diff --git a/tests/showoff/thtml2.nim b/tests/showoff/thtml2.nim
new file mode 100644
index 000000000..dcf6534a5
--- /dev/null
+++ b/tests/showoff/thtml2.nim
@@ -0,0 +1,37 @@
+discard """
+  output: "<html><head><title>now look at this</title></head><body><ul><li>Nim is quite capable</li></ul></body></html>"
+"""
+
+import strutils
+
+template html(name, matter: untyped) =
+  proc name(): string =
+    result = "<html>"
+    matter
+    result.add("</html>")
+
+template nestedTag(tag: untyped) =
+  template tag(matter: untyped) =
+    result.add("<" & astToStr(tag) & ">")
+    matter
+    result.add("</" & astToStr(tag) & ">")
+
+template simpleTag(tag: untyped) =
+  template tag(matter: untyped) =
+    result.add("<$1>$2</$1>" % [astToStr(tag), matter])
+
+nestedTag body
+nestedTag head
+nestedTag ul
+simpleTag title
+simpleTag li
+
+
+html mainPage:
+  head:
+    title "now look at this"
+  body:
+    ul:
+      li "Nim is quite capable"
+
+echo mainPage()
diff --git a/tests/showoff/tonce.nim b/tests/showoff/tonce.nim
new file mode 100644
index 000000000..ed2684dcf
--- /dev/null
+++ b/tests/showoff/tonce.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''first call of p
+some call of p
+new instantiation
+some call of p'''
+"""
+
+template once(body) =
+  var x {.global.} = false
+  if not x:
+    x = true
+    body
+
+proc p() =
+  once:
+    echo "first call of p"
+  echo "some call of p"
+
+p()
+once:
+  echo "new instantiation"
+p()
diff --git a/tests/showoff/tquasiquote.nim b/tests/showoff/tquasiquote.nim
new file mode 100644
index 000000000..404712a02
--- /dev/null
+++ b/tests/showoff/tquasiquote.nim
@@ -0,0 +1,14 @@
+discard """
+  outputsub: '''tquasiquote.nim(14, 8): Check failed: 1 > 2'''
+"""
+
+import macros
+
+macro check(ex: untyped): untyped =
+  var info = ex.lineInfo
+  var expString = ex.toStrLit
+  result = quote do:
+    if not `ex`:
+      echo `info`, ": Check failed: ", `expString`
+
+check 1 > 2
diff --git a/tests/specialops/tcallops.nim b/tests/specialops/tcallops.nim
new file mode 100644
index 000000000..c541a0c1d
--- /dev/null
+++ b/tests/specialops/tcallops.nim
@@ -0,0 +1,49 @@
+import macros
+
+{.experimental: "callOperator".}
+
+type Foo[T: proc] = object
+  callback: T
+
+macro `()`(foo: Foo, args: varargs[untyped]): untyped =
+  result = newCall(newDotExpr(foo, ident"callback"))
+  for a in args:
+    result.add(a)
+
+var f1Calls = 0
+var f = Foo[proc()](callback: proc() = inc f1Calls)
+doAssert f1Calls == 0
+f()
+doAssert f1Calls == 1
+var f2Calls = 0
+f.callback = proc() = inc f2Calls
+doAssert f2Calls == 0
+f()
+doAssert f2Calls == 1
+
+let g = Foo[proc (x: int): int](callback: proc (x: int): int = x * 2 + 1)
+doAssert g(15) == 31
+
+proc `()`(args: varargs[string]): string =
+  result = "("
+  for a in args: result.add(a)
+  result.add(')')
+
+let a = "1"
+let b = "2"
+let c = "3"
+
+doAssert a(b) == "(12)"
+doAssert a.b(c) == `()`(b, a, c)
+doAssert (a.b)(c) == `()`(a.b, c)
+doAssert `()`(a.b, c) == `()`(`()`(b, a), c)
+
+block: # bug #1072
+  var x: int
+
+  proc foo(some:int):int = some
+  proc `()`(l,r:string): string = discard
+
+  block:
+    var foo = 42
+    doAssert x.foo == 0
diff --git a/tests/specialops/tcallprecedence.nim b/tests/specialops/tcallprecedence.nim
new file mode 100644
index 000000000..6116f83d5
--- /dev/null
+++ b/tests/specialops/tcallprecedence.nim
@@ -0,0 +1,44 @@
+import macros
+
+{.experimental: "dotOperators".}
+{.experimental: "callOperator".}
+
+block:
+  template `.()`(foo: int, args: varargs[untyped]): untyped {.used.} =
+    ".()"
+
+  template `()`(foo: int, args: varargs[untyped]): untyped =
+    "()"
+
+  let a = (b: 1)
+  let c = 3
+
+  doAssert a.b(c) == "()"
+  doAssert not compiles(a(c))
+  doAssert (a.b)(c) == "()"
+
+macro `()`(args: varargs[typed]): untyped =
+  result = newLit("() " & args.treeRepr)
+
+macro `.`(args: varargs[typed]): untyped =
+  result = newLit(". " & args.treeRepr)
+
+block:
+  let a = 1
+  let b = 2
+  doAssert a.b == `()`(b, a)
+
+block:
+  let a = 1
+  proc b(): int {.used.} = 2
+  doAssert a.b == `.`(a, b)
+
+block:
+  let a = 1
+  proc b(x: int): int = x + 1
+  let c = 3
+
+  doAssert a.b(c) == `.`(a, b, c)
+  doAssert a(b) == `()`(a, b)
+  doAssert (a.b)(c) == `()`(a.b, c)
+  doAssert a.b == b(a)
diff --git a/tests/specialops/tdotops.nim b/tests/specialops/tdotops.nim
new file mode 100644
index 000000000..ca5eee665
--- /dev/null
+++ b/tests/specialops/tdotops.nim
@@ -0,0 +1,97 @@
+discard """
+  output: '''
+
+10
+assigning z = 20
+reading field y
+20
+call to y
+dot call
+no params call to a
+100
+no params call to b
+100
+one param call to c with 10
+100
+0 4
+'''
+"""
+
+block:
+  type Foo = object
+  var a: Foo
+  template `.`(a: Foo, b: untyped): untyped = astToStr(b)
+  template callme(a, f): untyped = a.f
+  doAssert callme(a, f2) == "f2" # not `f`
+  doAssert a.callme(f3) == "f3"
+
+type
+  T1 = object
+    x*: int
+
+  TD = distinct T1
+
+  T2 = object
+    x: int
+
+template `.`*(v: T1, f: untyped): int =
+  echo "reading field ", astToStr(f)
+  v.x
+
+template `.=`(t: var T1, f: untyped, v: int) =
+  echo "assigning ", astToStr(f), " = ", v
+  t.x = v
+
+template `.()`(x: T1, f: untyped, args: varargs[typed]): string =
+  echo "call to ", astToStr(f)
+  "dot call"
+
+echo ""
+
+var t = T1(x: 10)
+
+echo t.x
+t.z = 20
+echo t.y
+echo t.y()
+
+var d = TD(t)
+assert(not compiles(d.y))
+
+template `.`(v: T2, f: untyped): int =
+  echo "no params call to ", astToStr(f)
+  v.x
+
+template `.`*(v: T2, f: untyped, a: int): int =
+  echo "one param call to ", astToStr(f), " with ", a
+  v.x
+
+var tt = T2(x: 100)
+
+echo tt.a
+echo tt.b()
+echo tt.c(10)
+
+assert(not compiles(tt.d("x")))
+assert(not compiles(tt.d(1, 2)))
+
+# test simple usage that delegates fields:
+type
+  Other = object
+    a: int
+    b: string
+  MyObject = object
+    nested: Other
+    x, y: int
+
+template `.`(x: MyObject; field: untyped): untyped =
+  x.nested.field
+
+template `.=`(x: MyObject; field, value: untyped) =
+  x.nested.field = value
+
+var m: MyObject
+
+m.a = 4
+m.b = "foo"
+echo m.x, " ", m.a
diff --git a/tests/specialops/terrmsgs.nim b/tests/specialops/terrmsgs.nim
new file mode 100644
index 000000000..081bca451
--- /dev/null
+++ b/tests/specialops/terrmsgs.nim
@@ -0,0 +1,76 @@
+discard """
+action: reject
+cmd: '''nim check $options $file'''
+matrix: "; -d:testWithout; --mm:refc"
+"""
+
+when not defined(testWithout): # test for same errors before and after
+  {.experimental: "dotOperators".}
+  {.experimental: "callOperator".}
+
+# issue #13063
+
+block:
+  type Foo = object
+  type Bar = object
+    x1: int
+  var b: Bar
+  block:
+    template `.`(a: Foo, b: untyped): untyped = 123
+    echo b.x #[tt.Error
+          ^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
+  block:
+    template `.()`(a: Foo, b: untyped): untyped = 123
+    echo b.x() #[tt.Error
+          ^ attempting to call undeclared routine: 'x']#
+  block:
+    template `.=`(a: Foo, b: untyped, c: untyped) = b = c
+    b.x = 123 #[tt.Error
+        ^ undeclared field: 'x=' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
+    # yeah it says x= but does it matter in practice
+  block:
+    template `()`(a: Foo, b: untyped, c: untyped) = echo "something"
+
+    # completely undeclared::
+    xyz(123) #[tt.Error
+    ^ undeclared identifier: 'xyz']#
+
+    # already declared routine:
+    min(123) #[tt.Error
+       ^ type mismatch: got <int literal(123)>]#
+
+    # non-routine type shows `()` overloads:
+    b(123) #[tt.Error
+     ^ attempting to call routine: 'b']#
+
+    echo b.x #[tt.Error
+          ^ undeclared field: 'x' for type terrmsgs.Bar [type declared in terrmsgs.nim(15, 8)]]#
+    echo b.x() #[tt.Error
+          ^ attempting to call undeclared routine: 'x']#
+
+# issue #7777
+
+import macros
+
+block:
+  type TestType = object
+    private_field: string
+
+  when false:
+    template getField(obj, field: untyped): untyped = obj.field
+
+  macro `.`(obj: TestType, field: untyped): untyped =
+    let private = newIdentNode("private_" & $field)
+    result = quote do:
+      `obj`.getField(`private`) #[tt.Error
+           ^ attempting to call undeclared routine: 'getField']#
+
+  var tt: TestType
+  discard tt.field
+
+block: # related to issue #6981
+  proc `()`(a:string, b:string):string = a & b
+  proc mewSeq[T](a,b:int)=discard
+  proc mewSeq[T](c:int)= discard
+  mewSeq[int]() #[tt.Error
+             ^ type mismatch: got <>]#
diff --git a/tests/specialops/tnewseq.nim b/tests/specialops/tnewseq.nim
new file mode 100644
index 000000000..970a5a8c2
--- /dev/null
+++ b/tests/specialops/tnewseq.nim
@@ -0,0 +1,22 @@
+# issue #6981
+
+import std/assertions
+
+{.experimental: "callOperator".}
+
+block: # issue #6981
+  proc `()`(a:string, b:string):string = a & b
+
+  var s = newSeq[int](3)
+
+  doAssert s == @[0, 0, 0]
+
+block: # generalized example from #6981
+  proc mewSeq[T](a: int)=discard
+  proc mewSeq[T]()= discard
+  mewSeq[int]()
+
+block: # issue #9831
+  type Foo = object
+  proc `()`(foo: Foo) = discard
+  let x = newSeq[int]()
diff --git a/tests/specialops/tsetter.nim b/tests/specialops/tsetter.nim
new file mode 100644
index 000000000..6175cbec4
--- /dev/null
+++ b/tests/specialops/tsetter.nim
@@ -0,0 +1,10 @@
+block: # ensure RHS of setter statement is treated as call operand
+  proc `b=`(a: var int, c: proc (x: int): int) =
+    a = c(a)
+
+  proc foo(x: int): int = x + 1
+  proc foo(x: float): float = x - 1
+
+  var a = 123
+  a.b = foo
+  doAssert a == 124
diff --git a/tests/statictypes/t20148.nim b/tests/statictypes/t20148.nim
new file mode 100644
index 000000000..d74a7755e
--- /dev/null
+++ b/tests/statictypes/t20148.nim
@@ -0,0 +1,8 @@
+type Percent = range[0.0 .. 1.0]
+# type Percent = float # using unlimited `float` works fine
+
+proc initColor*(alpha: Percent): bool =
+  echo alpha
+
+const moduleInstanceStyle = initColor(1)
+# let moduleInstanceStyle = initColor(1) # using runtime conversion works fine
diff --git a/tests/statictypes/t3784.nim b/tests/statictypes/t3784.nim
new file mode 100644
index 000000000..3414d9802
--- /dev/null
+++ b/tests/statictypes/t3784.nim
@@ -0,0 +1,20 @@
+discard """
+output: "T[1, 1]"
+"""
+
+# https://github.com/nim-lang/Nim/issues/3784
+
+import typetraits
+
+type
+  S[N: static[int]] = object
+  T[A,B: static[int]] = object
+  
+  C = S[1]
+
+var
+  x: T[1,1]
+  y: T[C.N, C.N]
+
+echo y.type.name
+
diff --git a/tests/statictypes/t5780.nim b/tests/statictypes/t5780.nim
new file mode 100644
index 000000000..85548aaad
--- /dev/null
+++ b/tests/statictypes/t5780.nim
@@ -0,0 +1,3 @@
+type StringArray[N:int] = array[N, string]
+let a = ["one", "two"]
+doAssert a is StringArray
diff --git a/tests/statictypes/t9255.nim b/tests/statictypes/t9255.nim
new file mode 100644
index 000000000..aec2fbaf5
--- /dev/null
+++ b/tests/statictypes/t9255.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: '''
+type mismatch: got <proc (a0: int): string{.noSideEffect, gcsafe.}>
+'''
+  line: 13
+"""
+
+macro fun(a: static float): untyped =
+  discard
+
+when true:
+  proc bar(a0: int): string = discard
+  fun(bar)
diff --git a/tests/statictypes/tcryptodigest.nim b/tests/statictypes/tcryptodigest.nim
new file mode 100644
index 000000000..c78a4188a
--- /dev/null
+++ b/tests/statictypes/tcryptodigest.nim
@@ -0,0 +1,44 @@
+discard """
+  output: "Digest[128]\nDigest[256]"
+"""
+
+import typetraits
+
+type
+  Digest[bits: static[int]] = object
+    data: array[bits div 8, byte]
+
+  ContextKind = enum
+    A, B, C
+
+  HashingContext[bits: static[int], kind: static[ContextKind]] = object
+    ctx: array[bits div 8, byte]
+
+  Hash128 = HashingContext[128, A]
+  Hash256 = HashingContext[256, B]
+
+  HMAC[HashType] = object
+    h: HashType
+
+proc init(c: var HashingContext) = discard
+proc update(c: var HashingContext, data: ptr byte, dataLen: uint) = discard
+proc finish(c: var HashingContext): Digest[c.bits] = discard
+
+proc digest(T: typedesc, data: ptr byte, dataLen: uint): Digest[T.bits] =
+  mixin init, update, finish
+
+  var ctx: T
+  ctx.init()
+  ctx.update(data, dataLen)
+  result = ctx.finish()
+
+var h = Hash128.digest(nil, 0)
+echo h.type.name
+
+proc finish(hmac: var HMAC): Digest[HMAC.HashType.bits] =
+  discard
+
+var hm: HMAC[Hash256]
+var d = hm.finish
+echo d.type.name
+
diff --git a/tests/statictypes/texplicitprocparams.nim b/tests/statictypes/texplicitprocparams.nim
new file mode 100644
index 000000000..d1e717dbf
--- /dev/null
+++ b/tests/statictypes/texplicitprocparams.nim
@@ -0,0 +1,19 @@
+discard """
+output: '''
+(x: 100)
+5
+'''
+"""
+
+type
+  OdArray*[As: static[int], T] = object
+    x: int
+
+proc initOdArray*[As: static[int], T](len: int): OdArray[As, T] =
+  result.x = len
+
+echo initOdArray[10, int](100)
+
+proc doStatic[N: static[int]](): int = N
+echo doStatic[5]()
+
diff --git a/tests/statictypes/tgenericcomputedrange.nim b/tests/statictypes/tgenericcomputedrange.nim
new file mode 100644
index 000000000..9e3a49ae0
--- /dev/null
+++ b/tests/statictypes/tgenericcomputedrange.nim
@@ -0,0 +1,125 @@
+import math
+
+block: # issue #19916
+  type
+    Test[S: static[Natural]] = object
+      a: array[ceilDiv(S, 8), uint8]
+
+  let a = Test[32]()
+  doAssert a.a.len == 4
+
+block: # issue #20514
+  type Foo[S:static[array[2, int]]] = object
+    values: array[prod(S), float]
+
+  doAssert Foo[[4,5]]().values.len == 20
+
+block: # issue #20937
+  type
+    Vec3[T: SomeNumber] {.bycopy.} = tuple[x, y, z: T]
+
+  func volume[T](v: Vec3[T]): T =
+    when T is SomeUnsignedInt:
+      v.x * v.y * v.z
+    else:
+      abs (v.x * v.y * v.z)
+
+  type
+    Matrix3[C: static Vec3[uint], T] = object
+      cells: array[C.volume, T]
+
+  let m = Matrix3[(1.uint, 1.uint, 1.uint), uint](cells: [0.uint])
+  doAssert m.cells.len == 1
+  let m2 = Matrix3[(4.uint, 3.uint, 5.uint), uint]()
+  doAssert m2.cells.len == 60
+
+block:  # issue #19284
+  type Board[N, M: static Slice[int]] = array[len(N)*len(M), int8]
+
+  var t: Board[0..4, 0..4]
+  doAssert t.len == 25
+
+block: # minimal issue #19284
+  proc foo[T](x: T): int =
+    result = 0
+  type Foo[N: static int] = array[0..foo(N), int]
+
+  var t: Foo[5]
+  doAssert t.len == 1
+
+block:
+  type Foo[T; U: static T] = range[T(0) .. U]
+
+  block:
+    var x: array[Foo[int, 1], int]
+    x[0] = 1
+    x[1] = 2
+    doAssert x == [0: 1, 1: 2]
+    doAssert x is array[0 .. 1, int]
+
+  block:
+    type Bar = enum a, b, c
+    var x: array[Foo[Bar, c], int]
+    x[a] = 1
+    x[b] = 2
+    x[c] = 3
+    doAssert x == [a: 1, b: 2, c: 3]
+    doAssert x is array[a .. c, int]
+
+block:
+  type Foo[T; U: static T] = array[T(0) .. U, int]
+
+  block:
+    var x: Foo[int, 1]
+    x[0] = 1
+    x[1] = 2
+    doAssert x == [0: 1, 1: 2]
+    doAssert x is array[0 .. 1, int]
+
+  block:
+    type Bar = enum a, b, c
+    var x: Foo[Bar, c]
+    x[a] = 1
+    x[b] = 2
+    x[c] = 3
+    doAssert x == [a: 1, b: 2, c: 3]
+    doAssert x is array[a .. c, int]
+
+block:
+  type Foo[T; U: static T] = array[T(0) .. U + 1, int]
+
+  block:
+    var x: Foo[int, 1]
+    x[0] = 1
+    x[1] = 2
+    x[2] = 3
+    doAssert x == [0: 1, 1: 2, 2: 3]
+    doAssert x is array[0 .. 2, int]
+
+block:
+  type Foo[T; U: static T] = array[T(0) .. (U * 2) + 1, int]
+
+  block:
+    var x: Foo[int, 1]
+    x[0] = 1
+    x[1] = 2
+    x[2] = 3
+    x[3] = 4
+    doAssert x == [0: 1, 1: 2, 2: 3, 3: 4]
+    doAssert x is array[0 .. 3, int]
+
+block: # issue #22187
+  template m(T: type, s: int64): int64 = s
+  func p(n: int64): int = int(n)
+  type F[T; s: static int64] = object
+    k: array[p(m(T, s)), int64]
+  var x: F[int, 3]
+  doAssert x.k is array[3, int64]
+
+block: # issue #22490
+  proc log2trunc(x: uint64): int =
+    if x == 0: int(0) else: int(0)
+  template maxChunkIdx(T: typedesc): int64 = 0'i64
+  template layer(vIdx: int64): int = log2trunc(0'u64)
+  type HashList[T] = object
+    indices: array[int(layer(maxChunkIdx(T))), int]
diff --git a/tests/statictypes/tpassthruarith.nim b/tests/statictypes/tpassthruarith.nim
new file mode 100644
index 000000000..33e4e0303
--- /dev/null
+++ b/tests/statictypes/tpassthruarith.nim
@@ -0,0 +1,50 @@
+discard """
+output: '''
+[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
+[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+[1, 2, 3, 4]
+'''
+"""
+
+# https://github.com/nim-lang/Nim/issues/4880
+
+proc `^^`(x: int): int = x * 2
+
+type
+  Foo[x: static[int]] = array[x, int]
+  Bar[a, b: static[int]] = array[b, Foo[^^a]]
+
+var x: Bar[2, 3]
+echo repr(x)
+
+# https://github.com/nim-lang/Nim/issues/2730
+
+type
+  Matrix[M,N: static[int]] = distinct array[0..(M*N - 1), int]
+
+proc bigger[M,N](m: Matrix[M,N]): Matrix[(M * N) div 8, (M * N)] =
+  discard
+
+proc bigger2[M,N](m: Matrix[M,N]): Matrix[M * 2, N * 2] =
+  discard
+
+var m : Matrix[4, 4]
+var n = bigger(m)
+var o = bigger2(m)
+
+echo repr(m)
+echo repr(n)
+echo repr(o)
+
+type
+  Vect[N: static[int], A] = array[N, A]
+
+proc push[N: static[int], A](a: Vect[N, A], x: A): Vect[N + 1, A] =
+  for n in 0 ..<  N:
+    result[n] = a[n]
+  result[N] = x
+
+echo repr(push([1, 2, 3], 4))
+
diff --git a/tests/statictypes/tstackmatrix.nim b/tests/statictypes/tstackmatrix.nim
new file mode 100644
index 000000000..2509d21f8
--- /dev/null
+++ b/tests/statictypes/tstackmatrix.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "(M: 3, N: 3, fp: ...)"
+"""
+
+# bug #6843
+
+type
+  OrderType = enum colMajor, rowMajor
+  Matrix[A] = object
+    M, N: int
+    fp: ptr A # float pointer
+  DoubleArray64[M, N: static[int]] = array[M, array[N, float64]]
+
+
+proc stackMatrix[M, N: static[int]](a: var DoubleArray64[M, N], order = colMajor): Matrix[float64] =
+  Matrix[float64](
+    fp: addr a[0][0],
+    M: (if order == colMajor: N else: M),
+    N: (if order == colMajor: M else: N)
+  )
+
+var
+  data = [
+    [1'f64, 2, 3],
+    [4'f64, 5, 6],
+    [7'f64, 8, 9]
+  ]
+  m = stackMatrix(data)
+echo m
\ No newline at end of file
diff --git a/tests/statictypes/tstatic.nim b/tests/statictypes/tstatic.nim
new file mode 100644
index 000000000..aaa63534b
--- /dev/null
+++ b/tests/statictypes/tstatic.nim
@@ -0,0 +1,56 @@
+discard """
+  targets: "c cpp js"
+"""
+
+template main() =
+  block: # bug #17589
+    #[
+    # all those gave some variation of the same bug:
+    'intVal' is not accessible using discriminant 'kind' of type 'TFullReg'
+    'floatVal' is not accessible using discriminant 'kind' of type 'TFullReg'
+    ]#
+    block:
+      proc f(a: static uint64): uint64 =
+        a
+      const x = 3'u64
+      static: doAssert f(x) == 3'u64
+      doAssert f(x) == 3'u64
+
+    block:
+      proc f(a: static uint64): uint64 =
+        a
+      const x = 3'u64
+      static: doAssert f(x) == 3'u64
+      doAssert f(x) == 3'u64
+
+    block:
+      proc foo(x: uint8): uint8 = x
+      proc f(a: static uint8): auto = foo(a)
+      const x = 3'u8
+      static: doAssert f(x) == 3'u8
+      doAssert f(x) == 3'u8
+
+    block:
+      template foo2(x: float) =
+        let b = x == 0
+      proc foo(x: float) = foo2(x)
+      proc f(a: static float) = foo(a)
+      const x = 1.0
+      static: f(x)
+
+    block:
+      proc foo(x: int32) =
+        let b = x == 0
+      proc f(a: static int32) = foo(a)
+      static: f(32767) # was working
+      static: f(32768) # was failing because >= int16.high (see isInt16Lit)
+
+  block: # bug #14585
+    const foo_m0ninv = 0x1234'u64
+    proc foo(m0ninv: static uint64) =
+      let b = $m0ninv
+    static:
+      foo(foo_m0ninv)
+
+static: main()
+main()
diff --git a/tests/statictypes/tstaticgenericparam.nim b/tests/statictypes/tstaticgenericparam.nim
new file mode 100644
index 000000000..6acd05b70
--- /dev/null
+++ b/tests/statictypes/tstaticgenericparam.nim
@@ -0,0 +1,24 @@
+# static types that depend on a generic parameter
+
+block: # issue #19365
+  var ss: seq[string]
+  proc f[T](x: static T) =
+    ss.add($x & ": " & $T)
+
+  f(123)
+  doAssert ss == @["123: int"]
+  f("abc")
+  doAssert ss == @["123: int", "abc: string"]
+
+block: # issue #7209
+  type Modulo[A; M: static[A]] = distinct A
+
+  proc `$`[A; M: static[A]](x: Modulo[A, M]): string =
+    $(A(x)) & " mod " & $(M)
+
+  proc modulo[A](a: A, M: static[A]): Modulo[A, M] = Modulo[A, M](a %% M)
+
+  proc `+`[A; M: static[A]](x, y: Modulo[A, M]): Modulo[A, M] =
+    (A(x) + A(y)).modulo(M)
+
+  doAssert $(3.modulo(7) + 5.modulo(7)) == "1 mod 7"
diff --git a/tests/statictypes/tstaticimportcpp.nim b/tests/statictypes/tstaticimportcpp.nim
new file mode 100644
index 000000000..ec4696379
--- /dev/null
+++ b/tests/statictypes/tstaticimportcpp.nim
@@ -0,0 +1,63 @@
+discard """
+targets: "cpp"
+output: "[0, 0, 10, 0]\n5\n1.2\n15\ntest\n[0, 0, 20, 0]\n4"
+"""
+
+{.emit: """/*TYPESECTION*/
+
+template <int N, class T>
+struct GenericIntType {
+  T data[N];
+};
+
+template <class T>
+struct GenericTType {
+  T field;
+};
+
+struct SimpleStruct {
+  int field;
+};
+
+
+""" .}
+
+type
+  GenericIntType[N: static[int]; T] {.importcpp: "GenericIntType<'0, '1>".} = object
+    data: array[N, T]
+
+  GenericIntTypeAlt[N: static[int]; T] {.importcpp: "GenericIntType".} = object
+
+  GenericTType[T] {.importcpp: "GenericTType<'0>".} = object
+    field: T
+
+  GenInt4 = GenericIntType[4, int]
+
+  SimpleStruct {.importcpp: "SimpleStruct"} = object
+    field: int
+
+var
+  a = GenInt4()
+  b = SimpleStruct()
+  c = GenericTType[float]()
+  d = SimpleStruct(field: 15)
+  e = GenericTType[string](field: "test")
+  f = GenericIntTypeAlt[4, int8]()
+
+a.data[2] = 10
+b.field = 5
+c.field = 1.2
+
+echo a.data
+echo b.field
+echo c.field
+echo d.field
+echo e.field
+
+proc plus(a, b: GenInt4): GenInt4 =
+  for i in 0 ..< result.data.len:
+    result.data[i] = a.data[i] + b.data[i]
+
+echo plus(a, a).data
+
+echo sizeof(f)
diff --git a/tests/statictypes/tstaticprocparams.nim b/tests/statictypes/tstaticprocparams.nim
new file mode 100644
index 000000000..75d8288ac
--- /dev/null
+++ b/tests/statictypes/tstaticprocparams.nim
@@ -0,0 +1,16 @@
+proc consumer[T: static proc(i: int): int{.nimcall.}](i: int): int = T(i)
+proc consumer(T: static proc(i: int): int{.nimcall.}, i: int): int = T(i)
+
+proc addIt(i: int): int = i + i
+proc add(i: int): int = i + i # Checks if we can use overloads
+proc squareIt(i: int): int = i * i
+
+assert consumer[addIt](10) == 20
+assert consumer[add](10) == 20
+assert consumer[squareIt](30) == 900
+assert consumer[proc(i: int): int{.nimcall.} = i * i + i](10) == 110
+
+assert consumer(addIt, 10) == 20
+assert consumer(add, 10) == 20
+assert consumer(squareIt, 30) == 900
+assert consumer(proc(i: int): int{.nimcall.} = i * i + i, 10) == 110
diff --git a/tests/statictypes/tstatictypes.nim b/tests/statictypes/tstatictypes.nim
new file mode 100644
index 000000000..572b8c4a5
--- /dev/null
+++ b/tests/statictypes/tstatictypes.nim
@@ -0,0 +1,459 @@
+discard """
+nimoutFull: true
+nimout: '''
+staticAlialProc instantiated with 358
+staticAlialProc instantiated with 368
+0: Foo
+1: Bar
+0: Foo
+1: Bar
+0: Foo
+1: Bar
+0: Foo
+1: Bar
+'''
+output: '''
+16
+16
+b is 2 times a
+17
+['\x00', '\x00', '\x00', '\x00']
+heyho
+Val1
+Val1
+'''
+matrix: "--hints:off --mm:orc; --hints:off --mm:refc"
+"""
+
+import macros
+
+template ok(x) = doAssert(x)
+template no(x) = doAssert(not x)
+
+template accept(x) =
+  static: doAssert(compiles(x))
+
+template reject(x) =
+  static: doAssert(not compiles(x))
+
+proc plus(a, b: int): int = a + b
+
+template isStatic(x: static): bool = true
+template isStatic(x: auto): bool = false
+
+var v = 1
+
+when true:
+  # test that `isStatic` works as expected
+  const C = 2
+
+  static:
+    ok C.isStatic
+    ok isStatic(plus(1, 2))
+    ok plus(C, 2).isStatic
+
+    no isStatic(v)
+    no plus(1, v).isStatic
+
+when true:
+  # test that proc instantiation works as expected
+  type
+    StaticTypeAlias = static[int]
+
+  proc staticAliasProc(a: StaticTypeAlias,
+                       b: static[int],
+                       c: static int) =
+    static:
+      doAssert a.isStatic and b.isStatic and c.isStatic
+      doAssert isStatic(a + plus(b, c))
+      echo "staticAlialProc instantiated with ", a, b, c
+
+    when b mod a == 0:
+      echo "b is ", b div a, " times a"
+
+    echo a + b + c
+
+  staticAliasProc 1+2, 5, 8
+  staticAliasProc 3, 2+3, 9-1
+  staticAliasProc 3, 3+3, 4+4
+
+when true:
+  # test static coercions. normal cases that should work:
+  accept:
+    var s1 = static[int] plus(1, 2)
+    var s2 = static(plus(1,2))
+    var s3 = static plus(1,2)
+    var s4 = static[SomeInteger](1 + 2)
+
+  # the sub-script operator can be used only with types:
+  reject:
+    var just_static3 = static[plus(1,2)]
+
+  # static coercion takes into account the type:
+  reject:
+    var x = static[string](plus(1, 2))
+  reject:
+    var x = static[string] plus(1, 2)
+  reject:
+    var x = static[SomeFloat] plus(3, 4)
+
+  # you cannot coerce a run-time variable
+  reject:
+    var x = static(v)
+
+block: # issue #13730
+  type Foo[T: static[float]] = object
+  doAssert Foo[0.0] is Foo[-0.0]
+
+when true:
+  type
+    ArrayWrapper1[S: static int] = object
+      data: array[S + 1, int]
+
+    ArrayWrapper2[S: static[int]] = object
+      data: array[S.plus(2), int]
+
+    ArrayWrapper3[S: static[(int, string)]] = object
+      data: array[S[0], int]
+
+  var aw1: ArrayWrapper1[5]
+  var aw2: ArrayWrapper2[5]
+  var aw3: ArrayWrapper3[(10, "str")]
+
+  static:
+    doAssert aw1.data.high == 5
+    doAssert aw2.data.high == 6
+    doAssert aw3.data.high == 9
+
+# #6077
+block:
+  type
+    Backend = enum
+      Cpu
+
+    Tensor[B: static[Backend]; T] = object
+
+    BackProp[B: static[Backend],T] = proc (gradient: Tensor[B,T]): Tensor[B,T]
+
+# https://github.com/nim-lang/Nim/issues/10073
+block:
+  proc foo[N: static int](x: var int,
+                          y: int,
+                          z: static int,
+                          arr: array[N, int]): auto =
+    var t1 = (a: x, b: y, c: z, d: N)
+    var t2 = (x, y, z, N)
+    doAssert t1 == t2
+    result = t1
+
+  var y = 20
+  var x = foo(y, 10, 15, [1, 2, 3])
+  doAssert x == (20, 10, 15, 3)
+
+# #7609
+block:
+  type
+    Coord[N: static[int]] = tuple[col, row: range[0'i8 .. (N.int8-1)]]
+    Point[N: static[int]] = range[0'i16 .. N.int16 * N.int16 - 1]
+
+# https://github.com/nim-lang/Nim/issues/10339
+block:
+  type
+    MicroKernel = object
+      a: float
+      b: int
+
+  macro extractA(ukernel: static MicroKernel): untyped =
+    result = newLit ukernel.a
+
+  proc tFunc[ukernel: static MicroKernel]() =
+    const x = ukernel.extractA
+    doAssert x == 5.5
+
+  const uk = MicroKernel(a: 5.5, b: 1)
+  tFunc[uk]()
+
+
+# bug #7258
+type
+  StringValue*[LEN: static[Natural]] = array[LEN+Natural(2),char]
+  StringValue16* = StringValue[2]
+
+var
+  s: StringValue16
+
+echo s
+
+block: #13529
+  block:
+    type Foo[T: static type] = object
+    var foo: Foo["test"]
+    doAssert $foo == "()"
+    doAssert foo.T is string
+    static: doAssert foo.T == "test"
+    doAssert not compiles(
+      block:
+        type Foo2[T: static type] = object
+          x: T)
+
+  block:
+    type Foo[T: static[float]] = object
+    var foo: Foo[1.2]
+    doAssert $foo == "()"
+    doAssert foo.T == 1.2
+
+  block: # routines also work
+    proc fun(a: static) = (const a2 = a)
+    fun(1)
+    fun(1.2)
+  block: # routines also work
+    proc fun(a: static type) = (const a2 = a)
+    fun(1)
+    fun(1.2)
+
+  block: # this also works
+    proc fun[T](a: static[T]) = (const a2 = a)
+    fun(1)
+    fun(1.2)
+
+block: # #12713
+  block:
+    type Cell = object
+      c: int
+    proc test(c: static string) = discard #Remove this and it compiles
+    proc test(c: Cell) = discard
+    test Cell(c: 0)
+  block:
+    type Cell = object
+      c: int
+    proc test(c: static string) = discard #Remove this and it compiles
+    proc test(c: Cell) = discard
+    test Cell()
+
+block: # issue #14802
+  template fn(s: typed): untyped =
+    proc bar() = discard
+    12
+  const myConst = static(fn(1))
+  doAssert myConst == 12
+
+
+# bug #12571
+type
+  T[K: static bool] = object of RootObj
+    when K == true:
+      foo: string
+    else:
+      bar: string
+  U[K: static bool] = object of T[K]
+
+let t = T[true](foo: "hey")
+let u = U[false](bar: "ho")
+echo t.foo, u.bar
+
+
+#------------------------------------------------------------------------------
+# issue #9679
+
+type
+  Foo*[T] = object
+    bar*: int
+    dummy: T
+
+proc initFoo(T: type, bar: int): Foo[T] =
+  result.bar = 1
+
+proc fails[T](x: static Foo[T]) = # Change to non-static and it compiles
+  doAssert($x == "(bar: 1, dummy: 0)")
+
+block:
+  const foo = initFoo(int, 2)
+  fails(foo)
+
+
+import tables
+
+var foo{.compileTime.} = [
+  "Foo",
+  "Bar"
+]
+
+var bar{.compileTime.} = {
+  0: "Foo",
+  1: "Bar"
+}.toTable()
+
+macro fooM(): untyped =
+  for i, val in foo:
+    echo i, ": ", val
+
+macro barM(): untyped =
+  for i, val in bar:
+    echo i, ": ", val
+
+macro fooParam(x: static array[2, string]): untyped =
+  for i, val in x:
+    echo i, ": ", val
+
+macro barParam(x: static Table[int, string]): untyped =
+  let barParamInsides = proc(i: int, val: string): NimNode =
+    echo i, ": ", val
+  for i, val in x:
+    discard barParamInsides(i, val)
+
+fooM()
+barM()
+fooParam(foo)
+barParam(bar)
+
+
+#-----------------------------------------------------------------------------------------
+# issue #7546
+type
+  rangeB[N: static[int16]] = range[0'i16 .. N]
+  setB[N: static[int16]] = set[rangeB[N]]
+
+block:
+  var s : setB[14'i16]
+
+
+#-----------------------------------------------------------------------------------------
+# issue #9520
+
+type
+  MyEnum = enum
+    Val1, Val2
+
+proc myproc(a: static[MyEnum], b: int) =
+  if b < 0:
+    myproc(a, -b)
+
+  echo $a
+
+myproc(Val1, -10)
+
+
+#------------------------------------------------------------------------------------------
+# issue #6177
+
+type                                                                                                 
+  G[N,M:static[int], T] = object                                                                      
+    o: T                                                                                             
+                                                                                                     
+proc newG[N,M:static[int],T](x:var G[N,M,T], y:T) =                                                  
+  x.o = y+10*N+100*M                                                                                 
+                                                                                                     
+proc newG[N,M:static[int],T](x:T):G[N,M,T] = result.newG(x)                                          
+                                                                                                     
+var x:G[2,3,int]                                                                                     
+x.newG(4)                                                                                            
+var y = newG[2,3,int](4)
+
+
+#------------------------------------------------------------------------------------------
+# issue #12897
+
+type
+  TileCT[n: static int] = object
+    a: array[n, int]
+  Tile = TileCT #Commenting this out to make it work
+
+
+#------------------------------------------------------------------------------------------
+# issue #15858
+
+proc fn(N1: static int, N2: static int, T: typedesc): array[N1 * N2, T] = 
+  doAssert(len(result) == N1 * N2)
+
+let yy = fn(5, 10, float)
+
+
+block:
+  block:
+    type Foo[N: static int] = array[cint(0) .. cint(N), float]
+    type T = Foo[3]
+  block:
+    type Foo[N: static int] = array[int32(0) .. int32(N), float]
+    type T = Foo[3]
+
+
+#------------------------------------------------------------------------------------------
+# static proc/lambda param
+func isSorted2[T](a: openArray[T], cmp: static proc(x, y: T): bool {.inline.}): bool =
+  result = true
+  for i in 0..<len(a)-1:
+    if not cmp(a[i], a[i+1]):
+      return false
+
+proc compare(a, b: int): bool {.inline.} = a < b
+
+var sorted = newSeq[int](1000)
+for i in 0..<sorted.len: sorted[i] = i*2
+doAssert isSorted2(sorted, compare)
+doAssert isSorted2(sorted, proc (a, b: int): bool {.inline.} = a < b)
+
+
+block: # Ensure static descriminated objects compile
+  type
+    ObjKind = enum
+      KindA, KindB, KindC
+
+    MyObject[kind: static[ObjKind]] = object of RootObj
+      myNumber: int
+      when kind != KindA:
+        driverType: int
+        otherField: int
+      elif kind == KindC:
+        driverType: uint
+        otherField: int
+
+  var instance: MyObject[KindA]
+  discard instance
+  discard MyObject[KindC]()
+
+block: # more cases of above, issue #8446
+  type
+    Color = enum
+      red, green, blue
+    Blah[color: static[Color]] = object
+      when color == red:
+        a: string
+      else:
+        b: int
+
+  proc foo(blah: Blah) = discard
+  foo(Blah[red](a: "abc"))
+
+  type
+    Mytype[K: static[int]] = object
+      when K < 16:
+        data: uint8
+      else:
+        data: uint64
+  proc usingMyt(k: Mytype) = discard  # triggers Error: cannot generate code for: K
+
+block: # bug #22600
+  proc f(n: static int): int = n * 2 # same for template
+
+  type
+    a[N: static int] = object
+      field : array[N, uint8]
+
+    b[N: static int] = object
+      field : a[N]
+
+    c[N: static int] = object
+      f0    : a[N     ]         # works
+      f1    : a[N + 1 ]         # asserts
+      f2    : a[f(N)  ]         # asserts
+
+      f3    : b[N     ]         # works
+      f4    : b[N + 1 ]         # asserts
+      f5    : b[f(N)  ]         # asserts
+
+  proc init[N: static int](x : var a[N]) = discard
+  proc init[N: static int](x : var b[N]) = discard
+  proc init[N: static int](x : var c[N]) = x.f1.init() # this is needed
+
+  var x: c[2]
+  x.init()
diff --git a/tests/stckovfl.nim b/tests/stckovfl.nim
index 799fe0001..cbc893d2e 100755..100644
--- a/tests/stckovfl.nim
+++ b/tests/stckovfl.nim
@@ -1,8 +1,10 @@
 # To test stack overflow message
 
-proc over(a: int): int = 
-  if a == high(int): return
+proc over(a: int): int =
+  if a >= 10:
+    assert false
+    return
   result = over(a+1)+5
-  
+
 Echo($over(0))
 
diff --git a/tests/stdlib/concurrency/atomicSample.nim b/tests/stdlib/concurrency/atomicSample.nim
new file mode 100644
index 000000000..d56d867df
--- /dev/null
+++ b/tests/stdlib/concurrency/atomicSample.nim
@@ -0,0 +1,9 @@
+import atomics
+
+type
+  AtomicWithGeneric*[T] = object
+    value: Atomic[T]
+
+proc initAtomicWithGeneric*[T](value: T): AtomicWithGeneric[T] =
+  result.value.store(value)
+
diff --git a/tests/stdlib/concurrency/tatomic_import.nim b/tests/stdlib/concurrency/tatomic_import.nim
new file mode 100644
index 000000000..e8faaae20
--- /dev/null
+++ b/tests/stdlib/concurrency/tatomic_import.nim
@@ -0,0 +1,11 @@
+import atomicSample
+
+block crossFileObjectContainingAGenericWithAComplexObject:
+  discard initAtomicWithGeneric[string]("foo")
+
+block crossFileObjectContainingAGenericWithAnInteger:
+  discard initAtomicWithGeneric[int](1)
+  discard initAtomicWithGeneric[int8](1)
+  discard initAtomicWithGeneric[int16](1)
+  discard initAtomicWithGeneric[int32](1)
+  discard initAtomicWithGeneric[int64](1)
diff --git a/tests/stdlib/concurrency/tatomics.nim b/tests/stdlib/concurrency/tatomics.nim
new file mode 100644
index 000000000..08f2e7d3e
--- /dev/null
+++ b/tests/stdlib/concurrency/tatomics.nim
@@ -0,0 +1,637 @@
+discard """
+  # 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
+
+import std/[atomics, bitops]
+import std/assertions
+
+
+type
+  Object = object
+    val: int
+
+
+# Atomic operations for trivial objects
+
+
+block trivialLoad:
+  var location: Atomic[int]
+  location.store(1)
+  doAssert location.load == 1
+  location.store(2)
+  doAssert location.load(moRelaxed) == 2
+  location.store(3)
+  doAssert location.load(moAcquire) == 3
+
+
+block trivialStore:
+  var location: Atomic[int]
+  location.store(1)
+  doAssert location.load == 1
+  location.store(2, moRelaxed)
+  doAssert location.load == 2
+  location.store(3, moRelease)
+  doAssert location.load == 3
+
+
+block trivialExchange:
+  var location: Atomic[int]
+  location.store(1)
+  doAssert location.exchange(2) == 1
+  doAssert location.exchange(3, moRelaxed) == 2
+  doAssert location.exchange(4, moAcquire) == 3
+  doAssert location.exchange(5, moRelease) == 4
+  doAssert location.exchange(6, moAcquireRelease) == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchange(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchange(expected, 3, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchange(expected, 4, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchange(expected, 5, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchange(expected, 6, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchange(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 3, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 4, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 5, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 6, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+block trivialCompareExchangeSuccessFailureDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchange(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchange(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchange(expected, 5, moRelease, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeSuccessFailureDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchange(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 5, moRelease, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchange(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+block trivialCompareExchangeWeakDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchangeWeak(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchangeWeak(expected, 3, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchangeWeak(expected, 4, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchangeWeak(expected, 5, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeWeakDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchangeWeak(expected, 2)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 3, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 4, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 5, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+block trivialCompareExchangeWeakSuccessFailureDoesExchange:
+  var location: Atomic[int]
+  var expected = 1
+  location.store(1)
+  doAssert location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 2
+  expected = 2
+  doAssert location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 2
+  doAssert location.load == 3
+  expected = 3
+  doAssert location.compareExchangeWeak(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 3
+  doAssert location.load == 4
+  expected = 4
+  doAssert location.compareExchangeWeak(expected, 5, moRelease, moRelease)
+  doAssert expected == 4
+  doAssert location.load == 5
+  expected = 5
+  doAssert location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 5
+  doAssert location.load == 6
+
+
+block trivialCompareExchangeWeakSuccessFailureDoesNotExchange:
+  var location: Atomic[int]
+  var expected = 10
+  location.store(1)
+  doAssert not location.compareExchangeWeak(expected, 2, moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 3, moRelaxed, moRelaxed)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 4, moAcquire, moAcquire)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 5, moRelease, moRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+  expected = 10
+  doAssert not location.compareExchangeWeak(expected, 6, moAcquireRelease, moAcquireRelease)
+  doAssert expected == 1
+  doAssert location.load == 1
+
+
+# Atomic operations for non-trivial objects
+
+
+block objectLoad:
+  var location: Atomic[Object]
+  location.store(Object(val: 1))
+  doAssert location.load == Object(val: 1)
+  location.store(Object(val: 2))
+  doAssert location.load(moRelaxed) == Object(val: 2)
+  location.store(Object(val: 3))
+  doAssert location.load(moAcquire) == Object(val: 3)
+
+
+block objectStore:
+  var location: Atomic[Object]
+  location.store(Object(val: 1))
+  doAssert location.load == Object(val: 1)
+  location.store(Object(val: 2), moRelaxed)
+  doAssert location.load == Object(val: 2)
+  location.store(Object(val: 3), moRelease)
+  doAssert location.load == Object(val: 3)
+
+
+block objectExchange:
+  var location: Atomic[Object]
+  location.store(Object(val: 1))
+  doAssert location.exchange(Object(val: 2)) == Object(val: 1)
+  doAssert location.exchange(Object(val: 3), moRelaxed) == Object(val: 2)
+  doAssert location.exchange(Object(val: 4), moAcquire) == Object(val: 3)
+  doAssert location.exchange(Object(val: 5), moRelease) == Object(val: 4)
+  doAssert location.exchange(Object(val: 6), moAcquireRelease) == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchange(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchange(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchange(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchange(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchange(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+block objectCompareExchangeSuccessFailureDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchange(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeSuccessFailureDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchange(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchange(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+block objectCompareExchangeWeakDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchangeWeak(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeWeakDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchangeWeak(expected, Object(val: 2))
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+block objectCompareExchangeWeakSuccessFailureDoesExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 1)
+  location.store(Object(val: 1))
+  doAssert location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 2)
+  expected = Object(val: 2)
+  doAssert location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 2)
+  doAssert location.load == Object(val: 3)
+  expected = Object(val: 3)
+  doAssert location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 3)
+  doAssert location.load == Object(val: 4)
+  expected = Object(val: 4)
+  doAssert location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 4)
+  doAssert location.load == Object(val: 5)
+  expected = Object(val: 5)
+  doAssert location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 5)
+  doAssert location.load == Object(val: 6)
+
+
+block objectCompareExchangeWeakSuccessFailureDoesNotExchange:
+  var location: Atomic[Object]
+  var expected = Object(val: 10)
+  location.store(Object(val: 1))
+  doAssert not location.compareExchangeWeak(expected, Object(val: 2), moSequentiallyConsistent, moSequentiallyConsistent)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 3), moRelaxed, moRelaxed)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 4), moAcquire, moAcquire)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 5), moRelease, moRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+  expected = Object(val: 10)
+  doAssert not location.compareExchangeWeak(expected, Object(val: 6), moAcquireRelease, moAcquireRelease)
+  doAssert expected == Object(val: 1)
+  doAssert location.load == Object(val: 1)
+
+
+# Numerical operations
+
+
+block fetchAdd:
+  var location: Atomic[int]
+  doAssert location.fetchAdd(1) == 0
+  doAssert location.fetchAdd(1, moRelaxed) == 1
+  doAssert location.fetchAdd(1, moRelease) == 2
+  doAssert location.load == 3
+
+
+block fetchSub:
+  var location: Atomic[int]
+  doAssert location.fetchSub(1) == 0
+  doAssert location.fetchSub(1, moRelaxed) == -1
+  doAssert location.fetchSub(1, moRelease) == -2
+  doAssert location.load == -3
+
+
+block fetchAnd:
+  var location: Atomic[int]
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchAnd(j) == i)
+      doAssert(location.load == i.bitand(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchAnd(j, moRelaxed) == i)
+      doAssert(location.load == i.bitand(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchAnd(j, moRelease) == i)
+      doAssert(location.load == i.bitand(j))
+
+
+block fetchOr:
+  var location: Atomic[int]
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchOr(j) == i)
+      doAssert(location.load == i.bitor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchOr(j, moRelaxed) == i)
+      doAssert(location.load == i.bitor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchOr(j, moRelease) == i)
+      doAssert(location.load == i.bitor(j))
+
+
+block fetchXor:
+  var location: Atomic[int]
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchXor(j) == i)
+      doAssert(location.load == i.bitxor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchXor(j, moRelaxed) == i)
+      doAssert(location.load == i.bitxor(j))
+
+  for i in 0..16:
+    for j in 0..16:
+      location.store(i)
+      doAssert(location.fetchXor(j, moRelease) == i)
+      doAssert(location.load == i.bitxor(j))
+
+
+block atomicInc:
+  var location: Atomic[int]
+  location.atomicInc
+  doAssert location.load == 1
+  location.atomicInc(1)
+  doAssert location.load == 2
+  location += 1
+  doAssert location.load == 3
+
+
+block atomicDec:
+  var location: Atomic[int]
+  location.atomicDec
+  doAssert location.load == -1
+  location.atomicDec(1)
+  doAssert location.load == -2
+  location -= 1
+  doAssert location.load == -3
+
+
+# Flag operations
+
+
+block testAndSet:
+  var location: AtomicFlag
+  doAssert not location.testAndSet
+  doAssert location.testAndSet
+  doAssert location.testAndSet
+  location.clear()
+  doAssert not location.testAndSet(moRelaxed)
+  doAssert location.testAndSet(moRelaxed)
+  doAssert location.testAndSet(moRelaxed)
+  location.clear()
+  doAssert not location.testAndSet(moRelease)
+  doAssert location.testAndSet(moRelease)
+  doAssert location.testAndSet(moRelease)
+
+
+block clear:
+  var location: AtomicFlag
+  discard location.testAndSet
+  location.clear
+  doAssert not location.testAndSet
+  location.clear(moRelaxed)
+  doAssert not location.testAndSet
+  location.clear(moRelease)
+  doAssert not location.testAndSet
+
+block: # bug #18844
+  when not defined(cpp): # cpp pending pr #18836
+    type
+      Deprivation = object of RootObj
+        memes: Atomic[int]
+      Zoomer = object
+        dopamine: Deprivation
+
+    block:
+      var x = Deprivation()
+      var y = Zoomer()
+      doAssert x.memes.load == 0
+      doAssert y.dopamine.memes.load == 0
+
+    block:
+      var x: Deprivation
+      var y: Zoomer
+      doAssert x.memes.load == 0
+      doAssert y.dopamine.memes.load == 0
diff --git a/tests/stdlib/concurrency/tatomics_size.nim b/tests/stdlib/concurrency/tatomics_size.nim
new file mode 100644
index 000000000..f64adb308
--- /dev/null
+++ b/tests/stdlib/concurrency/tatomics_size.nim
@@ -0,0 +1,21 @@
+discard """
+  # 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
+import std/assertions
+
+block testSize: # issue 12726
+  type
+    Node = ptr object
+      # works
+      next: Atomic[pointer]
+      f:AtomicFlag
+    MyChannel = object
+      # type not defined completely
+      back: Atomic[ptr int]
+      f: AtomicFlag
+  static:
+    doAssert sizeof(Node) == sizeof(pointer)
+    doAssert sizeof(MyChannel) == sizeof(pointer) * 2
diff --git a/tests/stdlib/config.nims b/tests/stdlib/config.nims
new file mode 100644
index 000000000..dffae2812
--- /dev/null
+++ b/tests/stdlib/config.nims
@@ -0,0 +1,5 @@
+switch("styleCheck", "usages")
+switch("styleCheck", "error")
+switch("define", "nimPreviewSlimSystem")
+switch("define", "nimPreviewCstringConversion")
+switch("define", "nimPreviewProcConversion")
diff --git a/tests/stdlib/genericstrformat.nim b/tests/stdlib/genericstrformat.nim
new file mode 100644
index 000000000..0446f3269
--- /dev/null
+++ b/tests/stdlib/genericstrformat.nim
@@ -0,0 +1,16 @@
+# from issue #7632
+# imported and used in tstrformat
+
+import strformat
+
+proc fails*(a: static[int]): string =
+  &"formatted {a:2}"
+
+proc fails2*[N: static[int]](a: int): string =
+  &"formatted {a:2}"
+
+proc works*(a: int): string =
+  &"formatted {a:2}"
+
+proc fails0*(a: int or uint): string =
+  &"formatted {a:2}"
diff --git a/tests/stdlib/mgenast.nim b/tests/stdlib/mgenast.nim
new file mode 100644
index 000000000..b0904847e
--- /dev/null
+++ b/tests/stdlib/mgenast.nim
@@ -0,0 +1,57 @@
+import std/genasts
+import std/macros
+
+# Using a enum instead of, say, int, to make apparent potential bugs related to
+# forgetting converting to NimNode via newLit, see bug #9607
+
+type Foo* = enum kfoo0, kfoo1, kfoo2, kfoo3, kfoo4
+
+proc myLocalPriv(): auto = kfoo1
+proc myLocalPriv2(): auto = kfoo1
+macro bindme2*(): untyped =
+  genAst: myLocalPriv()
+macro bindme3*(): untyped =
+  ## myLocalPriv must be captured explicitly
+  genAstOpt({kDirtyTemplate}, myLocalPriv): myLocalPriv()
+
+macro bindme4*(): untyped =
+  ## calling this won't compile because `myLocalPriv` isn't captured
+  genAstOpt({kDirtyTemplate}): myLocalPriv()
+
+macro bindme5UseExpose*(): untyped =
+  genAst: myLocalPriv2()
+
+macro bindme5UseExposeFalse*(): untyped =
+  genAstOpt({kDirtyTemplate}): myLocalPriv2()
+
+# example from bug #7889
+from std/streams import newStringStream, readData, writeData
+
+macro bindme6UseExpose*(): untyped =
+  genAst:
+    var tst = "sometext"
+    var ss = newStringStream("anothertext")
+    when defined(gcArc) or defined(gcOrc):
+      prepareMutation(tst)
+    writeData(ss, tst[0].addr, 2)
+    discard readData(ss, tst[0].addr, 2)
+
+macro bindme6UseExposeFalse*(): untyped =
+  ## with `kDirtyTemplate`, requires passing all referenced symbols
+  ## which can be tedious
+  genAstOpt({kDirtyTemplate}, newStringStream, writeData, readData):
+    var tst = "sometext"
+    var ss = newStringStream("anothertext")
+    when defined(gcArc) or defined(gcOrc):
+      prepareMutation(tst)
+    writeData(ss, tst[0].addr, 2)
+    discard readData(ss, tst[0].addr, 2)
+
+
+proc locafun1(): auto = "in locafun1"
+proc locafun2(): auto = "in locafun2"
+# locafun3 in caller scope only
+macro mixinExample*(): untyped =
+  genAst:
+    mixin locafun1
+    (locafun1(), locafun2(), locafun3())
diff --git a/tests/stdlib/mimportutils.nim b/tests/stdlib/mimportutils.nim
new file mode 100644
index 000000000..678d9ec02
--- /dev/null
+++ b/tests/stdlib/mimportutils.nim
@@ -0,0 +1,38 @@
+type
+  A* = object
+    a0*: int
+    ha1: float
+  B = object
+    b0*: int
+    hb1: float
+  C* = ref object
+    c0: int
+    hc1: float
+  D* = ptr object
+    d0: int
+    hd1: float
+  PA* = ref A
+  PtA* = ptr A
+  E*[T] = object
+    he1: int
+  FSub[T1, T2] = object
+    h3: T1
+    h4: T2
+  F*[T1, T2] = ref FSub[T1, T2]
+  G*[T] = ref E[T]
+  H3*[T] = object
+    h5: T
+  H2*[T] = H3[T]
+  H1*[T] = ref H2[T]
+  H*[T] = H1[T]
+
+  Pity[T] = object
+    a: T
+  PityRef*[T] = ref Pity[T]
+  Hope*[T] = ref object
+    a: T
+
+type BAalias* = typeof(B.default)
+  # typeof is not a transparent abstraction, creates a `tyAlias`
+
+proc initB*(): B = B()
diff --git a/tests/stdlib/mintsets.nim b/tests/stdlib/mintsets.nim
new file mode 100644
index 000000000..98786e9ba
--- /dev/null
+++ b/tests/stdlib/mintsets.nim
@@ -0,0 +1,11 @@
+import std/intsets
+import std/assertions
+
+proc test1*[]() =
+  let a = initIntSet()
+  doAssert len(a) == 0
+
+proc test2*[]() =
+  var a = initIntSet()
+  var b = initIntSet()
+  a.incl b
diff --git a/tests/stdlib/mjsonexternproc.nim b/tests/stdlib/mjsonexternproc.nim
new file mode 100644
index 000000000..2967a1168
--- /dev/null
+++ b/tests/stdlib/mjsonexternproc.nim
@@ -0,0 +1,10 @@
+# Test case for https://github.com/nim-lang/Nim/issues/6385
+
+import json
+# export json
+
+proc foo*[T](a: T) =
+  let params = %*{
+    "data": [ 1 ]
+  }
+  echo $params
\ No newline at end of file
diff --git a/tests/stdlib/mstackframes.nim b/tests/stdlib/mstackframes.nim
new file mode 100644
index 000000000..f3daa1437
--- /dev/null
+++ b/tests/stdlib/mstackframes.nim
@@ -0,0 +1,38 @@
+import std/stackframes
+
+
+
+# line 5
+var count = 0
+
+proc main1(n: int) =
+  setFrameMsg $("main1", n)
+  if n > 0:
+    main1(n-1)
+
+proc main2(n: int) =
+  count.inc
+  setFrameMsg $("main2", n, count)
+  proc bar() =
+    setFrameMsg $("bar ",)
+    if n < 3: raise newException(CatchableError, "on purpose")
+  bar()
+  main2(n-1)
+
+proc main() =
+  var z = 0
+  setFrameMsg "\n  z: " & $z, prefix = ""
+  # multiple calls inside a frame are possible
+  z.inc
+  setFrameMsg "\n  z: " & $z, prefix = ""
+  try:
+    main2(5)
+  except CatchableError:
+    main1(10) # goes deep and then unwinds; sanity check to ensure `setFrameMsg` from inside
+              # `main1` won't invalidate the stacktrace; if StackTraceEntry.frameMsg
+              # were a reference instead of a copy, this would fail.
+    let e = getCurrentException()
+    let trace = e.getStackTrace
+    echo trace
+
+main()
diff --git a/tests/stdlib/nre/captures.nim b/tests/stdlib/nre/captures.nim
new file mode 100644
index 000000000..acc141baf
--- /dev/null
+++ b/tests/stdlib/nre/captures.nim
@@ -0,0 +1,64 @@
+import unittest, optional_nonstrict
+include nre
+
+block: # captures
+  block: # map capture names to numbers
+    check(getNameToNumberTable(re("(?<v1>1(?<v2>2(?<v3>3))(?'v4'4))()")) ==
+      { "v1" : 0, "v2" : 1, "v3" : 2, "v4" : 3 }.toTable())
+
+  block: # capture bounds are correct
+    let ex1 = re("([0-9])")
+    check("1 23".find(ex1).matchBounds == 0 .. 0)
+    check("1 23".find(ex1).captureBounds[0] == 0 .. 0)
+    check("1 23".find(ex1, 1).matchBounds == 2 .. 2)
+    check("1 23".find(ex1, 3).matchBounds == 3 .. 3)
+
+    let ex2 = re("()()()()()()()()()()([0-9])")
+    check("824".find(ex2).captureBounds[0] == 0 .. -1)
+    check("824".find(ex2).captureBounds[10] == 0 .. 0)
+
+    let ex3 = re("([0-9]+)")
+    check("824".find(ex3).captureBounds[0] == 0 .. 2)
+
+  block: # named captures
+    let ex1 = "foobar".find(re("(?<foo>foo)(?<bar>bar)"))
+    check(ex1.captures["foo"] == "foo")
+    check(ex1.captures["bar"] == "bar")
+
+    let ex2 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check("foo" in ex2.captureBounds)
+    check(ex2.captures["foo"] == "foo")
+    check(not ("bar" in ex2.captures))
+    expect KeyError:
+        discard ex2.captures["bar"]
+
+  block: # named capture bounds
+    let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check("foo" in ex1.captureBounds)
+    check(ex1.captureBounds["foo"] == 0..2)
+    check(not ("bar" in ex1.captures))
+    expect KeyError:
+        discard ex1.captures["bar"]
+
+  block: # capture count
+    let ex1 = re("(?<foo>foo)(?<bar>bar)?")
+    check(ex1.captureCount == 2)
+    check(ex1.captureNameId == {"foo" : 0, "bar" : 1}.toTable())
+
+  block: # named capture table
+    let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check(ex1.captures.toTable == {"foo" : "foo"}.toTable())
+    check(ex1.captureBounds.toTable == {"foo" : 0..2}.toTable())
+
+    let ex2 = "foobar".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check(ex2.captures.toTable == {"foo" : "foo", "bar" : "bar"}.toTable())
+
+  block: # capture sequence
+    let ex1 = "foo".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check(ex1.captures.toSeq == @[some("foo"), none(string)])
+    check(ex1.captureBounds.toSeq == @[some(0..2), none(Slice[int])])
+    check(ex1.captures.toSeq(some("")) == @[some("foo"), some("")])
+
+    let ex2 = "foobar".find(re("(?<foo>foo)(?<bar>bar)?"))
+    check(ex2.captures.toSeq == @[some("foo"), some("bar")])
+
diff --git a/tests/stdlib/nre/escape.nim b/tests/stdlib/nre/escape.nim
new file mode 100644
index 000000000..5e7dc0c0e
--- /dev/null
+++ b/tests/stdlib/nre/escape.nim
@@ -0,0 +1,7 @@
+import nre, unittest
+
+block: # escape strings
+  block: # escape strings
+    check("123".escapeRe() == "123")
+    check("[]".escapeRe() == r"\[\]")
+    check("()".escapeRe() == r"\(\)")
diff --git a/tests/stdlib/nre/find.nim b/tests/stdlib/nre/find.nim
new file mode 100644
index 000000000..7e7555d73
--- /dev/null
+++ b/tests/stdlib/nre/find.nim
@@ -0,0 +1,41 @@
+import unittest, sequtils
+import nre except toSeq
+import optional_nonstrict
+import times, strutils
+
+block: # find
+  block: # find text
+    check("3213a".find(re"[a-z]").match == "a")
+    check(toSeq(findIter("1 2 3 4 5 6 7 8 ", re" ")).map(
+      proc (a: RegexMatch): string = a.match
+    ) == @[" ", " ", " ", " ", " ", " ", " ", " "])
+
+  block: # find bounds
+    check(toSeq(findIter("1 2 3 4 5 ", re" ")).map(
+      proc (a: RegexMatch): Slice[int] = a.matchBounds
+    ) == @[1..1, 3..3, 5..5, 7..7, 9..9])
+
+  block: # overlapping find
+    check("222".findAll(re"22") == @["22"])
+    check("2222".findAll(re"22") == @["22", "22"])
+
+  block: # len 0 find
+    check("".findAll(re"\ ") == newSeq[string]())
+    check("".findAll(re"") == @[""])
+    check("abc".findAll(re"") == @["", "", "", ""])
+    check("word word".findAll(re"\b") == @["", "", "", ""])
+    check("word\r\lword".findAll(re"(*ANYCRLF)(?m)$") == @["", ""])
+    check("Ñлово Ñлово".findAll(re"(*U)\b") == @["", "", "", ""])
+
+  block: # bail early
+    ## we expect nothing to be found and we should be bailing out early which means that
+    ## the timing difference between searching in small and large data should be well
+    ## within a tolerance margin
+    const small = 10
+    const large = 1000
+    var smallData = repeat("url.sequence = \"http://whatever.com/jwhrejrhrjrhrjhrrjhrjrhrjrh\" ", small)
+    var largeData = repeat("url.sequence = \"http://whatever.com/jwhrejrhrjrhrjhrrjhrjrhrjrh\" ", large)
+    var expression = re"^url.* = &#34;(.*?)&#34;"
+
+    check(smallData.findAll(expression) == newSeq[string]())
+    check(largeData.findAll(expression) == newSeq[string]())
diff --git a/tests/stdlib/nre/init.nim b/tests/stdlib/nre/init.nim
new file mode 100644
index 000000000..f0c8e0a00
--- /dev/null
+++ b/tests/stdlib/nre/init.nim
@@ -0,0 +1,36 @@
+import unittest
+include nre
+
+block: # Test NRE initialization
+  block: # correct initialization
+    check(re("[0-9]+") != nil)
+    check(re("(?i)[0-9]+") != nil)
+
+  block: # options
+    check(extractOptions("(*NEVER_UTF)") ==
+          ("", pcre.NEVER_UTF, true))
+    check(extractOptions("(*UTF8)(*ANCHORED)(*UCP)z") ==
+          ("(*UTF8)(*UCP)z", pcre.ANCHORED, true))
+    check(extractOptions("(*ANCHORED)(*UTF8)(*JAVASCRIPT_COMPAT)z") ==
+          ("(*UTF8)z", pcre.ANCHORED or pcre.JAVASCRIPT_COMPAT, true))
+
+    check(extractOptions("(*NO_STUDY)(") == ("(", 0, false))
+
+    check(extractOptions("(*LIMIT_MATCH=6)(*ANCHORED)z") ==
+          ("(*LIMIT_MATCH=6)z", pcre.ANCHORED, true))
+
+  block: # incorrect options
+    for s in ["CR", "(CR", "(*CR", "(*abc)", "(*abc)CR",
+              "(?i)",
+              "(*LIMIT_MATCH=5", "(*NO_AUTO_POSSESS=5)"]:
+      let ss = s & "(*NEVER_UTF)"
+      check(extractOptions(ss) == (ss, 0, true))
+
+  block: # invalid regex
+    expect(SyntaxError): discard re("[0-9")
+    try:
+      discard re("[0-9")
+    except SyntaxError:
+      let ex = SyntaxError(getCurrentException())
+      check(ex.pos == 4)
+      check(ex.pattern == "[0-9")
diff --git a/tests/stdlib/nre/match.nim b/tests/stdlib/nre/match.nim
new file mode 100644
index 000000000..7e09a4b2f
--- /dev/null
+++ b/tests/stdlib/nre/match.nim
@@ -0,0 +1,18 @@
+include nre, unittest, optional_nonstrict
+
+block: # match
+  block: # upper bound must be inclusive
+    check("abc".match(re"abc", endpos = -1) == none(RegexMatch))
+    check("abc".match(re"abc", endpos = 1) == none(RegexMatch))
+    check("abc".match(re"abc", endpos = 2) != none(RegexMatch))
+
+  block: # match examples
+    check("abc".match(re"(\w)").captures[0] == "a")
+    check("abc".match(re"(?<letter>\w)").captures["letter"] == "a")
+    check("abc".match(re"(\w)\w").captures[-1] == "ab")
+    check("abc".match(re"(\w)").captureBounds[0] == 0 .. 0)
+    check("abc".match(re"").captureBounds[-1] == 0 .. -1)
+    check("abc".match(re"abc").captureBounds[-1] == 0 .. 2)
+
+  block: # match test cases
+    check("123".match(re"").matchBounds == 0 .. -1)
diff --git a/tests/stdlib/nre/misc.nim b/tests/stdlib/nre/misc.nim
new file mode 100644
index 000000000..b7df08ee9
--- /dev/null
+++ b/tests/stdlib/nre/misc.nim
@@ -0,0 +1,16 @@
+import unittest, nre, strutils, optional_nonstrict
+
+block: # Misc tests
+  block: # unicode
+    check("".find(re"(*UTF8)").match == "")
+    check("перевірка".replace(re"(*U)\w", "") == "")
+
+  block: # empty or non-empty match
+    check("abc".findAll(re"|.").join(":") == ":a::b::c:")
+    check("abc".findAll(re".|").join(":") == "a:b:c:")
+
+    check("abc".replace(re"|.", "x") == "xxxxxxx")
+    check("abc".replace(re".|", "x") == "xxxx")
+
+    check("abc".split(re"|.").join(":") == ":::::")
+    check("abc".split(re".|").join(":") == ":::")
diff --git a/tests/stdlib/nre/optional_nonstrict.nim b/tests/stdlib/nre/optional_nonstrict.nim
new file mode 100644
index 000000000..d13f4fab7
--- /dev/null
+++ b/tests/stdlib/nre/optional_nonstrict.nim
@@ -0,0 +1,3 @@
+import options
+converter option2val*[T](val: Option[T]): T =
+  return val.get()
diff --git a/tests/stdlib/nre/replace.nim b/tests/stdlib/nre/replace.nim
new file mode 100644
index 000000000..5cf659f21
--- /dev/null
+++ b/tests/stdlib/nre/replace.nim
@@ -0,0 +1,22 @@
+include nre
+import unittest
+
+block: # replace
+  block: # replace with 0-length strings
+    check("".replace(re"1", proc (v: RegexMatch): string = "1") == "")
+    check(" ".replace(re"", proc (v: RegexMatch): string = "1") == "1 1")
+    check("".replace(re"", proc (v: RegexMatch): string = "1") == "1")
+
+  block: # regular replace
+    check("123".replace(re"\d", "foo") == "foofoofoo")
+    check("123".replace(re"(\d)", "$1$1") == "112233")
+    check("123".replace(re"(\d)(\d)", "$1$2") == "123")
+    check("123".replace(re"(\d)(\d)", "$#$#") == "123")
+    check("123".replace(re"(?<foo>\d)(\d)", "$foo$#$#") == "1123")
+    check("123".replace(re"(?<foo>\d)(\d)", "${foo}$#$#") == "1123")
+
+  block: # replacing missing captures should throw instead of segfaulting
+    expect IndexDefect: discard "ab".replace(re"(a)|(b)", "$1$2")
+    expect IndexDefect: discard "b".replace(re"(a)?(b)", "$1$2")
+    expect KeyError: discard "b".replace(re"(a)?", "${foo}")
+    expect KeyError: discard "b".replace(re"(?<foo>a)?", "${foo}")
diff --git a/tests/stdlib/nre/split.nim b/tests/stdlib/nre/split.nim
new file mode 100644
index 000000000..3cd57bb82
--- /dev/null
+++ b/tests/stdlib/nre/split.nim
@@ -0,0 +1,53 @@
+import unittest, strutils
+include nre
+
+block: # string splitting
+  block: # splitting strings
+    check("1 2 3 4 5 6 ".split(re" ") == @["1", "2", "3", "4", "5", "6", ""])
+    check("1  2  ".split(re(" ")) == @["1", "", "2", "", ""])
+    check("1 2".split(re(" ")) == @["1", "2"])
+    check("foo".split(re("foo")) == @["", ""])
+    check("".split(re"foo") == @[""])
+    check("9".split(re"\son\s") == @["9"])
+
+  block: # captured patterns
+    check("12".split(re"(\d)") == @["", "1", "", "2", ""])
+
+  block: # maxsplit
+    check("123".split(re"", maxsplit = 2) == @["1", "23"])
+    check("123".split(re"", maxsplit = 1) == @["123"])
+    check("123".split(re"", maxsplit = -1) == @["1", "2", "3"])
+
+  block: # split with 0-length match
+    check("12345".split(re("")) == @["1", "2", "3", "4", "5"])
+    check("".split(re"") == newSeq[string]())
+    check("word word".split(re"\b") == @["word", " ", "word"])
+    check("word\r\lword".split(re"(*ANYCRLF)(?m)$") == @["word", "\r\lword"])
+    check("Ñлово Ñлово".split(re"(*U)(\b)") == @["", "Ñлово", "", " ", "", "Ñлово", ""])
+
+  block: # perl split tests
+    check("forty-two"                    .split(re"")      .join(",") == "f,o,r,t,y,-,t,w,o")
+    check("forty-two"                    .split(re"", 3)   .join(",") == "f,o,rty-two")
+    check("split this string"            .split(re" ")     .join(",") == "split,this,string")
+    check("split this string"            .split(re" ", 2)  .join(",") == "split,this string")
+    check("try$this$string"              .split(re"\$")    .join(",") == "try,this,string")
+    check("try$this$string"              .split(re"\$", 2) .join(",") == "try,this$string")
+    check("comma, separated, values"     .split(re", ")    .join("|") == "comma|separated|values")
+    check("comma, separated, values"     .split(re", ", 2) .join("|") == "comma|separated, values")
+    check("Perl6::Camelia::Test"         .split(re"::")    .join(",") == "Perl6,Camelia,Test")
+    check("Perl6::Camelia::Test"         .split(re"::", 2) .join(",") == "Perl6,Camelia::Test")
+    check("split,me,please"              .split(re",")     .join("|") == "split|me|please")
+    check("split,me,please"              .split(re",", 2)  .join("|") == "split|me,please")
+    check("Hello World    Goodbye   Mars".split(re"\s+")   .join(",") == "Hello,World,Goodbye,Mars")
+    check("Hello World    Goodbye   Mars".split(re"\s+", 3).join(",") == "Hello,World,Goodbye   Mars")
+    check("Hello test"                   .split(re"(\s+)") .join(",") == "Hello, ,test")
+    check("this will be split"           .split(re" ")     .join(",") == "this,will,be,split")
+    check("this will be split"           .split(re" ", 3)  .join(",") == "this,will,be split")
+    check("a.b"                          .split(re"\.")    .join(",") == "a,b")
+    check(""                             .split(re"")      .len       == 0)
+    check(":"                            .split(re"")      .len       == 1)
+
+  block: # start position
+    check("abc".split(re"", start = 1) == @["b", "c"])
+    check("abc".split(re"", start = 2) == @["c"])
+    check("abc".split(re"", start = 3) == newSeq[string]())
diff --git a/tests/stdlib/osproctest.nim b/tests/stdlib/osproctest.nim
new file mode 100644
index 000000000..8c4fba9ba
--- /dev/null
+++ b/tests/stdlib/osproctest.nim
@@ -0,0 +1,8 @@
+# This is test program for the osproc module.
+
+import os
+
+echo getCurrentDir()
+
+for i in 1..paramCount():
+  echo paramStr(i)
diff --git a/tests/stdlib/somesql.sql b/tests/stdlib/somesql.sql
new file mode 100644
index 000000000..74afcbab0
--- /dev/null
+++ b/tests/stdlib/somesql.sql
@@ -0,0 +1,298 @@
+create table anon40(
+  anon41 anon42 primary key default anon43(),
+  anon44 text unique not null,
+  anon45 text unique not null,
+  anon46 text not null,
+  anon47 text not null,
+  anon48 text default null,
+  anon49 text default null,
+  anon50 text default null,
+  anon51 text default null,
+  anon52 text default null,
+  anon53 text default null,
+  anon54 text default null,
+  anon55 text default null,
+  anon56 text default null,
+  anon57 text default null,
+  anon58 text default null,
+  anon59 text default null,
+  anon60 text default null,
+  anon61 text default null,
+  anon62 varchar(30) default null,
+  anon63 varchar(30) default null);
+create table anon64(
+  anon41 serial  primary key,
+  anon65 varchar(30) not null unique,
+  anon46 varchar(30) not null,
+  anon66 varchar(30) not null,
+  anon47 varchar(30) not null,
+  anon67 text not null,
+  anon55 varchar(30) not null unique,
+  anon68 varchar(30) default 'o',
+  anon69 boolean default true,
+  anon70 int not null  references anon40(anon41));
+create table anon71(
+  anon72 varchar(30) not null  primary key,
+  anon73 varchar(30) not null unique,
+  anon70 int not null  references anon40(anon41));
+create table anon74(
+  anon72 varchar(30) not null  primary key,
+  anon73 varchar(30) not null unique,
+  anon75 varchar(30) not null,
+  anon70 int not null references anon40(anon41),
+  foreign key(anon75) references anon71(anon72));
+create table anon76(
+  anon41 serial  primary key,
+  anon72 varchar(30) not null unique,
+  anon73 varchar(30) not null unique,
+  anon77 varchar(30) not null,
+  anon70 int not null  references anon40(anon41),
+  foreign key(anon77) references anon74(anon72));
+create table anon78(
+  anon41 serial  primary key,
+  anon72 varchar(30) not null unique,
+  anon73 varchar(30) not null unique,
+  anon79 int not null,
+  anon80 varchar(30) default null,
+  anon81 int not null,
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41),
+  foreign key(anon79) references anon78(anon41),
+  foreign key(anon81) references anon76(anon41));
+create table anon82(
+  anon41 serial  primary key,
+  anon72 varchar(30) not null unique,
+  anon73 text not null unique,
+  anon79 int not null,
+  anon80 text default null,
+  anon83 varchar(30) not null default 'd',
+  anon84 decimal default 0.00,
+  anon69 boolean not null default true,
+  anon85 decimal default 0.00,
+  anon86 decimal default 0.00,
+  anon87 decimal default 0.00,
+  anon70 int not null  references anon40(anon41),
+  foreign key(anon79) references anon78(anon41));
+create table anon88(
+  anon41 serial  primary key,
+  anon72 varchar(30) not null unique,
+  anon80 text default '',
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41));
+create table anon89(
+  anon90 int not null  primary key,
+  anon91 anon92 default 0.00,
+  anon93 varchar(30),
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41),
+  foreign key(anon90) references anon82(anon41));
+create table anon94(
+  anon41 serial  primary key,
+  anon73 text unique not null,
+  anon80 text default null,
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41));
+create table anon95(
+  anon41 serial  primary key,
+  anon73 text unique not null,
+  anon96 int not null  references anon94(anon41),
+  anon80 text default null,
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41));
+create table anon97(
+  anon41 serial  primary key,
+  anon73 text unique not null,
+  anon98 int not null  references anon95(anon41),
+  anon80 text default null,
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41));
+create table anon99(
+  anon41 serial  primary key,
+  anon73 varchar(30) unique not null,
+  anon100 varchar(30) default null,
+  anon101 anon102 default 0,
+  anon103 varchar(30) default 'g',
+  anon104 int not null,
+  anon105 decimal not null default 1,
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41));
+create table anon106(
+  anon107 varchar(30) default 'g',
+  anon108 int  references anon99(anon41) not null,
+  anon109 decimal default 1,
+  anon110 int  references anon99(anon41) not null,
+  anon70 int not null  references anon40(anon41));
+create table anon111(
+  anon41 serial  primary key,
+  anon112 text unique not null,
+  anon73 text unique not null,
+  anon113 anon102  references anon97(anon41) not null,
+  anon114 varchar(30) not null,
+  anon115 int not null  references anon88(anon41),
+  anon116 int not null  references anon82(anon41),
+  anon117 int not null  references anon82(anon41),
+  anon118 int not null  references anon82(anon41),
+  anon119 int not null  references anon82(anon41),
+  anon120 int not null  references anon82(anon41),
+  anon121 int not null  references anon82(anon41),
+  anon122 int  references anon99(anon41) not null,
+  anon123 decimal default 0.00,
+  anon124 decimal default 0.00,
+  anon69 boolean default true,
+  anon70 int not null  references anon40(anon41));
+create table anon125(
+  anon41 serial  primary key,
+  anon126 int  references anon111(anon41) not null,
+  anon80 text not null,
+  anon127 varchar(30) not null,
+  anon128 decimal default 0.00,
+  anon129 decimal default 0,
+  anon130 decimal default 0,
+  anon131 decimal default 0,
+  anon132 decimal default 0,
+  anon133 decimal default 0.00,
+  anon134 decimal default 0.00,
+  anon135 decimal default 0.00,
+  anon70 int not null  references anon40(anon41),  constraint anon136 check anon137(anon126, anon127, anon129));
+create table anon138(
+  anon41 serial  primary key,
+  anon126 int  references anon111(anon41) not null,
+  anon80 text not null,
+  anon127 varchar(30) not null,
+  anon139 date not null,
+  anon129 decimal default 0,
+  anon130 decimal default 0,
+  anon131 decimal default 0,
+  anon132 decimal default 0,
+  anon70 int not null  references anon40(anon41),  constraint anon136 check anon137(anon127, anon129));
+create table anon140(
+  anon41 serial  primary key,
+  anon141 text unique not null,
+  anon46 text default null,
+  anon47 text default null,
+  anon57 varchar(30) default null,
+  anon142 text default null,
+  anon51 text default null,
+  anon143 varchar(30) default null,
+  anon53 text default null,
+  anon54 text default null,
+  anon55 text default null,
+  anon45 text default null,
+  anon69 boolean default true,
+  anon70 int not null  references anon40(anon41));
+create table anon144(
+  anon41 serial  primary key,
+  anon72 varchar(30) unique not null,
+  anon73 varchar(30) unique not null,
+  anon80 varchar(30) default null,
+  anon69 boolean default true,
+  anon70 int not null  references anon40(anon41));
+create table anon145(
+  anon41 serial  primary key,
+  anon72 varchar(30) unique not null,
+  anon73 varchar(30) unique not null,
+  anon146 int not null,
+  anon147 anon92 default 1,
+  anon148 anon92 default 9999999,
+  anon80 varchar(30) default null,
+  anon69 boolean default true,
+  anon149 int default 0,
+  anon150 int not null,
+  anon151 anon92 default 0,
+  anon70 int not null  references anon40(anon41),
+  foreign key(anon150) references anon82(anon41),
+  foreign key(anon146) references anon144(anon41));
+create table anon152(
+  anon41 serial  primary key,
+  anon73 varchar(30) not null unique,
+  anon153 varchar(30) not null unique,
+  anon80 text default null,
+  anon69 boolean not null default true,
+  anon70 int not null  references anon40(anon41));
+create table anon154(
+  anon41 serial  primary key not null,
+  anon155 int not null unique,
+  date date default anon156 not null,
+  anon157 anon102  references anon140(anon41) not null,
+  anon158 anon102  references anon64(anon41) not null,
+  anon159 decimal default 0 not null,
+  anon160 decimal default 0 not null,
+  anon161 decimal default 0 not null,
+  anon162 decimal default 0 not null,
+  anon163 decimal default 0 not null,
+  anon164 decimal default 0 not null,
+  anon165 decimal default 0.00,
+  anon166 decimal default 0 not null,
+  anon167 decimal default 0.00,
+  anon168 decimal default 0 not null,
+  anon169 boolean default false,
+  anon170 varchar(30) default 'ca',
+  anon171 varchar(30) default 'n',
+  anon172 varchar(30) not null default 'd',
+  anon173 decimal default 0.00,
+  anon174 decimal default 0.00,
+  anon175 int,
+  anon176 varchar(30) default null,
+  anon177 varchar(30) default '',
+  anon178 varchar(30) default null,
+  anon70 int not null  references anon40(anon41));
+create table anon179(
+  anon41 serial  primary key not null,
+  anon180 anon102  references anon154(anon41) not null,
+  anon181 int  references anon125(anon41) not null,
+  anon182 int  references anon82(anon41) not null,
+  anon122 int  references anon99(anon41) not null,
+  anon183 decimal not null,
+  anon184 decimal default 0.00,
+  anon174 decimal default 0,
+  anon160 decimal default 0.00,
+  anon185 decimal default 0,
+  anon162 decimal default 0.00,
+  anon186 decimal default 0,
+  anon163 decimal default 0.00,
+  anon187 decimal default 0,
+  anon164 decimal default 0.00,
+  anon188 decimal default 0,
+  anon161 decimal default 0.00,
+  anon189 decimal default 0.00,
+  anon168 decimal default 0.00,
+  anon190 decimal not null,
+  anon191 decimal default 0,
+  anon83 varchar(30) not null default 't',
+  anon192 decimal default 0,
+  anon193 decimal not null,
+  anon194 decimal not null,
+  anon70 int not null  references anon40(anon41));
+create table anon195(
+  anon41 serial not null,
+  anon196 int not null,
+  anon175 char not null,
+  anon90 int not null  references anon82,
+  anon165 decimal default 0.00,
+  anon70 int not null  references anon40(anon41),  primary key(anon196, anon175));
+create table anon197(
+  anon41 serial not null,
+  anon196 int not null,
+  anon175 char not null,
+  anon198 int not null,
+  anon189 decimal default 0.00,
+  anon199 varchar(30) default null,
+  anon200 varchar(30) default null,
+  anon70 int not null  references anon40(anon41),
+  primary key(anon196, anon175),
+  foreign key(anon198) references anon145(anon41));
+create table anon201(
+  anon41 serial  primary key,
+  anon202 varchar(30) not null,
+  anon203 varchar(30) not null,
+  anon204 varchar(30) not null,
+  anon205 varchar(30) not null,
+  anon206 boolean default null,
+  anon70 int not null  references anon40(anon41));
+create table anon207(
+  anon41 serial  primary key,
+  anon208 varchar(30) not null,
+  anon209 varchar(30) not null,
+  anon204 varchar(30) default null,
+  anon70 int not null  references anon40(anon41));
+select * from anon207 where anon41 in (1, 2, 3);
diff --git a/tests/stdlib/t10231.nim b/tests/stdlib/t10231.nim
new file mode 100644
index 000000000..3d09721aa
--- /dev/null
+++ b/tests/stdlib/t10231.nim
@@ -0,0 +1,16 @@
+discard """
+  targets: "cpp"
+  action: run
+  exitcode: 0
+"""
+
+import os
+import std/assertions
+
+# consider moving this inside tosproc (taking care that it's for cpp mode)
+
+if paramCount() == 0:
+  # main process
+  doAssert execShellCmd(getAppFilename().quoteShell & " test") == 1
+else:
+  quit 1
diff --git a/tests/stdlib/t14139.nim b/tests/stdlib/t14139.nim
new file mode 100644
index 000000000..866bdb45f
--- /dev/null
+++ b/tests/stdlib/t14139.nim
@@ -0,0 +1,10 @@
+import std/heapqueue
+import std/assertions
+
+var test_queue : HeapQueue[int]
+
+test_queue.push(7)
+test_queue.push(3)
+test_queue.push(9)
+let i = test_queue.pushpop(10)
+doAssert i == 3
diff --git a/tests/stdlib/t15663.nim b/tests/stdlib/t15663.nim
new file mode 100644
index 000000000..8e8bfd9a8
--- /dev/null
+++ b/tests/stdlib/t15663.nim
@@ -0,0 +1,9 @@
+discard """
+  cmd: "nim c --gc:arc $file"
+  output: "Test"
+"""
+
+import std/widestrs
+
+let ws = newWideCString("Test")
+echo ws
diff --git a/tests/stdlib/t19304.nim b/tests/stdlib/t19304.nim
new file mode 100644
index 000000000..5e8795ac5
--- /dev/null
+++ b/tests/stdlib/t19304.nim
@@ -0,0 +1,7 @@
+import times
+
+type DjangoDateTime* = distinct DateTime
+
+# proc toTime*(x: DjangoDateTime): Time  {.borrow.} # <-- works
+proc format*(x: DjangoDateTime, f: TimeFormat,
+    loc: DateTimeLocale = DefaultLocale): string {.borrow.}
diff --git a/tests/stdlib/t20023.nim b/tests/stdlib/t20023.nim
new file mode 100644
index 000000000..8f12f8993
--- /dev/null
+++ b/tests/stdlib/t20023.nim
@@ -0,0 +1,10 @@
+import std/[tables, hashes, assertions]
+
+
+let t = ()
+var a = toTable({t:t})
+del(a,t)
+let b = default(typeof(a))
+
+doAssert a==b , "tables are not equal"
+doAssert hash(a) == hash(b), "table hashes are not equal"
diff --git a/tests/stdlib/t21251.nim b/tests/stdlib/t21251.nim
new file mode 100644
index 000000000..4402e9b7e
--- /dev/null
+++ b/tests/stdlib/t21251.nim
@@ -0,0 +1,6 @@
+import std / [tables, sets, sharedtables]
+
+var shared: SharedTable[int, int]
+shared.init
+
+shared[1] = 1
diff --git a/tests/stdlib/t21406.nim b/tests/stdlib/t21406.nim
new file mode 100644
index 000000000..86bf7b0c7
--- /dev/null
+++ b/tests/stdlib/t21406.nim
@@ -0,0 +1,7 @@
+import std/[times, strformat]
+import std/assertions
+
+let aTime = getTime()
+doAssert fmt"{aTime}" == $aTime
+let aNow = now()
+doAssert fmt"{aNow}" == $aNow
diff --git a/tests/stdlib/t21564.nim b/tests/stdlib/t21564.nim
new file mode 100644
index 000000000..0a5777d12
--- /dev/null
+++ b/tests/stdlib/t21564.nim
@@ -0,0 +1,32 @@
+discard """
+targets: "c js"
+"""
+
+import bitops
+import std/assertions
+
+proc main() =
+  block: # bug #21564
+    # tesk `bitops.bitsliced` patch
+    doAssert(0x17.bitsliced(4..7) == 0x01)
+    doAssert(0x17.bitsliced(0..3) == 0x07)
+
+  block:
+    # test in-place `bitops.bitslice`
+    var t = 0x12F4
+    t.bitslice(4..7)
+
+    doAssert(t == 0xF)
+
+  block:
+    # test `bitops.toMask` patch via bitops.masked
+    doAssert(0x12FFFF34.masked(8..23) == 0x00FFFF00)
+
+  block: # bug #22687
+    var a: uint8 = 0b1111_1111
+    doAssert a.bitsliced(4..7).int == 15
+
+main()
+
+static:
+  main()
diff --git a/tests/stdlib/t7686.nim b/tests/stdlib/t7686.nim
new file mode 100644
index 000000000..9902cfcb5
--- /dev/null
+++ b/tests/stdlib/t7686.nim
@@ -0,0 +1,10 @@
+import std/strutils
+import std/assertions
+
+type
+  MyEnum = enum
+    A,
+    a
+
+doAssert parseEnum[MyEnum]("A") == A
+doAssert parseEnum[MyEnum]("a") == a
diff --git a/tests/stdlib/t8925.nim b/tests/stdlib/t8925.nim
new file mode 100644
index 000000000..c55e93e73
--- /dev/null
+++ b/tests/stdlib/t8925.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "type mismatch between pattern '$$i' (position: 1) and HourRange var 'hour'"
+  file: "strscans.nim"
+"""
+
+import strscans
+
+type
+  HourRange = range[0..23]
+
+var
+  hour: HourRange
+  timeStr: string
+
+if scanf(timeStr, "$i", hour):
+  discard
diff --git a/tests/stdlib/t9754.nim b/tests/stdlib/t9754.nim
new file mode 100644
index 000000000..971b5a8fb
--- /dev/null
+++ b/tests/stdlib/t9754.nim
@@ -0,0 +1,6 @@
+discard """
+  joinable: false
+"""
+
+import tmarshal
+import tparsesql
\ No newline at end of file
diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim
new file mode 100644
index 000000000..e2024df0c
--- /dev/null
+++ b/tests/stdlib/talgorithm.nim
@@ -0,0 +1,275 @@
+discard """
+  targets: "c js"
+  matrix: "--mm:refc; --mm:orc"
+  output:'''@["3", "2", "1"]
+'''
+"""
+#12928,10456
+
+import std/[sequtils, algorithm, json, sugar]
+import std/assertions
+
+proc test() = 
+  try: 
+    let info = parseJson("""
+    {"a": ["1", "2", "3"]}
+    """)
+    let prefixes = info["a"].getElems().mapIt(it.getStr()).sortedByIt(it).reversed()
+    echo prefixes
+  except:
+    discard
+
+test()
+
+block:
+  # Tests for lowerBound
+  var arr = @[1, 2, 3, 5, 6, 7, 8, 9]
+  doAssert arr.lowerBound(0) == 0
+  doAssert arr.lowerBound(4) == 3
+  doAssert arr.lowerBound(5) == 3
+  doAssert arr.lowerBound(10) == 8
+  arr = @[1, 5, 10]
+  doAssert arr.lowerBound(4) == 1
+  doAssert arr.lowerBound(5) == 1
+  doAssert arr.lowerBound(6) == 2
+  # Tests for isSorted
+  var srt1 = [1, 2, 3, 4, 4, 4, 4, 5]
+  var srt2 = ["iello", "hello"]
+  var srt3 = [1.0, 1.0, 1.0]
+  var srt4: seq[int]
+  doAssert srt1.isSorted(cmp) == true
+  doAssert srt2.isSorted(cmp) == false
+  doAssert srt3.isSorted(cmp) == true
+  doAssert srt4.isSorted(cmp) == true
+  var srtseq = newSeq[int]()
+  doAssert srtseq.isSorted(cmp) == true
+  # Tests for reversed
+  var arr1 = @[0, 1, 2, 3, 4]
+  doAssert arr1.reversed() == @[4, 3, 2, 1, 0]
+  for i in 0 .. high(arr1):
+    doAssert arr1.reversed(0, i) == arr1.reversed()[high(arr1) - i .. high(arr1)]
+    doAssert arr1.reversed(i, high(arr1)) == arr1.reversed()[0 .. high(arr1) - i]
+
+block:
+  var list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+  let list2 = list.rotatedLeft(1 ..< 9, 3)
+  let expected = [0, 4, 5, 6, 7, 8, 1, 2, 3, 9, 10]
+
+  doAssert list.rotateLeft(1 ..< 9, 3) == 6
+  doAssert list == expected
+  doAssert list2 == @expected
+
+  var s0, s1, s2, s3, s4, s5 = "xxxabcdefgxxx"
+
+  doAssert s0.rotateLeft(3 ..< 10, 3) == 7
+  doAssert s0 == "xxxdefgabcxxx"
+  doAssert s1.rotateLeft(3 ..< 10, 2) == 8
+  doAssert s1 == "xxxcdefgabxxx"
+  doAssert s2.rotateLeft(3 ..< 10, 4) == 6
+  doAssert s2 == "xxxefgabcdxxx"
+  doAssert s3.rotateLeft(3 ..< 10, -3) == 6
+  doAssert s3 == "xxxefgabcdxxx"
+  doAssert s4.rotateLeft(3 ..< 10, -10) == 6
+  doAssert s4 == "xxxefgabcdxxx"
+  doAssert s5.rotateLeft(3 ..< 10, 11) == 6
+  doAssert s5 == "xxxefgabcdxxx"
+
+  block product:
+    doAssert product(newSeq[seq[int]]()) == newSeq[seq[int]](), "empty input"
+    doAssert product(@[newSeq[int](), @[], @[]]) == newSeq[seq[int]](), "bit more empty input"
+    doAssert product(@[@[1, 2]]) == @[@[1, 2]], "a simple case of one element"
+    doAssert product(@[@[1, 2], @[3, 4]]) == @[@[2, 4], @[1, 4], @[2, 3], @[1,
+        3]], "two elements"
+    doAssert product(@[@[1, 2], @[3, 4], @[5, 6]]) == @[@[2, 4, 6], @[1, 4, 6],
+        @[2, 3, 6], @[1, 3, 6], @[2, 4, 5], @[1, 4, 5], @[2, 3, 5], @[1, 3, 5]], "three elements"
+    doAssert product(@[@[1, 2], @[]]) == newSeq[seq[int]](), "two elements, but one empty"
+
+  block lowerBound:
+    doAssert lowerBound([1, 2, 4], 3, system.cmp[int]) == 2
+    doAssert lowerBound([1, 2, 2, 3], 4, system.cmp[int]) == 4
+    doAssert lowerBound([1, 2, 3, 10], 11) == 4
+
+  block upperBound:
+    doAssert upperBound([1, 2, 4], 3, system.cmp[int]) == 2
+    doAssert upperBound([1, 2, 2, 3], 3, system.cmp[int]) == 4
+    doAssert upperBound([1, 2, 3, 5], 3) == 3
+
+  block fillEmptySeq:
+    var s = newSeq[int]()
+    s.fill(0)
+
+  block testBinarySearch:
+    var noData: seq[int]
+    doAssert binarySearch(noData, 7) == -1
+    let oneData = @[1]
+    doAssert binarySearch(oneData, 1) == 0
+    doAssert binarySearch(oneData, 7) == -1
+    let someData = @[1, 3, 4, 7]
+    doAssert binarySearch(someData, 1) == 0
+    doAssert binarySearch(someData, 7) == 3
+    doAssert binarySearch(someData, -1) == -1
+    doAssert binarySearch(someData, 5) == -1
+    doAssert binarySearch(someData, 13) == -1
+    let moreData = @[1, 3, 5, 7, 4711]
+    doAssert binarySearch(moreData, -1) == -1
+    doAssert binarySearch(moreData, 1) == 0
+    doAssert binarySearch(moreData, 5) == 2
+    doAssert binarySearch(moreData, 6) == -1
+    doAssert binarySearch(moreData, 4711) == 4
+    doAssert binarySearch(moreData, 4712) == -1
+
+# merge
+proc main() =
+  block:
+    var x = @[1, 7, 8, 11, 21, 33, 45, 99]
+    var y = @[6, 7, 9, 12, 57, 66]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged == sorted(x & y)
+
+  block:
+    var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3]
+    var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13]
+
+    var merged: seq[int]
+    merged.merge(x, y, (x, y) => -system.cmp(x, y))
+    doAssert merged.isSorted((x, y) => -system.cmp(x, y))
+    doAssert merged == sorted(x & y, SortOrder.Descending)
+
+  block:
+    var x: seq[int] = @[]
+    var y = @[1]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.isSorted(SortOrder.Descending)
+    doAssert merged == @[1]
+
+  block:
+    var x = [1, 3, 5, 5, 7]
+    var y: seq[int] = @[]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged == @x
+
+  block:
+    var x = [1, 3, 5, 5, 7]
+    var y: seq[int] = @[]
+
+    var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34]
+    merged.merge(x, y)
+    doAssert merged == @[1, 2, 3, 5, 6, 56, 99, 2, 34, 1, 3, 5, 5, 7]
+
+
+  block:
+    var x: array[0, int]
+    var y = [1, 4, 6, 7, 9]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged == @y
+
+  block:
+    var x: array[0, int]
+    var y: array[0, int]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.len == 0
+
+  block:
+    var x: array[0, int]
+    var y: array[0, int]
+
+    var merged: seq[int] = @[99, 99, 99]
+    merged.setLen(0)
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.len == 0
+
+  block:
+    var x: seq[int]
+    var y: seq[int]
+
+    var merged: seq[int]
+    merged.merge(x, y)
+    doAssert merged.isSorted
+    doAssert merged.len == 0
+
+  block:
+    type
+      Record = object
+        id: int
+    
+    proc r(id: int): Record =
+      Record(id: id)
+
+    proc cmp(x, y: Record): int =
+      if x.id == y.id: return 0
+      if x.id < y.id: return -1
+      result = 1
+
+    var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
+    var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
+
+    var merged: seq[Record] = @[]
+    merged.merge(x, y, cmp)
+    doAssert merged.isSorted(cmp)
+    doAssert merged.len == 12
+
+  block:
+    type
+      Record = object
+        id: int
+    
+    proc r(id: int): Record =
+      Record(id: id)
+
+    proc ascendingCmp(x, y: Record): int =
+      if x.id == y.id: return 0
+      if x.id < y.id: return -1
+      result = 1
+
+    proc descendingCmp(x, y: Record): int =
+      if x.id == y.id: return 0
+      if x.id < y.id: return 1
+      result = -1
+
+    var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
+    var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
+
+    var merged: seq[Record]
+    merged.setLen(0)
+    merged.merge(x, y, ascendingCmp)
+    doAssert merged.isSorted(ascendingCmp)
+    doAssert merged == sorted(x & y, ascendingCmp)
+
+    reverse(x)
+    reverse(y)
+
+    merged.setLen(0)
+    merged.merge(x, y, descendingCmp)
+    doAssert merged.isSorted(descendingCmp)
+    doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending)
+
+    reverse(x)
+    reverse(y)
+    merged.setLen(0)
+    merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y))
+    doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y))
+    doAssert merged == sorted(x & y, ascendingCmp)
+
+
+  var x: seq[(int, int)]
+  x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0])
+  doAssert x == @[(1, 1), (1, 2)]
+
+static: main()
+main()
diff --git a/tests/stdlib/tarithmetics.nim b/tests/stdlib/tarithmetics.nim
new file mode 100644
index 000000000..0a6dd1fcf
--- /dev/null
+++ b/tests/stdlib/tarithmetics.nim
@@ -0,0 +1,50 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+import std/assertions
+# TODO: in future work move existing arithmetic tests (tests/arithm/*) into this file
+# FYI https://github.com/nim-lang/Nim/pull/17767
+
+template main =
+  # put all arithmetic tests
+
+  block tshr:
+    block: # Signed types
+      let
+        a1 = -3
+        a2 = -2
+        b1 = -4'i8
+        b2 = 1'i8
+        c1 = -5'i16
+        c2 = 1'i16
+        d1 = -7i32
+        d2 = 1'i32
+        e1 = -9'i64
+        e2 = 1'i64
+      doAssert a1 shr a2 == -1
+      doAssert b1 shr b2 == -2
+      doAssert c1 shr c2 == -3
+      doAssert d1 shr d2 == -4
+      doAssert e1 shr e2 == -5
+
+    block: # Unsigned types
+      let
+        a1 = 3'u
+        a2 = 2'u
+        b1 = 2'u8
+        b2 = 1'u8
+        c1 = 5'u16
+        c2 = 1'u16
+        d1 = 6'u32
+        d2 = 1'u32
+        e1 = 8'u64
+        e2 = 1'u64
+      doAssert a1 shr a2 == 0
+      doAssert b1 shr b2 == 1
+      doAssert c1 shr c2 == 2
+      doAssert d1 shr d2 == 3
+      doAssert e1 shr e2 == 4
+
+static: main()
+main()
diff --git a/tests/stdlib/tasynchttpserver.nim b/tests/stdlib/tasynchttpserver.nim
new file mode 100644
index 000000000..5a7e2da40
--- /dev/null
+++ b/tests/stdlib/tasynchttpserver.nim
@@ -0,0 +1,121 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  exitcode: 0
+  output: "OK"
+  disabled: false
+"""
+
+import strutils
+from net import TimeoutError
+import std/assertions
+
+import httpclient, asynchttpserver, asyncdispatch, asyncfutures
+
+template runTest(
+    handler: proc (request: Request): Future[void] {.gcsafe.},
+    request: proc (server: AsyncHttpServer): Future[AsyncResponse],
+    test: proc (response: AsyncResponse, body: string): Future[void]) =
+
+  let server = newAsyncHttpServer()
+
+  discard server.serve(Port(64123), handler)
+
+  let
+    response = waitFor(request(server))
+    body = waitFor(response.body)
+
+  discard test(response, body)
+
+proc test200() {.async.} =
+  proc handler(request: Request) {.async.} =
+    await request.respond(Http200, "Hello World, 200")
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http200)
+    doAssert(body == "Hello World, 200")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "16")
+
+  runTest(handler, request, test)
+
+proc test404() {.async.} =
+  proc handler(request: Request) {.async.} =
+    await request.respond(Http404, "Hello World, 404")
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http404)
+    doAssert(body == "Hello World, 404")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "16")
+
+  runTest(handler, request, test)
+
+proc testCustomEmptyHeaders() {.async.} =
+  proc handler(request: Request) {.async.} =
+    await request.respond(Http200, "Hello World, 200", newHttpHeaders())
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http200)
+    doAssert(body == "Hello World, 200")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "16")
+
+  runTest(handler, request, test)
+
+proc testCustomContentLength() {.async.} =
+  proc handler(request: Request) {.async.} =
+    let headers = newHttpHeaders()
+    headers["Content-Length"] = "0"
+    await request.respond(Http200, "Hello World, 200", headers)
+
+  proc request(server: AsyncHttpServer): Future[AsyncResponse] {.async.} =
+    let
+      client = newAsyncHttpClient()
+      clientResponse = await client.request("http://localhost:64123/")
+
+    server.close()
+
+    return clientResponse
+
+  proc test(response: AsyncResponse, body: string) {.async.} =
+    doAssert(response.status == $Http200)
+    doAssert(body == "")
+    doAssert(response.headers.hasKey("Content-Length"))
+    doAssert(response.headers["Content-Length"] == "0")
+    doAssert contentLength(response) == 0 # bug #22778
+
+  runTest(handler, request, test)
+
+waitFor(test200())
+waitFor(test404())
+waitFor(testCustomEmptyHeaders())
+waitFor(testCustomContentLength())
+
+echo "OK"
diff --git a/tests/stdlib/tasynchttpserver_transferencoding.nim b/tests/stdlib/tasynchttpserver_transferencoding.nim
new file mode 100644
index 000000000..886ba0f33
--- /dev/null
+++ b/tests/stdlib/tasynchttpserver_transferencoding.nim
@@ -0,0 +1,91 @@
+discard """
+  matrix: "--mm:arc; --mm:arc -d:danger; --mm:refc"
+  disabled: "freebsd"
+"""
+
+import httpclient, asynchttpserver, asyncdispatch, asyncfutures
+import net
+
+import std/asyncnet
+import std/nativesockets
+import std/assertions
+
+const postBegin = """
+POST / HTTP/1.1
+Transfer-Encoding:chunked
+
+"""
+
+template genTest(input, expected: string) =
+  proc handler(request: Request, future: Future[bool]) {.async, gcsafe.} =
+    doAssert(request.body == expected)
+    doAssert(request.headers.hasKey("Transfer-Encoding"))
+    doAssert(not request.headers.hasKey("Content-Length"))
+    future.complete(true)
+    await request.respond(Http200, "Good")
+
+  proc sendData(data: string, port: Port) {.async.} =
+    var socket = newSocket()
+    defer: socket.close()
+
+    socket.connect("127.0.0.1", port)
+    socket.send(data)
+
+  proc runTest(): Future[bool] {.async.} =
+    var handlerFuture = newFuture[bool]("runTest")
+    let data = postBegin & input
+    let server = newAsyncHttpServer()
+    server.listen(Port(0))
+
+    proc wrapper(request: Request): Future[void] {.gcsafe, closure.} =
+      handler(request, handlerFuture)
+    
+    asyncCheck sendData(data, server.getPort)
+    asyncCheck server.acceptRequest(wrapper)
+    doAssert await handlerFuture
+    
+    server.close()
+    return true
+
+  doAssert waitFor runTest()
+
+block:
+  const expected = "hello=world"
+  const input = ("b\r\n" &
+                 "hello=world\r\n" &
+                 "0\r\n" &
+                 "\r\n")
+  genTest(input, expected)
+block:
+  const expected = "hello encoding"
+  const input = ("e\r\n" &
+                 "hello encoding\r\n" &
+                 "0\r\n" &
+                 "\r\n")
+  genTest(input, expected)
+block:
+  # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
+  const expected = "MozillaDeveloperNetwork"
+  const input = ("7\r\n" &
+                "Mozilla\r\n" &
+                "9\r\n" &
+                "Developer\r\n" &
+                "7\r\n" &
+                "Network\r\n" &
+                "0\r\n" &
+                "\r\n")
+  genTest(input, expected)
+block:
+  # https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+  const expected = "Wikipedia in \r\n\r\nchunks."
+  const input = ("4\r\n" &
+                "Wiki\r\n" &
+                "6\r\n" &
+                "pedia \r\n" &
+                "E\r\n" &
+                "in \r\n" &
+                "\r\n" &
+                "chunks.\r\n" &
+                "0\r\n" &
+                "\r\n")
+  genTest(input, expected)
diff --git a/tests/stdlib/tbase64.nim b/tests/stdlib/tbase64.nim
new file mode 100644
index 000000000..c3bfb818e
--- /dev/null
+++ b/tests/stdlib/tbase64.nim
@@ -0,0 +1,63 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+import std/assertions
+import std/base64
+
+template main() =
+  doAssert encode("a") == "YQ=="
+  doAssert encode("Hello World") == "SGVsbG8gV29ybGQ="
+  doAssert encode("leasure.") == "bGVhc3VyZS4="
+  doAssert encode("easure.") == "ZWFzdXJlLg=="
+  doAssert encode("asure.") == "YXN1cmUu"
+  doAssert encode("sure.") == "c3VyZS4="
+  doAssert encode([1,2,3]) == "AQID"
+  doAssert encode(['h','e','y']) == "aGV5"
+
+  doAssert encode("") == ""
+  doAssert decode("") == ""
+
+  doAssert decode(" ") == ""
+
+  const testInputExpandsTo76 = "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
+  const testInputExpands = "++++++++++++++++++++++++++++++"
+  const longText = """Man is distinguished, not only by his reason, but by this
+    singular passion from other animals, which is a lust of the mind,
+    that by a perseverance of delight in the continued and indefatigable
+    generation of knowledge, exceeds the short vehemence of any carnal
+    pleasure."""
+  const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
+                 "asure.", longText, testInputExpandsTo76, testInputExpands]
+
+  doAssert encodeMime("foobarbaz", lineLen=4) == "Zm9v\r\nYmFy\r\nYmF6"
+  doAssert decode("Zm9v\r\nYmFy\r\nYmF6") == "foobarbaz"
+
+  for t in items(tests):
+    doAssert decode(encode(t)) == t
+    doAssert decode(encodeMime(t, lineLen=40)) == t
+    doAssert decode(encodeMime(t, lineLen=76)) == t
+
+  doAssertRaises(ValueError): discard decode("SGVsbG\x008gV29ybGQ=")
+
+  block base64urlSafe:
+    doAssert encode("c\xf7>", safe = true) == "Y_c-"
+    doAssert encode("c\xf7>", safe = false) == "Y/c+" # Not a nice URL :(
+    doAssert decode("Y/c+") == decode("Y_c-")
+    # Output must not change with safe=true
+    doAssert encode("Hello World", safe = true) == "SGVsbG8gV29ybGQ="
+    doAssert encode("leasure.", safe = true)  == "bGVhc3VyZS4="
+    doAssert encode("easure.", safe = true) == "ZWFzdXJlLg=="
+    doAssert encode("asure.", safe = true) == "YXN1cmUu"
+    doAssert encode("sure.", safe = true) == "c3VyZS4="
+    doAssert encode([1,2,3], safe = true) == "AQID"
+    doAssert encode(['h','e','y'], safe = true) == "aGV5"
+    doAssert encode("", safe = true) == ""
+    doAssert encode("the quick brown dog jumps over the lazy fox", safe = true) == "dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA=="
+
+func mainNoSideEffects() = main()
+
+static: main()
+main()
+static: mainNoSideEffects()
+mainNoSideEffects()
diff --git a/tests/stdlib/tbitops.nim b/tests/stdlib/tbitops.nim
new file mode 100644
index 000000000..3ecab2c64
--- /dev/null
+++ b/tests/stdlib/tbitops.nim
@@ -0,0 +1,351 @@
+discard """
+  nimout: "OK"
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+OK
+'''
+"""
+import bitops
+import std/assertions
+
+proc main() =
+  const U8 = 0b0011_0010'u8
+  const I8 = 0b0011_0010'i8
+  const U16 = 0b00100111_00101000'u16
+  const I16 = 0b00100111_00101000'i16
+  const U32 = 0b11010101_10011100_11011010_01010000'u32
+  const I32 = 0b11010101_10011100_11011010_01010000'i32
+  const U64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
+  const I64A = 0b01000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
+  const U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
+  const I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
+  const U64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'u64
+  const I64C = 0b00101010_11110101_10001111_00101000_00000100_00000000_00000100_00000000'i64
+
+  doAssert (U8 and U8) == bitand(U8,U8)
+  doAssert (I8 and I8) == bitand(I8,I8)
+  doAssert (U16 and U16) == bitand(U16,U16)
+  doAssert (I16 and I16) == bitand(I16,I16)
+  doAssert (U32 and U32) == bitand(U32,U32)
+  doAssert (I32 and I32) == bitand(I32,I32)
+  doAssert (U64A and U64B) == bitand(U64A,U64B)
+  doAssert (I64A and I64B) == bitand(I64A,I64B)
+  doAssert (U64A and U64B and U64C) == bitand(U64A,U64B,U64C)
+  doAssert (I64A and I64B and I64C) == bitand(I64A,I64B,I64C)
+
+  doAssert (U8 or U8) == bitor(U8,U8)
+  doAssert (I8 or I8) == bitor(I8,I8)
+  doAssert (U16 or U16) == bitor(U16,U16)
+  doAssert (I16 or I16) == bitor(I16,I16)
+  doAssert (U32 or U32) == bitor(U32,U32)
+  doAssert (I32 or I32) == bitor(I32,I32)
+  doAssert (U64A or U64B) == bitor(U64A,U64B)
+  doAssert (I64A or I64B) == bitor(I64A,I64B)
+  doAssert (U64A or U64B or U64C) == bitor(U64A,U64B,U64C)
+  doAssert (I64A or I64B or I64C) == bitor(I64A,I64B,I64C)
+
+  doAssert (U8 xor U8) == bitxor(U8,U8)
+  doAssert (I8 xor I8) == bitxor(I8,I8)
+  doAssert (U16 xor U16) == bitxor(U16,U16)
+  doAssert (I16 xor I16) == bitxor(I16,I16)
+  doAssert (U32 xor U32) == bitxor(U32,U32)
+  doAssert (I32 xor I32) == bitxor(I32,I32)
+  doAssert (U64A xor U64B) == bitxor(U64A,U64B)
+  doAssert (I64A xor I64B) == bitxor(I64A,I64B)
+  doAssert (U64A xor U64B xor U64C) == bitxor(U64A,U64B,U64C)
+  doAssert (I64A xor I64B xor I64C) == bitxor(I64A,I64B,I64C)
+
+  doAssert not(U8) == bitnot(U8)
+  doAssert not(I8) == bitnot(I8)
+  doAssert not(U16) == bitnot(U16)
+  doAssert not(I16) == bitnot(I16)
+  doAssert not(U32) == bitnot(U32)
+  doAssert not(I32) == bitnot(I32)
+  doAssert not(U64A) == bitnot(U64A)
+  doAssert not(I64A) == bitnot(I64A)
+
+  doAssert U64A.fastLog2 == 62
+  doAssert I64A.fastLog2 == 62
+  doAssert U64A.countLeadingZeroBits == 1
+  doAssert I64A.countLeadingZeroBits == 1
+  doAssert U64A.countTrailingZeroBits == 0
+  doAssert I64A.countTrailingZeroBits == 0
+  doAssert U64A.firstSetBit == 1
+  doAssert I64A.firstSetBit == 1
+  doAssert U64A.parityBits == 1
+  doAssert I64A.parityBits == 1
+  doAssert U64A.countSetBits == 29
+  doAssert I64A.countSetBits == 29
+  doAssert U64A.rotateLeftBits(37) == 0b00101001_00001111_01000010_00101000_10000111_11101111_10010001_01010011'u64
+  doAssert U64A.rotateRightBits(37) == 0b01010100_11001010_01000011_11010000_10001010_00100001_11111011_11100100'u64
+
+  doAssert U64B.firstSetBit == 36
+  doAssert I64B.firstSetBit == 36
+
+  doAssert U32.fastLog2 == 31
+  doAssert I32.fastLog2 == 31
+  doAssert U32.countLeadingZeroBits == 0
+  doAssert I32.countLeadingZeroBits == 0
+  doAssert U32.countTrailingZeroBits == 4
+  doAssert I32.countTrailingZeroBits == 4
+  doAssert U32.firstSetBit == 5
+  doAssert I32.firstSetBit == 5
+  doAssert U32.parityBits == 0
+  doAssert I32.parityBits == 0
+  doAssert U32.countSetBits == 16
+  doAssert I32.countSetBits == 16
+  doAssert U32.rotateLeftBits(21) == 0b01001010_00011010_10110011_10011011'u32
+  doAssert U32.rotateRightBits(21) == 0b11100110_11010010_10000110_10101100'u32
+
+  doAssert U16.fastLog2 == 13
+  doAssert I16.fastLog2 == 13
+  doAssert U16.countLeadingZeroBits == 2
+  doAssert I16.countLeadingZeroBits == 2
+  doAssert U16.countTrailingZeroBits == 3
+  doAssert I16.countTrailingZeroBits == 3
+  doAssert U16.firstSetBit == 4
+  doAssert I16.firstSetBit == 4
+  doAssert U16.parityBits == 0
+  doAssert I16.parityBits == 0
+  doAssert U16.countSetBits == 6
+  doAssert I16.countSetBits == 6
+  doAssert U16.rotateLeftBits(12) == 0b10000010_01110010'u16
+  doAssert U16.rotateRightBits(12) == 0b01110010_10000010'u16
+
+  doAssert U8.fastLog2 == 5
+  doAssert I8.fastLog2 == 5
+  doAssert U8.countLeadingZeroBits == 2
+  doAssert I8.countLeadingZeroBits == 2
+  doAssert U8.countTrailingZeroBits == 1
+  doAssert I8.countTrailingZeroBits == 1
+  doAssert U8.firstSetBit == 2
+  doAssert I8.firstSetBit == 2
+  doAssert U8.parityBits == 1
+  doAssert I8.parityBits == 1
+  doAssert U8.countSetBits == 3
+  doAssert I8.countSetBits == 3
+  doAssert U8.rotateLeftBits(3) == 0b10010001'u8
+  doAssert U8.rotateRightBits(3) == 0b0100_0110'u8
+
+  template test_undefined_impl(ffunc: untyped; expected: int; is_static: bool) =
+    doAssert ffunc(0'u8) == expected
+    doAssert ffunc(0'i8) == expected
+    doAssert ffunc(0'u16) == expected
+    doAssert ffunc(0'i16) == expected
+    doAssert ffunc(0'u32) == expected
+    doAssert ffunc(0'i32) == expected
+    doAssert ffunc(0'u64) == expected
+    doAssert ffunc(0'i64) == expected
+
+  template test_undefined(ffunc: untyped; expected: int) =
+    test_undefined_impl(ffunc, expected, false)
+    static:
+      test_undefined_impl(ffunc, expected, true)
+
+  when defined(noUndefinedBitOpts):
+    # check for undefined behavior with zero.
+    test_undefined(countSetBits, 0)
+    test_undefined(parityBits, 0)
+    test_undefined(firstSetBit, 0)
+    test_undefined(countLeadingZeroBits, 0)
+    test_undefined(countTrailingZeroBits, 0)
+    test_undefined(fastLog2, -1)
+
+    # check for undefined behavior with rotate by zero.
+    doAssert U8.rotateLeftBits(0) == U8
+    doAssert U8.rotateRightBits(0) == U8
+    doAssert U16.rotateLeftBits(0) == U16
+    doAssert U16.rotateRightBits(0) == U16
+    doAssert U32.rotateLeftBits(0) == U32
+    doAssert U32.rotateRightBits(0) == U32
+    doAssert U64A.rotateLeftBits(0) == U64A
+    doAssert U64A.rotateRightBits(0) == U64A
+
+    # check for undefined behavior with rotate by integer width.
+    doAssert U8.rotateLeftBits(8) == U8
+    doAssert U8.rotateRightBits(8) == U8
+    doAssert U16.rotateLeftBits(16) == U16
+    doAssert U16.rotateRightBits(16) == U16
+    doAssert U32.rotateLeftBits(32) == U32
+    doAssert U32.rotateRightBits(32) == U32
+    doAssert U64A.rotateLeftBits(64) == U64A
+    doAssert U64A.rotateRightBits(64) == U64A
+
+  block:
+    # basic mask operations (mutating)
+    var v: uint8
+    v.setMask(0b1100_0000)
+    v.setMask(0b0000_1100)
+    doAssert v == 0b1100_1100
+    v.flipMask(0b0101_0101)
+    doAssert v == 0b1001_1001
+    v.clearMask(0b1000_1000)
+    doAssert v == 0b0001_0001
+    v.clearMask(0b0001_0001)
+    doAssert v == 0b0000_0000
+    v.setMask(0b0001_1110)
+    doAssert v == 0b0001_1110
+    v.mask(0b0101_0100)
+    doAssert v == 0b0001_0100
+  block:
+    # basic mask operations (non-mutating)
+    let v = 0b1100_0000'u8
+    doAssert v.masked(0b0000_1100) == 0b0000_0000
+    doAssert v.masked(0b1000_1100) == 0b1000_0000
+    doAssert v.setMasked(0b0000_1100) == 0b1100_1100
+    doAssert v.setMasked(0b1000_1110) == 0b1100_1110
+    doAssert v.flipMasked(0b1100_1000) == 0b0000_1000
+    doAssert v.flipMasked(0b0000_1100) == 0b1100_1100
+    let t = 0b1100_0110'u8
+    doAssert t.clearMasked(0b0100_1100) == 0b1000_0010
+    doAssert t.clearMasked(0b1100_0000) == 0b0000_0110
+  block:
+    # basic bitslice opeartions
+    let a = 0b1111_1011'u8
+    doAssert a.bitsliced(0 .. 3) == 0b1011
+    doAssert a.bitsliced(2 .. 3) == 0b10
+    doAssert a.bitsliced(4 .. 7) == 0b1111
+
+    # same thing, but with exclusive ranges.
+    doAssert a.bitsliced(0 ..< 4) == 0b1011
+    doAssert a.bitsliced(2 ..< 4) == 0b10
+    doAssert a.bitsliced(4 ..< 8) == 0b1111
+
+    # mutating
+    var b = 0b1111_1011'u8
+    b.bitslice(1 .. 3)
+    doAssert b == 0b101
+
+    # loop test:
+    let c = 0b1111_1111'u8
+    for i in 0 .. 7:
+      doAssert c.bitsliced(i .. 7) == c shr i
+  block:
+    # bitslice versions of mask operations (mutating)
+    var a = 0b1100_1100'u8
+    let b = toMask[uint8](2 .. 3)
+    a.mask(b)
+    doAssert a == 0b0000_1100
+    a.setMask(4 .. 7)
+    doAssert a == 0b1111_1100
+    a.flipMask(1 .. 3)
+    doAssert a == 0b1111_0010
+    a.flipMask(2 .. 4)
+    doAssert a == 0b1110_1110
+    a.clearMask(2 .. 4)
+    doAssert a == 0b1110_0010
+    a.mask(0 .. 3)
+    doAssert a == 0b0000_0010
+
+    # composition of mask from slices:
+    let c = bitor(toMask[uint8](2 .. 3), toMask[uint8](5 .. 7))
+    doAssert c == 0b1110_1100'u8
+  block:
+    # bitslice versions of mask operations (non-mutating)
+    let a = 0b1100_1100'u8
+    doAssert a.masked(toMask[uint8](2 .. 3)) == 0b0000_1100
+    doAssert a.masked(2 .. 3) == 0b0000_1100
+    doAssert a.setMasked(0 .. 3) == 0b1100_1111
+    doAssert a.setMasked(3 .. 4) == 0b1101_1100
+    doAssert a.flipMasked(0 .. 3) == 0b1100_0011
+    doAssert a.flipMasked(0 .. 7) == 0b0011_0011
+    doAssert a.flipMasked(2 .. 3) == 0b1100_0000
+    doAssert a.clearMasked(2 .. 3) == 0b1100_0000
+    doAssert a.clearMasked(3 .. 6) == 0b1000_0100
+  block:
+    # single bit operations
+    var v: uint8
+    v.setBit(0)
+    doAssert v == 0x0000_0001
+    v.setBit(1)
+    doAssert v == 0b0000_0011
+    v.flipBit(7)
+    doAssert v == 0b1000_0011
+    v.clearBit(0)
+    doAssert v == 0b1000_0010
+    v.flipBit(1)
+    doAssert v == 0b1000_0000
+    doAssert v.testBit(7)
+    doAssert not v.testBit(6)
+  block:
+    # multi bit operations
+    var v: uint8
+    v.setBits(0, 1, 7)
+    doAssert v == 0b1000_0011
+    v.flipBits(2, 3)
+    doAssert v == 0b1000_1111
+    v.clearBits(7, 0, 1)
+    doAssert v == 0b0000_1100
+  block:
+    # signed
+    var v: int8
+    v.setBit(7)
+    doAssert v == -128
+  block:
+    var v: uint64
+    v.setBit(63)
+    doAssert v == 0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000'u64
+
+  block:
+    proc testReverseBitsInvo(x: SomeUnsignedInt) =
+      doAssert reverseBits(reverseBits(x)) == x
+
+    proc testReverseBitsPerType(x, reversed: uint64) =
+      doAssert reverseBits(x) == reversed
+      doAssert reverseBits(cast[uint32](x)) == cast[uint32](reversed shr 32)
+      doAssert reverseBits(cast[uint32](x shr 16)) == cast[uint32](reversed shr 16)
+      doAssert reverseBits(cast[uint16](x)) == cast[uint16](reversed shr 48)
+      doAssert reverseBits(cast[uint8](x)) == cast[uint8](reversed shr 56)
+
+      testReverseBitsInvo(x)
+      testReverseBitsInvo(cast[uint32](x))
+      testReverseBitsInvo(cast[uint16](x))
+      testReverseBitsInvo(cast[uint8](x))
+
+    proc testReverseBitsRefl(x, reversed: uint64) =
+      testReverseBitsPerType(x, reversed)
+      testReverseBitsPerType(reversed, x)
+
+    proc testReverseBitsShift(d, b: uint64) =
+      var
+        x = d
+        y = b
+
+      for i in 1..64:
+        testReverseBitsRefl(x, y)
+        x = x shl 1
+        y = y shr 1
+
+    proc testReverseBits(d, b: uint64) =
+      testReverseBitsShift(d, b)
+
+    testReverseBits(0x0u64, 0x0u64)
+    testReverseBits(0xffffffffffffffffu64, 0xffffffffffffffffu64)
+    testReverseBits(0x0123456789abcdefu64, 0xf7b3d591e6a2c480u64)
+    testReverseBits(0x5555555555555555u64, 0xaaaaaaaaaaaaaaaau64)
+    testReverseBits(0x5555555500000001u64, 0x80000000aaaaaaaau64)
+    testReverseBits(0x55555555aaaaaaaau64, 0x55555555aaaaaaaau64)
+    testReverseBits(0xf0f0f0f00f0f0f0fu64, 0xf0f0f0f00f0f0f0fu64)
+    testReverseBits(0x181881810ff00916u64, 0x68900ff081811818u64)
+
+  echo "OK"
+
+  # bug #7587
+  doAssert popcount(0b11111111'i8) == 8
+
+block: # not ready for vm because exception is compile error
+  try:
+    var v: uint32
+    var i = 32
+    v.setBit(i)
+    doAssert false
+  except RangeDefect:
+    discard
+  except:
+    doAssert false
+
+
+main()
+static:
+  # test everything on vm as well
+  main()
diff --git a/tests/stdlib/tbitops.nim.cfg b/tests/stdlib/tbitops.nim.cfg
new file mode 100644
index 000000000..013e8d38e
--- /dev/null
+++ b/tests/stdlib/tbitops.nim.cfg
@@ -0,0 +1 @@
+-d:noUndefinedBitOpts
diff --git a/tests/stdlib/tbitops_utils.nim b/tests/stdlib/tbitops_utils.nim
new file mode 100644
index 000000000..e3f96fecc
--- /dev/null
+++ b/tests/stdlib/tbitops_utils.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/bitops_utils
+import std/assertions
+
+template chk(a, b) =
+  let a2 = castToUnsigned(a)
+  doAssert a2 == b
+  doAssert type(a2) is type(b)
+  doAssert type(b) is type(a2)
+
+chk 1'i8, 1'u8
+chk -1'i8, 255'u8
+chk 1'u8, 1'u8
+chk 1'u, 1'u
+chk -1, cast[uint](-1)
+chk -1'i64, cast[uint64](-1)
diff --git a/tests/stdlib/tcasts.nim b/tests/stdlib/tcasts.nim
new file mode 100644
index 000000000..e01c7e940
--- /dev/null
+++ b/tests/stdlib/tcasts.nim
@@ -0,0 +1,26 @@
+import std/[strutils]
+import std/[assertions, objectdollar]
+
+# bug #19101
+type
+  Small = object
+    a: int
+
+  Big = object
+    a, b, c, d: int
+
+proc main =
+  var
+    n = 1'i8
+    f = 2.0
+    s = Small(a: 1)
+    b = Big(a: 12345, b: 23456, c: 34567, d: 45678)
+
+  doAssert $cast[int](f).toBin(64) == "0100000000000000000000000000000000000000000000000000000000000000"
+  f = cast[float](n)
+  doAssert $cast[int](f).toBin(64) == "0000000000000000000000000000000000000000000000000000000000000001"
+
+  doAssert $b == "(a: 12345, b: 23456, c: 34567, d: 45678)"
+  b = cast[Big](s)
+  doAssert $b == "(a: 1, b: 0, c: 0, d: 0)"
+main()
diff --git a/tests/stdlib/tcgi.nim b/tests/stdlib/tcgi.nim
new file mode 100644
index 000000000..ef39450da
--- /dev/null
+++ b/tests/stdlib/tcgi.nim
@@ -0,0 +1,31 @@
+discard """

+  matrix: "--mm:refc; --mm:orc"

+"""

+

+import std/unittest

+import std/[cgi, strtabs, sugar]

+import std/assertions

+

+block: # Test cgi module

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

+

+  block: # test query parsing with readData

+    let parsedQuery = readData(queryString)

+

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

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

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

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

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

+

+    expect KeyError:

+      discard parsedQuery["not_existing_key"]

+

+# bug #15369

+let queryString = "a=1&b=0&c=3&d&e&a=5&a=t%20e%20x%20t&e=http%3A%2F%2Fw3schools.com%2Fmy%20test.asp%3Fname%3Dst%C3%A5le%26car%3Dsaab"

+

+doAssert collect(for pair in decodeData(queryString): pair) ==

+  @[("a", "1"), ("b", "0"), ("c", "3"),

+    ("d", ""),("e", ""), ("a", "5"), ("a", "t e x t"),

+  ("e", "http://w3schools.com/my test.asp?name=ståle&car=saab")

+]

diff --git a/tests/stdlib/tclosures.nim b/tests/stdlib/tclosures.nim
new file mode 100644
index 000000000..84b033fa8
--- /dev/null
+++ b/tests/stdlib/tclosures.nim
@@ -0,0 +1,47 @@
+discard """
+  targets: "c js"
+"""
+
+import std/assertions
+
+block: # bug #4299
+  proc scopeProc() =
+    proc normalProc() =
+      discard
+
+    proc genericProc[T]() =
+      normalProc()
+
+    genericProc[string]()
+
+  scopeProc()
+
+block: # bug #12492
+  proc foo() =
+    var i = 0
+    proc bar() =
+      inc i
+
+    bar()
+    doAssert i == 1
+
+  foo()
+  static:
+    foo()
+
+block: # bug #10849
+  type
+    Generic[T] = ref object
+      getState: proc(): T
+
+  proc newGeneric[T](): Generic[T] =
+    var state: T
+
+    proc getState[T](): T =
+      state
+
+    Generic[T](getState: getState)
+
+  let g = newGeneric[int]()
+  let state = g.getState()
+  doAssert state == 0
diff --git a/tests/stdlib/tcmdline.nim b/tests/stdlib/tcmdline.nim
new file mode 100644
index 000000000..8b428900b
--- /dev/null
+++ b/tests/stdlib/tcmdline.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+  joinable: false
+"""
+
+import std/os
+import std/assertions
+
+var params = paramCount()
+doAssert params == 0
+doAssert paramStr(0).len > 0
+doAssert commandLineParams().len == 0
diff --git a/tests/stdlib/tcomplex.nim b/tests/stdlib/tcomplex.nim
new file mode 100644
index 000000000..ca83314b9
--- /dev/null
+++ b/tests/stdlib/tcomplex.nim
@@ -0,0 +1,115 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[complex, math]
+import std/assertions
+
+proc `=~`[T](x, y: Complex[T]): bool =
+  result = abs(x.re-y.re) < 1e-6 and abs(x.im-y.im) < 1e-6
+
+proc `=~`[T](x: Complex[T]; y: T): bool =
+  result = abs(x.re-y) < 1e-6 and abs(x.im) < 1e-6
+
+let
+  z: Complex64 = complex(0.0, 0.0)
+  oo: Complex64 = complex(1.0, 1.0)
+  a: Complex64 = complex(1.0, 2.0)
+  b: Complex64 = complex(-1.0, -2.0)
+  m1: Complex64 = complex(-1.0, 0.0)
+  i: Complex64 = complex(0.0, 1.0)
+  one: Complex64 = complex(1.0, 0.0)
+  tt: Complex64 = complex(10.0, 20.0)
+  ipi: Complex64 = complex(0.0, -PI)
+
+doAssert(a/2.0 =~ complex(0.5, 1.0))
+doAssert(a == a)
+doAssert((a-a) == z)
+doAssert((a+b) == z)
+doAssert((a+b) =~ 0.0)
+doAssert((a/b) == m1)
+doAssert((1.0/a) =~ complex(0.2, -0.4))
+doAssert((a*b) == complex(3.0, -4.0))
+doAssert(10.0*a == tt)
+doAssert(a*10.0 == tt)
+doAssert(tt/10.0 == a)
+doAssert(oo+(-1.0) == i)
+doAssert( (-1.0)+oo == i)
+doAssert(abs(oo) == sqrt(2.0))
+doAssert(conjugate(a) == complex(1.0, -2.0))
+doAssert(sqrt(m1) == i)
+doAssert(exp(ipi) =~ m1)
+
+doAssert(pow(a, b) =~ complex(-3.72999124927876, -1.68815826725068))
+doAssert(pow(z, a) =~ complex(0.0, 0.0))
+doAssert(pow(z, z) =~ complex(1.0, 0.0))
+doAssert(pow(a, one) =~ a)
+doAssert(pow(a, m1) =~ complex(0.2, -0.4))
+doAssert(pow(a, 2.0) =~ complex(-3.0, 4.0))
+doAssert(pow(a, 2) =~ complex(-3.0, 4.0))
+doAssert(not(pow(a, 2.0) =~ a))
+
+doAssert(ln(a) =~ complex(0.804718956217050, 1.107148717794090))
+doAssert(log10(a) =~ complex(0.349485002168009, 0.480828578784234))
+doAssert(log2(a) =~ complex(1.16096404744368, 1.59727796468811))
+
+doAssert(sin(a) =~ complex(3.16577851321617, 1.95960104142161))
+doAssert(cos(a) =~ complex(2.03272300701967, -3.05189779915180))
+doAssert(tan(a) =~ complex(0.0338128260798967, 1.0147936161466335))
+doAssert(cot(a) =~ 1.0 / tan(a))
+doAssert(sec(a) =~ 1.0 / cos(a))
+doAssert(csc(a) =~ 1.0 / sin(a))
+doAssert(arcsin(a) =~ complex(0.427078586392476, 1.528570919480998))
+doAssert(arccos(a) =~ complex(1.14371774040242, -1.52857091948100))
+doAssert(arctan(a) =~ complex(1.338972522294494, 0.402359478108525))
+doAssert(arccot(a) =~ complex(0.2318238045004031, -0.402359478108525))
+doAssert(arcsec(a) =~ complex(1.384478272687081, 0.3965682301123288))
+doAssert(arccsc(a) =~ complex(0.1863180541078155, -0.3965682301123291))
+
+doAssert(cosh(a) =~ complex(-0.642148124715520, 1.068607421382778))
+doAssert(sinh(a) =~ complex(-0.489056259041294, 1.403119250622040))
+doAssert(tanh(a) =~ complex(1.1667362572409199, -0.243458201185725))
+doAssert(sech(a) =~ 1.0 / cosh(a))
+doAssert(csch(a) =~ 1.0 / sinh(a))
+doAssert(coth(a) =~ 1.0 / tanh(a))
+doAssert(arccosh(a) =~ complex(1.528570919480998, 1.14371774040242))
+doAssert(arcsinh(a) =~ complex(1.469351744368185, 1.06344002357775))
+doAssert(arctanh(a) =~ complex(0.173286795139986, 1.17809724509617))
+doAssert(arcsech(a) =~ arccosh(1.0/a))
+doAssert(arccsch(a) =~ arcsinh(1.0/a))
+doAssert(arccoth(a) =~ arctanh(1.0/a))
+
+doAssert(phase(a) == 1.1071487177940904)
+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)
+  a64: Complex32 = 2.0f*i64 + 1.0.float32
+  b64: Complex32 = complex(-1.0'f32, -2.0'f32)
+
+doAssert(a64 == a64)
+doAssert(a64 == -b64)
+doAssert(a64 + b64 =~ 0.0'f32)
+doAssert(not(pow(a64, b64) =~ a64))
+doAssert(pow(a64, 0.5f) =~ sqrt(a64))
+doAssert(pow(a64, 2) =~ complex(-3.0'f32, 4.0'f32))
+doAssert(sin(arcsin(b64)) =~ b64)
+doAssert(cosh(arccosh(a64)) =~ a64)
+
+doAssert(phase(a64) - 1.107149f < 1e-6)
+let t64 = polar(a64)
+doAssert(rect(t64.r, t64.phi) =~ a64)
+doAssert(rect(1.0f, 2.0f) =~ complex(-0.4161468f, 0.90929742f))
+doAssert(sizeof(a64) == 8)
+doAssert(sizeof(a) == 16)
+
+doAssert 123.0.im + 456.0 == complex64(456, 123)
+
+let localA = complex(0.1'f32)
+doAssert localA.im is float32
diff --git a/tests/stdlib/tcookies.nim b/tests/stdlib/tcookies.nim
new file mode 100644
index 000000000..3ff0f3bae
--- /dev/null
+++ b/tests/stdlib/tcookies.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+
+import std/[cookies, times, strtabs]
+import std/assertions
+
+let expire = fromUnix(0) + 1.seconds
+
+let theCookies = [
+  setCookie("test", "value", expire),
+  setCookie("test", "value", expire.local),
+  setCookie("test", "value", expire.utc)
+]
+let expected = "Set-Cookie: test=value; Expires=Thu, 01 Jan 1970 00:00:01 GMT"
+doAssert theCookies == [expected, expected, expected]
+
+let table = parseCookies("uid=1; kp=2")
+doAssert table["uid"] == "1"
+doAssert table["kp"] == "2"
diff --git a/tests/stdlib/tcritbits.nim b/tests/stdlib/tcritbits.nim
new file mode 100644
index 000000000..e6282f045
--- /dev/null
+++ b/tests/stdlib/tcritbits.nim
@@ -0,0 +1,89 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/[sequtils,critbits]
+import std/assertions
+
+template main =
+  var r: CritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+  r.incl "foo"
+
+  doAssert r.contains"def"
+
+  r.excl "def"
+  doAssert r.missingOrExcl("foo") == false
+  doAssert "foo" notin toSeq(r.items)
+
+  doAssert r.missingOrExcl("foo") == true
+
+  doAssert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
+
+  doAssert toSeq(r.itemsWithPrefix("de")) == @["definition"]
+  var c = CritBitTree[int]()
+
+  c.inc("a")
+  doAssert c["a"] == 1
+
+  c.inc("a", 4)
+  doAssert c["a"] == 5
+
+  c.inc("a", -5)
+  doAssert c["a"] == 0
+
+  c.inc("b", 2)
+  doAssert c["b"] == 2
+
+  c.inc("c", 3)
+  doAssert c["c"] == 3
+
+  c.inc("a", 1)
+  doAssert c["a"] == 1
+
+  var cf = CritBitTree[float]()
+
+  cf.incl("a", 1.0)
+  doAssert cf["a"] == 1.0
+
+  cf.incl("b", 2.0)
+  doAssert cf["b"] == 2.0
+
+  cf.incl("c", 3.0)
+  doAssert cf["c"] == 3.0
+
+  doAssert cf.len == 3
+  cf.excl("c")
+  doAssert cf.len == 2
+
+  var cb: CritBitTree[string]
+  cb.incl("help", "help")
+  for k in cb.keysWithPrefix("helpp"):
+    doAssert false, "there is no prefix helpp"
+
+  block: # bug #14339
+    var strings: CritBitTree[int]
+    discard strings.containsOrIncl("foo", 3)
+    doAssert strings["foo"] == 3
+
+  block tcritbitsToString:
+    block:
+      var t: CritBitTree[int]
+      t["a"] = 1
+      doAssert $t == """{"a": 1}"""
+    block:
+      var t: CritBitTree[string]
+      t["a"] = "1"
+      doAssert $t == """{"a": "1"}"""
+    block:
+      var t: CritBitTree[char]
+      t["a"] = '1'
+      doAssert $t == """{"a": '1'}"""
+
+main()
+static: main()
diff --git a/tests/stdlib/tcstring.nim b/tests/stdlib/tcstring.nim
new file mode 100644
index 000000000..d7fdd7738
--- /dev/null
+++ b/tests/stdlib/tcstring.nim
@@ -0,0 +1,93 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--gc:refc; --gc:arc"
+"""
+
+from std/sugar import collect
+from stdtest/testutils import whenRuntimeJs, whenVMorJs
+import std/assertions
+
+template testMitems() =
+  block:
+    var a = "abc"
+    var b = a.cstring
+    let s = collect:
+      for bi in mitems(b):
+        if bi == 'b': bi = 'B'
+        bi
+    whenRuntimeJs:
+      discard # xxx mitems should give CT error instead of @['\x00', '\x00', '\x00']
+    do:
+      doAssert s == @['a', 'B', 'c']
+
+  block:
+    var a = "abc\0def"
+    var b = a.cstring
+    let s = collect:
+      for bi in mitems(b):
+        if bi == 'b': bi = 'B'
+        bi
+    whenRuntimeJs:
+      discard # ditto
+    do:
+      doAssert s == @['a', 'B', 'c']
+
+proc mainProc() =
+  testMitems()
+
+template main() =
+  block: # bug #13859
+    let str = "abc".cstring
+    doAssert len(str).int8 == 3
+    doAssert len(str).int16 == 3
+    doAssert len(str).int32 == 3
+    var str2 = "cde".cstring
+    doAssert len(str2).int8 == 3
+    doAssert len(str2).int16 == 3
+    doAssert len(str2).int32 == 3
+
+    const str3 = "abc".cstring
+    doAssert len(str3).int32 == 3
+    doAssert len("abc".cstring).int16 == 3
+    doAssert len("abc".cstring).float32 == 3.0
+
+  block: # bug #17159
+    block:
+      var a = "abc"
+      var b = a.cstring
+      doAssert $(b, ) == """("abc",)"""
+      let s = collect:
+        for bi in b: bi
+      doAssert s == @['a', 'b', 'c']
+
+    block:
+      var a = "abc\0def"
+      var b = a.cstring
+      let s = collect:
+        for bi in b: bi
+      whenRuntimeJs:
+        doAssert $(b, ) == """("abc\x00def",)"""
+        doAssert s == @['a', 'b', 'c', '\x00', 'd', 'e', 'f']
+      do:
+        doAssert $(b, ) == """("abc",)"""
+        doAssert s == @['a', 'b', 'c']
+
+  block:
+    when defined(gcArc): # xxx SIGBUS
+      discard
+    else:
+      mainProc()
+    when false: # xxx bug vm: Error: unhandled exception: 'node' is not accessible using discriminant 'kind' of type 'TFullReg' [FieldDefect]
+      testMitems()
+
+  block: # bug #13321: [codegen] --gc:arc does not properly emit cstring, results in SIGSEGV
+    let a = "hello".cstring
+    doAssert $a == "hello"
+    doAssert $a[0] == "h"
+    doAssert $a[4] == "o"
+    whenVMorJs: discard # xxx this should work in vm, refs https://github.com/timotheecour/Nim/issues/619
+    do:
+      doAssert a[a.len] == '\0'
+
+static: main()
+main()
diff --git a/tests/stdlib/tcstrutils.nim b/tests/stdlib/tcstrutils.nim
new file mode 100644
index 000000000..e73b2b681
--- /dev/null
+++ b/tests/stdlib/tcstrutils.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/cstrutils
+import std/assertions
+
+proc main() =
+  let s = cstring "abcdef"
+  doAssert s.startsWith("a")
+  doAssert not s.startsWith("b")
+  doAssert s.endsWith("f")
+  doAssert not s.endsWith("a")
+  doAssert s.startsWith("")
+  doAssert s.endsWith("")
+
+  let a = cstring "abracadabra"
+  doAssert a.startsWith("abra")
+  doAssert not a.startsWith("bra")
+  doAssert a.endsWith("abra")
+  doAssert not a.endsWith("dab")
+  doAssert a.startsWith("")
+  doAssert a.endsWith("")
+
+  doAssert cmpIgnoreCase(cstring "FooBar", "foobar") == 0
+  doAssert cmpIgnoreCase(cstring "bar", "Foo") < 0
+  doAssert cmpIgnoreCase(cstring "Foo5", "foo4") > 0
+
+  doAssert cmpIgnoreStyle(cstring "foo_bar", "FooBar") == 0
+  doAssert cmpIgnoreStyle(cstring "foo_bar_5", "FooBar4") > 0
+
+  doAssert cmpIgnoreCase(cstring "", cstring "") == 0
+  doAssert cmpIgnoreCase(cstring "", cstring "Hello") < 0
+  doAssert cmpIgnoreCase(cstring "wind", cstring "") > 0
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tdb.nim b/tests/stdlib/tdb.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/stdlib/tdb.nim
diff --git a/tests/stdlib/tdb.nims b/tests/stdlib/tdb.nims
new file mode 100644
index 000000000..d31d0b26f
--- /dev/null
+++ b/tests/stdlib/tdb.nims
@@ -0,0 +1 @@
+--styleCheck:off
\ No newline at end of file
diff --git a/tests/stdlib/tdb_mysql.nim b/tests/stdlib/tdb_mysql.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/stdlib/tdb_mysql.nim
diff --git a/tests/stdlib/tdecls.nim b/tests/stdlib/tdecls.nim
new file mode 100644
index 000000000..42dc646f2
--- /dev/null
+++ b/tests/stdlib/tdecls.nim
@@ -0,0 +1,50 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+import std/assertions
+import std/decls
+
+template fun() =
+  var s = @[10,11,12]
+  var a {.byaddr.} = s[0]
+  a+=100
+  doAssert s == @[110,11,12]
+  doAssert a is int
+  var b {.byaddr.}: int = s[0]
+  doAssert a.addr == b.addr
+
+  {.push warningAsError[ImplicitTemplateRedefinition]: on.}
+  # in the future ImplicitTemplateRedefinition will be an error anyway
+  doAssert not compiles(block:
+    # redeclaration not allowed
+    var foo = 0
+    var foo {.byaddr.} = s[0])
+
+  doAssert not compiles(block:
+    # ditto
+    var foo {.byaddr.} = s[0]
+    var foo {.byaddr.} = s[0])
+  {.pop.}
+
+  block:
+    var b {.byaddr.} = s[1] # redeclaration ok in sub scope
+    b = 123
+
+  doAssert s == @[110,123,12]
+
+  b = b * 10
+  doAssert s == @[1100,123,12]
+
+  doAssert not compiles(block:
+    var b2 {.byaddr.}: float = s[2])
+
+  doAssert compiles(block:
+    var b2 {.byaddr.}: int = s[2])
+
+proc fun2() = fun()
+fun()
+fun2()
+static: fun2()
+when false: # pending bug #13887
+  static: fun()
diff --git a/tests/stdlib/tdecode_helpers.nim b/tests/stdlib/tdecode_helpers.nim
new file mode 100644
index 000000000..1c0735e05
--- /dev/null
+++ b/tests/stdlib/tdecode_helpers.nim
@@ -0,0 +1,27 @@
+import std/private/decode_helpers
+import std/assertions
+
+block:
+  var i = 0
+  let c = decodePercent("%t9", i)
+  doAssert (i, c) == (0, '%')
+
+block:
+  var i = 0
+  let c = decodePercent("19", i)
+  doAssert (i, c) == (0, '%')
+
+block:
+  var i = 0
+  let c = decodePercent("%19", i)
+  doAssert (i, c) == (2, '\x19')
+
+block:
+  var i = 0
+  let c = decodePercent("%A9", i)
+  doAssert (i, c) == (2, '\xA9')
+
+block:
+  var i = 0
+  let c = decodePercent("%Aa", i)
+  doAssert (i, c) == (2, '\xAA')
diff --git a/tests/stdlib/tdeques.nim b/tests/stdlib/tdeques.nim
new file mode 100644
index 000000000..39ff996d1
--- /dev/null
+++ b/tests/stdlib/tdeques.nim
@@ -0,0 +1,243 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/deques
+from std/sequtils import toSeq
+import std/assertions
+
+block:
+  proc index(self: Deque[int], idx: Natural): int =
+    self[idx]
+
+  proc main =
+    var testDeque = initDeque[int]()
+    testDeque.addFirst(1)
+    doAssert testDeque.index(0) == 1
+
+  main()
+
+block:
+  var d = initDeque[int]()
+  d.addLast(1)
+  doAssert $d == "[1]"
+block:
+  var d = initDeque[string]()
+  d.addLast("1")
+  doAssert $d == """["1"]"""
+block:
+  var d = initDeque[char]()
+  d.addLast('1')
+  doAssert $d == "['1']"
+
+block:
+  var deq = initDeque[int](1)
+  deq.addLast(4)
+  deq.addFirst(9)
+  deq.addFirst(123)
+  var first = deq.popFirst()
+  deq.addLast(56)
+  doAssert(deq.peekLast() == 56)
+  deq.addLast(6)
+  doAssert(deq.peekLast() == 6)
+  var second = deq.popFirst()
+  deq.addLast(789)
+  doAssert(deq.peekLast() == 789)
+
+  doAssert first == 123
+  doAssert second == 9
+  doAssert($deq == "[4, 56, 6, 789]")
+  doAssert deq == [4, 56, 6, 789].toDeque
+
+  doAssert deq[0] == deq.peekFirst and deq.peekFirst == 4
+  #doAssert deq[^1] == deq.peekLast and deq.peekLast == 789
+  deq[0] = 42
+  deq[deq.len - 1] = 7
+
+  doAssert 6 in deq and 789 notin deq
+  doAssert deq.find(6) >= 0
+  doAssert deq.find(789) < 0
+
+  block:
+    var d = initDeque[int](1)
+    d.addLast 7
+    d.addLast 8
+    d.addLast 10
+    d.addFirst 5
+    d.addFirst 2
+    d.addFirst 1
+    d.addLast 20
+    d.shrink(fromLast = 2)
+    doAssert($d == "[1, 2, 5, 7, 8]")
+    d.shrink(2, 1)
+    doAssert($d == "[5, 7]")
+    d.shrink(2, 2)
+    doAssert d.len == 0
+
+  for i in -2 .. 10:
+    if i in deq:
+      doAssert deq.contains(i) and deq.find(i) >= 0
+    else:
+      doAssert(not deq.contains(i) and deq.find(i) < 0)
+
+  when compileOption("boundChecks"):
+    try:
+      echo deq[99]
+      doAssert false
+    except IndexDefect:
+      discard
+
+    try:
+      doAssert deq.len == 4
+      for i in 0 ..< 5: deq.popFirst()
+      doAssert false
+    except IndexDefect:
+      discard
+
+  # grabs some types of resize error.
+  deq = initDeque[int]()
+  for i in 1 .. 4: deq.addLast i
+  deq.popFirst()
+  deq.popLast()
+  for i in 5 .. 8: deq.addFirst i
+  doAssert $deq == "[8, 7, 6, 5, 2, 3]"
+
+  # Similar to proc from the documentation example
+  proc foo(a, b: Positive) = # assume random positive values for `a` and `b`.
+    var deq = initDeque[int]()
+    doAssert deq.len == 0
+    for i in 1 .. a: deq.addLast i
+
+    if b < deq.len: # checking before indexed access.
+      doAssert deq[b] == b + 1
+
+    # The following two lines don't need any checking on access due to the logic
+    # of the program, but that would not be the case if `a` could be 0.
+    doAssert deq.peekFirst == 1
+    doAssert deq.peekLast == a
+
+    while deq.len > 0: # checking if the deque is empty
+      doAssert deq.popFirst() > 0
+
+  #foo(0,0)
+  foo(8, 5)
+  foo(10, 9)
+  foo(1, 1)
+  foo(2, 1)
+  foo(1, 5)
+  foo(3, 2)
+
+import std/sets
+
+block t13310:
+  proc main() =
+    var q = initDeque[HashSet[int16]](2)
+    q.addFirst([1'i16].toHashSet)
+    q.addFirst([2'i16].toHashSet)
+    q.addFirst([3'i16].toHashSet)
+    doAssert $q == "[{3}, {2}, {1}]"
+
+  static:
+    main()
+
+
+proc main() =
+  block:
+    let a = [10, 20, 30].toDeque
+    doAssert toSeq(a.pairs) == @[(0, 10), (1, 20), (2, 30)]
+
+  block:
+    let q = [7, 9].toDeque
+    doAssert 7 in q
+    doAssert q.contains(7)
+    doAssert 8 notin q
+
+  block:
+    let a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.peekFirst == 10
+    doAssert len(a) == 5
+
+  block:
+    let a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.peekLast == 50
+    doAssert len(a) == 5
+
+  block:
+    var a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.popFirst == 10
+    doAssert $a == "[20, 30, 40, 50]"
+
+  block:
+    var a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    doAssert a.popLast == 50
+    doAssert $a == "[10, 20, 30, 40]"
+
+  block:
+    var a = [10, 20, 30, 40, 50].toDeque
+    doAssert $a == "[10, 20, 30, 40, 50]"
+    clear(a)
+    doAssert len(a) == 0
+
+  block: # bug #21278
+    var a = [10, 20, 30, 40].toDeque
+
+    a.shrink(fromFirst = 0, fromLast = 1)
+    doAssert $a == "[10, 20, 30]"
+
+  block:
+    var a, b: Deque[int]
+    for i in 1 .. 256:
+      a.addLast(i)
+    for i in 1 .. 255:
+      a.popLast
+    b.addLast(1)
+    doAssert a == b
+
+  block:
+    # Issue 23275
+    # Test `==`.
+    block:
+      var a, b = initDeque[int]()
+      doAssert a == b
+      doAssert a.hash == b.hash
+      a.addFirst(1)
+      doAssert a != b
+      doAssert a.hash != b.hash
+      b.addLast(1)
+      doAssert a == b
+      doAssert a.hash == b.hash
+      a.popFirst
+      b.popLast
+      doAssert a == b
+      doAssert a.hash == b.hash
+      a.addLast 2
+      doAssert a != b
+      doAssert a.hash != b.hash
+      b.addFirst 2
+      doAssert a == b
+      doAssert a.hash == b.hash
+
+    block:
+      var a, b = initDeque[int]()
+      for i in countDown(100, 1):
+        a.addFirst(i)
+      for i in 1..100:
+        b.addLast(i)
+      doAssert a == b
+      for i in 1..99:
+        a.popLast
+      let a1 = [1].toDeque
+      doAssert a == a1
+      doAssert a.hash == a1.hash
+      var c = initDeque[int]()
+      c.addLast(1)
+      doAssert a == c
+      doAssert a.hash == c.hash
+
+static: main()
+main()
diff --git a/tests/stdlib/tdiff.nim b/tests/stdlib/tdiff.nim
new file mode 100644
index 000000000..132f7120b
--- /dev/null
+++ b/tests/stdlib/tdiff.nim
@@ -0,0 +1,75 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import experimental/diff
+import std/strutils
+import std/assertions
+
+proc testHelper(f: seq[Item]): string =
+  for it in f:
+    result.add(
+      $it.deletedA & "." & $it.insertedB & "." & $it.startA & "." & $it.startB & "*"
+    )
+
+proc main() =
+  var a, b: string
+
+  # Diff Self Test
+  # test all changes
+  a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n')
+  b = "0,1,2,3,4,5,6,7,8,9".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "12.10.0.0*",
+    "all-changes test failed.")
+  # test all same
+  a = "a,b,c,d,e,f,g,h,i,j,k,l".replace(',', '\n')
+  b = a
+  doAssert(testHelper(diffText(a, b)) ==
+    "",
+    "all-same test failed.")
+
+  # test snake
+  a = "a,b,c,d,e,f".replace(',', '\n')
+  b = "b,c,d,e,f,x".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "1.0.0.0*0.1.6.5*",
+    "snake test failed.")
+
+  # 2002.09.20 - repro
+  a = "c1,a,c2,b,c,d,e,g,h,i,j,c3,k,l".replace(',', '\n')
+  b = "C1,a,C2,b,c,d,e,I1,e,g,h,i,j,C3,k,I2,l".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "1.1.0.0*1.1.2.2*0.2.7.7*1.1.11.13*0.1.13.15*",
+    "repro20020920 test failed.")
+
+  # 2003.02.07 - repro
+  a = "F".replace(',', '\n')
+  b = "0,F,1,2,3,4,5,6,7".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "0.1.0.0*0.7.1.2*",
+    "repro20030207 test failed.")
+
+  # Muegel - repro
+  a = "HELLO\nWORLD"
+  b = "\n\nhello\n\n\n\nworld\n"
+  doAssert(testHelper(diffText(a, b)) ==
+    "2.8.0.0*",
+    "repro20030409 test failed.")
+
+  # test some differences
+  a = "a,b,-,c,d,e,f,f".replace(',', '\n')
+  b = "a,b,x,c,e,f".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "1.1.2.2*1.0.4.4*1.0.7.6*",
+    "some-changes test failed.")
+
+  # test one change within long chain of repeats
+  a = "a,a,a,a,a,a,a,a,a,a".replace(',', '\n')
+  b = "a,a,a,a,-,a,a,a,a,a".replace(',', '\n')
+  doAssert(testHelper(diffText(a, b)) ==
+    "0.1.4.4*1.0.9.10*",
+    "long chain of repeats test failed.")
+main()
+static: main()
diff --git a/tests/stdlib/tdistros_detect.nim b/tests/stdlib/tdistros_detect.nim
new file mode 100644
index 000000000..1176c8993
--- /dev/null
+++ b/tests/stdlib/tdistros_detect.nim
@@ -0,0 +1,16 @@
+import std/[assertions, distros]
+
+when defined(windows):
+    doAssert detectOs(Windows) == true
+    doAssert detectOs(Linux) == false
+    doAssert detectOs(MacOSX) == false
+
+when defined(linux):
+    doAssert detectOs(Linux) == true
+    doAssert detectOs(Windows) == false
+    doAssert detectOs(MacOSX) == false
+
+when defined(macosx):
+    doAssert detectOs(MacOSX) == true
+    doAssert detectOs(Windows) == false
+    doAssert detectOs(Linux) == false
diff --git a/tests/stdlib/tdochelpers.nim b/tests/stdlib/tdochelpers.nim
new file mode 100644
index 000000000..4d532b5d0
--- /dev/null
+++ b/tests/stdlib/tdochelpers.nim
@@ -0,0 +1,221 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+
+[Suite] Integration with Nim
+'''
+"""
+
+# tests for dochelpers.nim module
+
+import ../../lib/packages/docutils/[rstast, rst, dochelpers]
+import unittest
+import std/assertions
+
+proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
+                    arg: string) =
+  doAssert msgkind == mwBrokenLink
+
+proc fromRst(text: string): LangSymbol =
+  let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
+                   {roNimFile},
+                   msgHandler=testMsgHandler)
+  assert r.node.kind == rnRstRef
+  result = toLangSymbol(r.node)
+
+proc fromMd(text: string): LangSymbol =
+  let r = rstParse(text, "-input-", LineRstInit, ColRstInit,
+                   {roPreferMarkdown, roSupportMarkdown, roNimFile},
+                   msgHandler=testMsgHandler)
+  assert r.node.kind == rnPandocRef
+  assert r.node.len == 2
+  # this son is the target:
+  assert r.node.sons[1].kind == rnInner
+  result = toLangSymbol(r.node.sons[1])
+
+suite "Integration with Nim":
+  test "simple symbol parsing (shortest form)":
+    let expected = LangSymbol(symKind: "", name: "g")
+    check "g_".fromRst == expected
+    check "[g]".fromMd == expected
+    # test also alternative syntax variants of Pandoc Markdown:
+    check "[g][]".fromMd == expected
+    check "[this symbol][g]".fromMd == expected
+
+  test "simple symbol parsing (group of words)":
+    #let input1 = "`Y`_".rstParseTest
+    let expected1 = LangSymbol(symKind: "", name: "Y")
+    check "`Y`_".fromRst == expected1
+    check "[Y]".fromMd == expected1
+
+    # this means not a statement 'type', it's a backticked identifier `type`:
+    let expected2 = LangSymbol(symKind: "", name: "type")
+    check "`type`_".fromRst == expected2
+    check "[type]".fromMd == expected2
+
+    let expected3 = LangSymbol(symKind: "", name: "[]")
+    check "`[]`_".fromRst == expected3
+    # Markdown syntax for this case is NOT [[]]
+    check "[`[]`]".fromMd == expected3
+
+    let expected4 = LangSymbol(symKind: "", name: "Xyz")
+    check "`X Y Z`_".fromRst == expected4
+    check "[X Y Z]".fromMd == expected4
+
+  test "simple proc parsing":
+    let expected = LangSymbol(symKind: "proc", name: "f")
+    check "`proc f`_".fromRst == expected
+    check "[proc f]".fromMd == expected
+
+  test "another backticked name":
+    let expected = LangSymbol(symKind: "template", name: "type")
+    check """`template \`type\``_""".fromRst == expected
+    # no backslash in Markdown:
+    check """[template `type`]""".fromMd == expected
+
+  test "simple proc parsing with parameters":
+    let expected = LangSymbol(symKind: "proc", name: "f",
+                              parametersProvided: true)
+    check "`proc f*()`_".fromRst == expected
+    check "`proc f()`_".fromRst == expected
+    check "[proc f*()]".fromMd == expected
+    check "[proc f()]".fromMd == expected
+
+  test "symbol parsing with 1 parameter":
+    let expected = LangSymbol(symKind: "", name: "f",
+                              parameters: @[("G[int]", "")],
+                              parametersProvided: true)
+    check "`f(G[int])`_".fromRst == expected
+    check "[f(G[int])]".fromMd == expected
+
+  test "more proc parsing":
+    let input1 = "`proc f[T](x:G[T]):M[T]`_".fromRst
+    let input2 = "`proc f[ T ] ( x: G [T] ): M[T]`_".fromRst
+    let input3 = "`proc f*[T](x: G[T]): M[T]`_".fromRst
+    let expected = LangSymbol(symKind: "proc",
+                              name: "f",
+                              generics: "[T]",
+                              parameters: @[("x", "G[T]")],
+                              parametersProvided: true,
+                              outType: "M[T]")
+    check(input1 == expected)
+    check(input2 == expected)
+    check(input3 == expected)
+
+  test "advanced proc parsing with Nim identifier normalization":
+    let inputRst = """`proc binarySearch*[T, K](a: openarray[T]; key: K;
+                       cmp: proc (x: T; y: K): int)`_"""
+    let inputMd = """[proc binarySearch*[T, K](a: openarray[T]; key: K;
+                       cmp: proc (x: T; y: K): int)]"""
+    let expected = LangSymbol(symKind: "proc",
+                              name: "binarysearch",
+                              generics: "[T,K]",
+                              parameters: @[
+                                ("a", "openarray[T]"),
+                                ("key", "K"),
+                                ("cmp", "proc(x:T;y:K):int")],
+                              parametersProvided: true,
+                              outType: "")
+    check(inputRst.fromRst == expected)
+    check(inputMd.fromMd == expected)
+
+  test "the same without proc":
+    let input = """`binarySearch*[T, K](a: openarray[T]; key: K;
+                    cmp: proc (x: T; y: K): int {.closure.})`_"""
+    let expected = LangSymbol(symKind: "",
+                              name: "binarysearch",
+                              generics: "[T,K]",
+                              parameters: @[
+                                ("a", "openarray[T]"),
+                                ("key", "K"),
+                                ("cmp", "proc(x:T;y:K):int")],
+                              parametersProvided: true,
+                              outType: "")
+    check(input.fromRst == expected)
+    let inputMd = """[binarySearch*[T, K](a: openarray[T]; key: K;
+                      cmp: proc (x: T; y: K): int {.closure.})]"""
+    check(inputMd.fromMd == expected)
+
+  test "operator $ with and without backticks":
+    let input1 = """`func \`$\`*[T](a: \`open Array\`[T]): string`_"""
+    let input1md = "[func `$`*[T](a: `open Array`[T]): string]"
+    let input2 = """`func $*[T](a: \`open Array\`[T]): string`_"""
+    let input2md = "[func $*[T](a: `open Array`[T]): string]"
+    let expected = LangSymbol(symKind: "func",
+                              name: "$",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]")],
+                              parametersProvided: true,
+                              outType: "string")
+    check input1.fromRst == expected
+    check input2.fromRst == expected
+    check input1md.fromMd == expected
+    check input2md.fromMd == expected
+
+  test "operator [] with and without backticks":
+    let input1 = """`func \`[]\`[T](a: \`open Array\`[T], idx: int): T`_"""
+    let input1md = "[func `[]`[T](a: `open Array`[T], idx: int): T]"
+    let input2 = """`func [][T](a: \`open Array\`[T], idx: int): T`_"""
+    let input2md = "[func [][T](a: `open Array`[T], idx: int): T]"
+    let expected = LangSymbol(symKind: "func",
+                              name: "[]",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]"),
+                                            ("idx", "int")],
+                              parametersProvided: true,
+                              outType: "T")
+    check input1.fromRst == expected
+    check input2.fromRst == expected
+    check input1md.fromMd == expected
+    check input2md.fromMd == expected
+
+  test "postfix symbol specifier #1":
+    let input = "`walkDir iterator`_"
+    let inputMd = "[walkDir iterator]"
+    let expected = LangSymbol(symKind: "iterator",
+                              name: "walkdir")
+    check input.fromRst == expected
+    check inputMd.fromMd == expected
+
+  test "postfix symbol specifier #2":
+    let input1 = """`\`[]\`[T](a: \`open Array\`[T], idx: int): T func`_"""
+    let input1md = "[`[]`[T](a: `open Array`[T], idx: int): T func]"
+    let input2 = """`[][T](a: \`open Array\`[T], idx: int): T func`_"""
+    # note again that ` is needed between 1st and second [
+    let input2md = "[`[]`[T](a: `open Array`[T], idx: int): T func]"
+    let expected = LangSymbol(symKind: "func",
+                              name: "[]",
+                              generics: "[T]",
+                              parameters: @[("a", "openarray[T]"),
+                                            ("idx", "int")],
+                              parametersProvided: true,
+                              outType: "T")
+    check input1.fromRst == expected
+    check input2.fromRst == expected
+    check input1md.fromMd == expected
+    check input2md.fromMd == expected
+
+  test "type of type":
+    let inputRst = "`CopyFlag enum`_"
+    let inputMd = "[CopyFlag enum]"
+    let expected = LangSymbol(symKind: "type",
+                              symTypeKind: "enum",
+                              name: "Copyflag")
+    check inputRst.fromRst == expected
+    check inputMd.fromMd == expected
+
+  test "prefixed module":
+    let inputRst = "`module std / paths`_"
+    let inputMd = "[module std / paths]"
+    let expected = LangSymbol(symKind: "module",
+                              name: "std/paths")
+    check inputRst.fromRst == expected
+    check inputMd.fromMd == expected
+
+  test "postfixed module":
+    let inputRst = "`std / paths module`_"
+    let inputMd = "[std / paths module]"
+    let expected = LangSymbol(symKind: "module",
+                              name: "std/paths")
+    check inputRst.fromRst == expected
+    check inputMd.fromMd == expected
diff --git a/tests/stdlib/teditdistance.nim b/tests/stdlib/teditdistance.nim
new file mode 100644
index 000000000..14ba6df97
--- /dev/null
+++ b/tests/stdlib/teditdistance.nim
@@ -0,0 +1,45 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/editdistance
+import std/assertions
+
+doAssert editDistance("", "") == 0
+doAssert editDistance("kitten", "sitting") == 3 # from Wikipedia
+doAssert editDistance("flaw", "lawn") == 2 # from Wikipedia
+
+doAssert editDistance("привет", "превет") == 1
+doAssert editDistance("Ã…ge", "Age") == 1
+# editDistance, one string is longer in bytes, but shorter in rune length
+# first string: 4 bytes, second: 6 bytes, but only 3 runes
+doAssert editDistance("aaaa", "×××") == 4
+
+block veryLongStringEditDistanceTest:
+  const cap = 256
+  var
+    s1 = newStringOfCap(cap)
+    s2 = newStringOfCap(cap)
+  while len(s1) < cap:
+    s1.add 'a'
+  while len(s2) < cap:
+    s2.add 'b'
+  doAssert editDistance(s1, s2) == cap
+
+block combiningCodePointsEditDistanceTest:
+  const s = "A\xCC\x8Age"
+  doAssert editDistance(s, "Age") == 1
+
+doAssert editDistanceAscii("", "") == 0
+doAssert editDistanceAscii("kitten", "sitting") == 3 # from Wikipedia
+doAssert editDistanceAscii("flaw", "lawn") == 2 # from Wikipedia
+
+
+doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)
+doAssert(editDistance("prefix__hallo_suffix", "prefix") == 14)
+doAssert(editDistance("prefix__hallo_suffix", "suffix") == 14)
+doAssert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)
+doAssert(editDistance("main", "malign") == 2)
\ No newline at end of file
diff --git a/tests/stdlib/tencodings.nim b/tests/stdlib/tencodings.nim
new file mode 100644
index 000000000..2f4daaba3
--- /dev/null
+++ b/tests/stdlib/tencodings.nim
@@ -0,0 +1,107 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/encodings
+import std/assertions
+
+var fromGBK = open("utf-8", "gbk")
+var toGBK = open("gbk", "utf-8")
+
+var fromGB2312 = open("utf-8", "gb2312")
+var toGB2312 = open("gb2312", "utf-8")
+
+
+block:
+  let data = "\215\237\186\243\178\187\214\170\204\236\212\218\203\174\163\172\194\250\180\178\208\199\195\206\209\185\208\199\186\211"
+  doAssert fromGBK.convert(data) == "醉åŽä¸çŸ¥å¤©åœ¨æ°´ï¼Œæ»¡åºŠæ˜Ÿæ¢¦åŽ‹æ˜Ÿæ²³"
+
+block:
+  let data = "万两黄金容易得,知心一个也难求"
+  doAssert toGBK.convert(data) == "\205\242\193\189\187\198\189\240\200\221\210\215\181\195\163\172\214\170\208\196\210\187\184\246\210\178\196\209\199\243"
+
+
+block:
+  let data = "\215\212\208\197\200\203\201\250\182\254\176\217\196\234\163\172\187\225\181\177\203\174\187\247\200\253\199\167\192\239"
+  doAssert fromGB2312.convert(data) == "自信人生二百年,会当水击三åƒé‡Œ"
+
+block:
+  let data = "è°æ€•?一蓑烟雨任平生"
+  doAssert toGB2312.convert(data) == "\203\173\197\194\163\191\210\187\203\242\209\204\211\234\200\206\198\189\201\250"
+
+
+when defined(windows):
+  block should_throw_on_unsupported_conversions:
+    let original = "some string"
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-8", "utf-32")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-8", "unicodeFFFE")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-8", "utf-32BE")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "unicodeFFFE", "utf-8")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-32", "utf-8")
+
+    doAssertRaises(EncodingError):
+      discard convert(original, "utf-32BE", "utf-8")
+
+  block should_convert_from_utf16_to_utf8:
+    let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "теÑÑ‚"
+    let result = convert(original, "utf-8", "utf-16")
+    doAssert(result == "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82")
+
+  block should_convert_from_utf16_to_win1251:
+    let original = "\x42\x04\x35\x04\x41\x04\x42\x04" # utf-16 little endian test string "теÑÑ‚"
+    let result = convert(original, "windows-1251", "utf-16")
+    doAssert(result == "\xf2\xe5\xf1\xf2")
+
+  block should_convert_from_win1251_to_koi8r:
+    let original = "\xf2\xe5\xf1\xf2" # win1251 test string "теÑÑ‚"
+    let result = convert(original, "koi8-r", "windows-1251")
+    doAssert(result == "\xd4\xc5\xd3\xd4")
+
+  block should_convert_from_koi8r_to_win1251:
+    let original = "\xd4\xc5\xd3\xd4" # koi8r test string "теÑÑ‚"
+    let result = convert(original, "windows-1251", "koi8-r")
+    doAssert(result == "\xf2\xe5\xf1\xf2")
+
+  block should_convert_from_utf8_to_win1251:
+    let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "теÑÑ‚"
+    let result = convert(original, "windows-1251", "utf-8")
+    doAssert(result == "\xf2\xe5\xf1\xf2")
+
+  block should_convert_from_utf8_to_utf16:
+    let original = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82" # utf-8 test string "теÑÑ‚"
+    let result = convert(original, "utf-16", "utf-8")
+    doAssert(result == "\x42\x04\x35\x04\x41\x04\x42\x04")
+
+  block should_handle_empty_string_for_any_conversion:
+    let original = ""
+    var result = convert(original, "utf-16", "utf-8")
+    doAssert(result == "")
+    result = convert(original, "utf-8", "utf-16")
+    doAssert(result == "")
+    result = convert(original, "windows-1251", "koi8-r")
+    doAssert(result == "")
+
+
+block:
+  let
+    orig = "öäüß"
+    cp1252 = convert(orig, "CP1252", "UTF-8")
+    ibm850 = convert(cp1252, "ibm850", "CP1252")
+    current = getCurrentEncoding()
+  doAssert orig == "\195\182\195\164\195\188\195\159"
+  doAssert ibm850 == "\148\132\129\225"
+  doAssert convert(ibm850, current, "ibm850") == orig
+
+block: # fixes about #23481
+  doAssertRaises EncodingError:
+    discard open(destEncoding="this is a invalid enc")
diff --git a/tests/stdlib/tenumerate.nim b/tests/stdlib/tenumerate.nim
new file mode 100644
index 000000000..2789ebe3a
--- /dev/null
+++ b/tests/stdlib/tenumerate.nim
@@ -0,0 +1,24 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/enumerate
+import std/assertions
+
+let a = @[1, 3, 5, 7]
+
+block:
+  var res: seq[(int, int)]
+  for i, x in enumerate(a):
+    res.add (i, x)
+  doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+block:
+  var res: seq[(int, int)]
+  for (i, x) in enumerate(a.items):
+    res.add (i, x)
+  doAssert res == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+block:
+  var res: seq[(int, int)]
+  for i, x in enumerate(3, a):
+    res.add (i, x)
+  doAssert res == @[(3, 1), (4, 3), (5, 5), (6, 7)]
diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim
new file mode 100644
index 000000000..2662a660d
--- /dev/null
+++ b/tests/stdlib/tenumutils.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/enumutils
+from std/sequtils import toSeq
+import std/assertions
+
+template main =
+  block: # items
+    type A = enum a0 = 2, a1 = 4, a2
+    type B[T] = enum b0 = 2, b1 = 4
+    doAssert A.toSeq == [a0, a1, a2]
+    doAssert B[float].toSeq == [B[float].b0, B[float].b1]
+
+  block: # symbolName
+    block:
+      type A2 = enum a20, a21, a22
+      doAssert $a21 == "a21"
+      doAssert a21.symbolName == "a21"
+      proc `$`(a: A2): string = "foo"
+      doAssert $a21 == "foo"
+      doAssert a21.symbolName == "a21"
+      var a = a22
+      doAssert $a == "foo"
+      doAssert a.symbolName == "a22"
+
+    type B = enum
+      b0 = (10, "kb0")
+      b1 = "kb1"
+      b2
+    let b = B.low
+    doAssert b.symbolName == "b0"
+    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/tenvvars.nim b/tests/stdlib/tenvvars.nim
new file mode 100644
index 000000000..1a07f02b8
--- /dev/null
+++ b/tests/stdlib/tenvvars.nim
@@ -0,0 +1,162 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  targets: "c js cpp"
+"""
+
+import std/envvars
+from std/sequtils import toSeq
+import stdtest/testutils
+import std/[assertions]
+
+when not defined(js):
+  import std/typedthreads
+
+# "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386)
+const unicodeUtf8 = "\xc3\x86"
+
+template main =
+  block: # delEnv, existsEnv, getEnv, envPairs
+    for val in ["val", "", unicodeUtf8]: # ensures empty val works too
+      const key = "NIM_TESTS_TOSENV_KEY"
+      doAssert not existsEnv(key)
+
+      putEnv(key, "tempval")
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == "tempval"
+
+      putEnv(key, val) # change a key that already exists
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == val
+
+      doAssert (key, val) in toSeq(envPairs())
+      delEnv(key)
+      doAssert (key, val) notin toSeq(envPairs())
+      doAssert not existsEnv(key)
+      delEnv(key) # deleting an already deleted env var
+      doAssert not existsEnv(key)
+
+    block:
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == ""
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " "
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval"
+
+    whenVMorJs: discard # xxx improve
+    do:
+      doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE"))
+      doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE"))
+      doAssert not existsEnv("")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
+
+static: main()
+main()
+
+when defined(windows):
+  import std/widestrs
+  proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "<stdlib.h>".}
+proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
+
+when not defined(js) and not defined(nimscript):
+  block: # bug #18533
+    var thr: Thread[void]
+    proc threadFunc {.thread.} = putEnv("foo", "fooVal2")
+
+    putEnv("foo", "fooVal1")
+    doAssert getEnv("foo") == "fooVal1"
+    createThread(thr, threadFunc)
+    joinThreads(thr)
+    when defined(windows):
+      doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString)
+    else:
+      doAssert getEnv("foo") == $c_getenv("foo".cstring)
+
+    doAssertRaises(OSError): delEnv("foo=bar")
+
+when defined(windows) and not defined(nimscript):
+  import std/encodings
+
+  proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
+  proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "<stdlib.h>".}
+
+  block: # Bug #20083
+    # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode
+    # characters correctly. This means that module X in the process calling the
+    # CRT environment variable API will get the correct string. Raw CRT API
+    # calls below represent module X.
+
+    # Getting an env. var. with unicode characters returns the correct UTF-8
+    # encoded string.
+    block:
+      const envName = "twin_envvars1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Putting an env. var. with unicode characters gives the correct UTF-16
+    # encoded string from low-level routine.
+    block:
+      const envName = "twin_envvars2"
+      putEnv(envName, unicodeUtf8)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters is retrieved correctly
+    block:
+      const envName = unicodeUtf8 & "1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Env. name containing Unicode characters is set correctly
+    block:
+      const envName = unicodeUtf8 & "2"
+      putEnv(envName, unicodeUtf8)
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters and empty value is set correctly
+    block:
+      const envName = unicodeUtf8 & "3"
+      putEnv(envName, "")
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == ""
+
+    # It's hard to test on Windows code pages, because there is no "change
+    # a process' locale" API.
+    if getCurrentEncoding(true) == "windows-1252":
+      const
+        unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding
+
+      # Test that env. var. ANSI API has correct encoding
+      block:
+        const
+          envName = unicodeUtf8 & "4"
+          envNameAnsi = unicodeAnsi & "4"
+        putEnv(envName, unicodeUtf8)
+        doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi
+
+      block:
+        const
+          envName = unicodeUtf8 & "5"
+          envNameAnsi = unicodeAnsi & "5"
+        doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0
+        doAssert getEnv(envName) == unicodeUtf8
+
+      # Env. name containing Unicode characters and empty value is set correctly;
+      # and, if env. name. characters cannot be represented in codepage, don't
+      # raise an error.
+      #
+      # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The
+      # windows-1250 locale has no representation of `abreveUtf8` below, so the
+      # conversion will fail, but this must not be fatal. It is expected that the
+      # routine ignores updating MBCS environment (`environ` global) and carries
+      # on.
+      block:
+        const
+          # "LATIN SMALL LETTER A WITH BREVE" in UTF-8
+          abreveUtf8 = "\xc4\x83"
+          envName = abreveUtf8 & "6"
+        putEnv(envName, "")
+        doAssert existsEnv(envName)
+        doAssert $c_wgetenv(envName.newWideCString) == ""
+        doAssert getEnv(envName) == ""
diff --git a/tests/stdlib/texitprocs.nim b/tests/stdlib/texitprocs.nim
new file mode 100644
index 000000000..ea29d8f58
--- /dev/null
+++ b/tests/stdlib/texitprocs.nim
@@ -0,0 +1,22 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+targets: "c cpp js"
+output: '''
+ok4
+ok3
+ok2
+ok1
+'''
+"""
+
+import std/exitprocs
+
+proc fun1() {.noconv.} = echo "ok1"
+proc fun2() = echo "ok2"
+proc fun3() {.noconv.} = echo "ok3"
+proc fun4() = echo "ok4"
+
+addExitProc(fun1)
+addExitProc(fun2)
+addExitProc(fun3)
+addExitProc(fun4)
diff --git a/tests/stdlib/tfdleak.nim b/tests/stdlib/tfdleak.nim
new file mode 100644
index 000000000..272a7507c
--- /dev/null
+++ b/tests/stdlib/tfdleak.nim
@@ -0,0 +1,152 @@
+discard """
+  exitcode: 0
+  output: ""
+  matrix: "; -d:nimInheritHandles; --mm:refc"
+  joinable: false
+"""
+
+import os, osproc, strutils, nativesockets, net, selectors, memfiles,
+       asyncdispatch, asyncnet
+
+import std/[assertions, syncio]
+
+when defined(windows):
+  import winlean
+
+  # Note: Windows 10-only API
+  proc compareObjectHandles(first, second: Handle): WINBOOL
+                           {.stdcall, dynlib: "kernelbase",
+                             importc: "CompareObjectHandles".}
+else:
+  import posix
+
+proc leakCheck(f: AsyncFD | int | FileHandle | SocketHandle, msg: string,
+               expectLeak = defined(nimInheritHandles)) =
+  var args = @[$f.int, msg, $expectLeak]
+
+  when defined(windows):
+    var refFd: Handle
+    # NOTE: This function shouldn't be used to duplicate sockets,
+    #       as this function may mess with the socket internal refcounting.
+    #       but due to the lack of type segmentation in the stdlib for
+    #       Windows (AsyncFD can be a file or a socket), we will have to
+    #       settle with this.
+    #
+    #       Now, as a poor solution for the refcounting problem, we just
+    #       simply let the duplicated handle leak. This should not interfere
+    #       with the test since new handles can't occupy the slot held by
+    #       the leaked ones.
+    if duplicateHandle(getCurrentProcess(), f.Handle,
+                       getCurrentProcess(), addr refFd,
+                       0, 1, DUPLICATE_SAME_ACCESS) == 0:
+      raiseOSError osLastError(), "Couldn't create the reference handle"
+    args.add $refFd
+
+  discard startProcess(
+    getAppFilename(),
+    args = args,
+    options = {poParentStreams}
+  ).waitForExit
+
+proc isValidHandle(f: int): bool =
+  ## Check if a handle is valid. Requires OS-native handles.
+  when defined(windows):
+    var flags: DWORD
+    result = getHandleInformation(f.Handle, addr flags) != 0
+  else:
+    result = fcntl(f.cint, F_GETFD) != -1
+
+proc main() =
+  if paramCount() == 0:
+    # Parent process
+    let f = syncio.open("__test_fdleak", fmReadWrite)
+    defer: close f
+
+    leakCheck(f.getOsFileHandle, "system.open()")
+
+    doAssert f.reopen("__test_fdleak2", fmReadWrite), "reopen failed"
+
+    leakCheck(f.getOsFileHandle, "reopen")
+
+    let sock = createNativeSocket()
+    defer: close sock
+    leakCheck(sock, "createNativeSocket()")
+    if sock.setInheritable(not defined(nimInheritHandles)):
+      leakCheck(sock, "createNativeSocket()", not defined(nimInheritHandles))
+    else:
+      raiseOSError osLastError()
+
+    let server = newSocket()
+    defer: close server
+    server.bindAddr(address = "127.0.0.1")
+    server.listen()
+    let (_, port) = server.getLocalAddr
+
+    leakCheck(server.getFd, "newSocket()")
+
+    let client = newSocket()
+    defer: close client
+    client.connect("127.0.0.1", port)
+
+    var input: Socket
+    server.accept(input)
+
+    leakCheck(input.getFd, "accept()")
+
+    # ioselectors_select doesn't support returning a handle.
+    when not defined(windows):
+      let selector = newSelector[int]()
+      leakCheck(selector.getFd, "selector()", false)
+
+    var mf = memfiles.open("__test_fdleak3", fmReadWrite, newFileSize = 1)
+    defer: close mf
+    when defined(windows):
+      leakCheck(mf.mapHandle, "memfiles.open().mapHandle", false)
+    else:
+      leakCheck(mf.handle, "memfiles.open().handle", false)
+
+    let sockAsync = createAsyncNativeSocket()
+    defer: closeSocket sockAsync
+    leakCheck(sockAsync, "createAsyncNativeSocket()")
+    if sockAsync.setInheritable(not defined(nimInheritHandles)):
+      leakCheck(sockAsync, "createAsyncNativeSocket()", not defined(nimInheritHandles))
+    else:
+      raiseOSError osLastError()
+
+    let serverAsync = newAsyncSocket()
+    defer: close serverAsync
+    serverAsync.bindAddr(address = "127.0.0.1")
+    serverAsync.listen()
+    let (_, portAsync) = serverAsync.getLocalAddr
+
+    leakCheck(serverAsync.getFd, "newAsyncSocket()")
+
+    let clientAsync = newAsyncSocket()
+    defer: close clientAsync
+    waitFor clientAsync.connect("127.0.0.1", portAsync)
+
+    let inputAsync = waitFor serverAsync.accept()
+
+    leakCheck(inputAsync.getFd, "accept() async")
+  else:
+    let
+      fd = parseInt(paramStr 1)
+      expectLeak = parseBool(paramStr 3)
+      msg = (if expectLeak: "not " else: "") & "leaked " & paramStr 2
+    let validHandle =
+      when defined(windows):
+        # On Windows, due to the use of winlean, causes the program to open
+        # a handle to the various dlls that's loaded. This handle might
+        # collide with the handle sent for testing.
+        #
+        # As a walkaround, we pass an another handle that's purposefully leaked
+        # as a reference so that we can verify whether the "leaked" handle
+        # is the right one.
+        let refFd = parseInt(paramStr 4)
+        fd.isValidHandle and compareObjectHandles(fd, refFd) != 0
+      else:
+        fd.isValidHandle
+    if expectLeak xor validHandle:
+      echo msg
+
+when isMainModule: main()
diff --git a/tests/stdlib/tfdleak_multiple.nim b/tests/stdlib/tfdleak_multiple.nim
new file mode 100644
index 000000000..c26681217
--- /dev/null
+++ b/tests/stdlib/tfdleak_multiple.nim
@@ -0,0 +1,31 @@
+discard """
+joinable: false
+"""
+
+import os, osproc, strutils
+import std/assertions
+
+const Iterations = 200
+
+proc testFdLeak() =
+  var count = 0
+  let
+    test = getAppDir() / "tfdleak"
+    exe = test.addFileExt(ExeExt).quoteShell
+    options = ["", "-d:nimInheritHandles"]
+  for opt in options:
+    let
+      run = "nim c $1 $2" % [opt, quoteShell test]
+      (output, status) = execCmdEx run
+    doAssert status == 0, "Test complination failed:\n$1\n$2" % [run, output]
+    for i in 1..Iterations:
+      let (output, status) = execCmdEx exe
+      doAssert status == 0, "Execution of " & exe & " failed"
+      if "leaked" in output:
+        count.inc
+    doAssert count == 0, "Leaked " & $count & " times"
+
+when defined(windows):
+  # tfdleak was only flaky for windows (and for netbsd, there is still a bug)
+  # note that this test is quite slow, 87 sec on windows.
+  testFdLeak()
diff --git a/tests/stdlib/tfenv.nim b/tests/stdlib/tfenv.nim
new file mode 100644
index 000000000..a486b8a9d
--- /dev/null
+++ b/tests/stdlib/tfenv.nim
@@ -0,0 +1,8 @@
+import std/fenv
+import std/assertions
+
+
+func is_significant(x: float): bool =
+  x > minimumPositiveValue(float) and x < maximumPositiveValue(float)
+
+doAssert is_significant(10.0)
diff --git a/tests/stdlib/tfilesanddirs.nim b/tests/stdlib/tfilesanddirs.nim
new file mode 100644
index 000000000..a1920d4f2
--- /dev/null
+++ b/tests/stdlib/tfilesanddirs.nim
@@ -0,0 +1,36 @@
+import std/[paths, files, dirs, appdirs]
+
+from stdtest/specialpaths import buildDir
+import std/[syncio, assertions]
+
+block fileOperations:
+  let files = @[Path"these.txt", Path"are.x", Path"testing.r", Path"files.q"]
+  let dirs = @[Path"some", Path"created", Path"test", Path"dirs"]
+
+  let dname = Path"__really_obscure_dir_name"
+
+  createDir(dname.Path)
+  doAssert dirExists(Path(dname))
+ 
+  # Test creating files and dirs
+  for dir in dirs:
+    createDir(Path(dname/dir))
+    doAssert dirExists(Path(dname/dir))
+
+  for file in files:
+    let fh = open(string(dname/file), fmReadWrite) # createFile
+    fh.close()
+    doAssert fileExists(Path(dname/file))
+
+block: # getCacheDir
+  doAssert getCacheDir().dirExists
+
+block: # moveFile
+  let tempDir = getTempDir() / Path("D20221022T151608")
+  createDir(tempDir)
+  defer: removeDir(tempDir)
+
+block: # moveDir
+  let tempDir = getTempDir() / Path("D20220609T161443")
+  createDir(tempDir)
+  defer: removeDir(tempDir)
diff --git a/tests/stdlib/tfrexp1.nim b/tests/stdlib/tfrexp1.nim
new file mode 100644
index 000000000..aa734ddac
--- /dev/null
+++ b/tests/stdlib/tfrexp1.nim
@@ -0,0 +1,55 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "js c cpp"
+"""
+
+import std/math
+import std/assertions
+
+const manualTest = false
+
+when manualTest:
+  import strformat
+
+proc frexp_test(lo, hi, step: float64) =
+  var exp: int
+  var frac: float64
+
+  var eps = 1e-15.float64
+
+  var x:float64 = lo
+  while x <= hi:
+    frac = frexp(x.float, exp)
+    let rslt = pow(2.0, float(exp)) * frac
+
+    doAssert(abs(rslt - x) < eps)
+
+    when manualTest:
+      echo fmt("x: {x:10.3f} exp: {exp:4d} frac: {frac:24.20f} check: {$(abs(rslt - x) < eps):-5s} {rslt: 9.3f}")
+    x += step
+
+when manualTest:
+  var exp: int
+  var frac: float64
+
+  for flval in [1.7976931348623157e+308, -1.7976931348623157e+308, # max, min float64
+                3.4028234663852886e+38, -3.4028234663852886e+38,   # max, min float32
+                4.9406564584124654e-324, -4.9406564584124654e-324, # smallest/largest positive/negative float64
+                1.4012984643248171e-45, -1.4012984643248171e-45,   # smallest/largest positive/negative float32
+                2.2250738585072014e-308, 1.1754943508222875e-38]:  # smallest normal float64/float32
+    frac = frexp(flval, exp)
+    echo fmt("{flval:25.16e}, {exp: 6d}, {frac: .20f} {frac * pow(2.0, float(exp)): .20e}")
+
+  frexp_test(-1000.0, 1000.0, 0.0125)
+else:
+  frexp_test(-200000.0, 200000.0, 0.125)
+
+
+doAssert frexp(8.0) == (0.5, 4)
+doAssert frexp(-8.0) == (-0.5, 4)
+doAssert frexp(0.0) == (0.0, 0)
+
+block:
+  var x: int
+  doAssert frexp(5.0, x) == 0.625
+  doAssert x == 3
diff --git a/tests/stdlib/tgenast.nim b/tests/stdlib/tgenast.nim
new file mode 100644
index 000000000..d99c9312e
--- /dev/null
+++ b/tests/stdlib/tgenast.nim
@@ -0,0 +1,274 @@
+discard """
+  matrix: "--mm:orc; --mm:refc"
+"""
+
+# xxx also test on js
+
+import std/genasts
+import std/macros
+from std/strformat import `&`
+import std/assertions
+import ./mgenast
+
+proc main =
+  block:
+    macro bar(x0: static Foo, x1: Foo, x2: Foo, xignored: Foo): untyped =
+      let s0 = "not captured!"
+      let s1 = "not captured!"
+      let xignoredLocal = kfoo4
+
+      # newLit optional:
+      let x3 = newLit kfoo4
+      let x3b = kfoo4
+
+      result = genAstOpt({kDirtyTemplate}, s1=true, s2="asdf", x0, x1=x1, x2, x3, x3b):
+        doAssert not declared(xignored)
+        doAssert not declared(xignoredLocal)
+        (s1, s2, s0, x0, x1, x2, x3, x3b)
+
+    let s0 = "caller scope!"
+
+    doAssert bar(kfoo1, kfoo2, kfoo3, kfoo4) ==
+      (true, "asdf", "caller scope!", kfoo1, kfoo2, kfoo3, kfoo4, kfoo4)
+
+  block:
+    # doesn't have limitation mentioned in https://github.com/nim-lang/RFCs/issues/122#issue-401636535
+    macro abc(name: untyped): untyped =
+      result = genAst(name):
+        type name = object
+
+    abc(Bar)
+    doAssert Bar.default == Bar()
+
+  block:
+    # backticks parser limitations / ambiguities not are an issue with `genAst`:
+    # (#10326 #9745 are fixed but `quote do` still has underlying ambiguity issue
+    # with backticks)
+    type Foo = object
+      a: int
+
+    macro m1(): untyped =
+      # result = quote do: # Error: undeclared identifier: 'a1'
+      result = genAst:
+        template `a1=`(x: var Foo, val: int) =
+          x.a = val
+
+    m1()
+    var x0: Foo
+    x0.a1 = 10
+    doAssert x0 == Foo(a: 10)
+
+  block:
+    # avoids bug #7375
+    macro fun(b: static[bool], b2: bool): untyped =
+      result = newStmtList()
+    macro foo(c: bool): untyped =
+      var b = false
+      result = genAst(b, c):
+        fun(b, c)
+
+    foo(true)
+
+  block:
+    # avoids bug #7589
+    # since `==` works with genAst, the problem goes away
+    macro foo2(): untyped =
+      # result = quote do: # Error: '==' cannot be passed to a procvar
+      result = genAst:
+        `==`(3,4)
+    doAssert not foo2()
+
+  block:
+    # avoids bug #7726
+    # expressions such as `a.len` are just passed as arguments to `genAst`, and
+    # caller scope is not polluted with definitions such as `let b = newLit a.len`
+    macro foo(): untyped =
+      let a = @[1, 2, 3, 4, 5]
+      result = genAst(a, b = a.len): # shows 2 ways to get a.len
+        (a.len, b)
+    doAssert foo() == (5, 5)
+
+  block:
+    # avoids bug #9607
+    proc fun1(info:LineInfo): string = "bar1"
+    proc fun2(info:int): string = "bar2"
+
+    macro bar2(args: varargs[untyped]): untyped =
+      let info = args.lineInfoObj
+      let fun1 = bindSym"fun1" # optional; we can remove this and also the
+      # capture of fun1, as show in next example
+      result = genAst(info, fun1):
+        (fun1(info), fun2(info.line))
+    doAssert bar2() == ("bar1", "bar2")
+
+    macro bar3(args: varargs[untyped]): untyped =
+      let info = args.lineInfoObj
+      result = genAst(info):
+        (fun1(info), fun2(info.line))
+    doAssert bar3() == ("bar1", "bar2")
+
+    macro bar(args: varargs[untyped]): untyped =
+      let info = args.lineInfoObj
+      let fun1 = bindSym"fun1"
+      let fun2 = bindSym"fun2"
+      result = genAstOpt({kDirtyTemplate}, info):
+        (fun1(info), fun2(info.line))
+    doAssert bar() == ("bar1", "bar2")
+
+  block:
+    # example from bug #7889 works
+    # after changing method call syntax to regular call syntax; this is a
+    # limitation described in bug #7085
+    # note that `quote do` would also work after that change in this example.
+    doAssert bindme2() == kfoo1
+    doAssert bindme3() == kfoo1
+    doAssert not compiles(bindme4()) # correctly gives Error: undeclared identifier: 'myLocalPriv'
+    proc myLocalPriv2(): auto = kfoo2
+    doAssert bindme5UseExpose() == kfoo1
+
+    # example showing hijacking behavior when using `kDirtyTemplate`
+    doAssert bindme5UseExposeFalse() == kfoo2
+      # local `myLocalPriv2` hijacks symbol `mgenast.myLocalPriv2`. In most
+      # use cases this is probably not what macro writer intends as it's
+      # surprising; hence `kDirtyTemplate` is not the default.
+
+    when nimvm: # disabled because `newStringStream` is used
+      discard
+    else:
+      bindme6UseExpose()
+      bindme6UseExposeFalse()
+
+  block:
+    macro mbar(x3: Foo, x3b: static Foo): untyped =
+      var x1=kfoo3
+      var x2=newLit kfoo3
+      var x4=kfoo3
+      var xLocal=kfoo3
+
+      proc funLocal(): auto = kfoo4
+
+      result = genAst(x1, x2, x3, x4):
+        # local x1 overrides remote x1
+        when false:
+          # one advantage of using `kDirtyTemplate` is that these would hold:
+          doAssert not declared xLocal
+          doAssert not compiles(echo xLocal)
+          # however, even without it, we at least correctly generate CT error
+          # if trying to use un-captured symbol; this correctly gives:
+          # Error: internal error: environment misses: xLocal
+          echo xLocal
+
+        proc foo1(): auto =
+          # note that `funLocal` is captured implicitly, according to hygienic
+          # template rules; with `kDirtyTemplate` it would not unless
+          # captured in `genAst` capture list explicitly
+          (a0: xRemote, a1: x1, a2: x2, a3: x3, a4: x4, a5: funLocal())
+
+      return result
+
+    proc main()=
+      var xRemote=kfoo1
+      var x1=kfoo2
+      mbar(kfoo4, kfoo4)
+      doAssert foo1() == (a0: kfoo1, a1: kfoo3, a2: kfoo3, a3: kfoo4, a4: kfoo3, a5: kfoo4)
+
+    main()
+
+  block:
+    # With `kDirtyTemplate`, the example from #8220 works.
+    # See https://nim-lang.github.io/Nim/strformat.html#limitations for
+    # an explanation of why {.dirty.} is needed.
+    macro foo(): untyped =
+      result = genAstOpt({kDirtyTemplate}):
+        let bar = "Hello, World"
+        &"Let's interpolate {bar} in the string"
+    doAssert foo() == "Let's interpolate Hello, World in the string"
+
+
+  block: # nested application of genAst
+    macro createMacro(name, obj, field: untyped): untyped =
+      result = genAst(obj = newDotExpr(obj, field), lit = 10, name, field):
+        # can't reuse `result` here, would clash
+        macro name(arg: untyped): untyped =
+          genAst(arg2=arg): # somehow `arg2` rename is needed
+            (obj, astToStr(field), lit, arg2)
+
+    var x = @[1, 2, 3]
+    createMacro foo, x, len
+    doAssert (foo 20) == (3, "len", 10, 20)
+
+  block: # test with kNoNewLit
+    macro bar(): untyped =
+      let s1 = true
+      template boo(x): untyped =
+        fun(x)
+      result = genAstOpt({kNoNewLit}, s1=newLit(s1), s1b=s1): (s1, s1b)
+    doAssert bar() == (true, 1)
+
+  block: # sanity check: check passing `{}` also works
+    macro bar(): untyped =
+      result = genAstOpt({}, s1=true): s1
+    doAssert bar() == true
+
+  block: # test passing function and type symbols
+    proc z1(): auto = 41
+    type Z4 = type(1'i8)
+    macro bar(Z1: typedesc): untyped =
+      proc z2(): auto = 42
+      proc z3[T](a: T): auto = 43
+      let Z2 = genAst():
+        type(true)
+      let z4 = genAst():
+        proc myfun(): auto = 44
+        myfun
+      type Z3 = type(1'u8)
+      result = genAst(z4, Z1, Z2):
+        # z1, z2, z3, Z3, Z4 are captured automatically
+        # z1, z2, z3 can optionally be specified in capture list
+        (z1(), z2(), z3('a'), z4(), $Z1, $Z2, $Z3, $Z4)
+    type Z1 = type('c')
+    doAssert bar(Z1) == (41, 42, 43, 44, "char", "bool", "uint8", "int8")
+
+  block: # fix bug #11986
+    proc foo(): auto =
+      var s = { 'a', 'b' }
+      # var n = quote do: `s` # would print {97, 98}
+      var n = genAst(s): s
+      n.repr
+    static: doAssert foo() == "{'a', 'b'}"
+
+  block: # also from #11986
+    macro foo(): untyped =
+      var s = { 'a', 'b' }
+      # quote do:
+      #   let t = `s`
+      #   $typeof(t) # set[range 0..65535(int)]
+      genAst(s):
+        let t = s
+        $typeof(t)
+    doAssert foo() == "set[char]"
+
+  block:
+    macro foo(): untyped =
+      type Foo = object
+      template baz2(a: int): untyped = a*10
+      macro baz3(a: int): untyped = newLit 13
+      result = newStmtList()
+
+      result.add genAst(Foo, baz2, baz3) do: # shows you can pass types, templates etc
+        var x: Foo
+        $($typeof(x), baz2(3), baz3(4))
+
+      let ret = genAst() do: # shows you don't have to, since they're inject'd
+        var x: Foo
+        $($typeof(x), baz2(3), baz3(4))
+    doAssert foo() == """("Foo", 30, 13)"""
+
+  block: # illustrates how symbol visiblity can be controlled precisely using `mixin`
+    proc locafun1(): auto = "in locafun1 (caller scope)" # this will be used because of `mixin locafun1` => explicit hijacking is ok
+    proc locafun2(): auto = "in locafun2 (caller scope)" # this won't be used => no hijacking
+    proc locafun3(): auto = "in locafun3 (caller scope)"
+    doAssert mixinExample() == ("in locafun1 (caller scope)", "in locafun2", "in locafun3 (caller scope)")
+
+static: main()
+main()
diff --git a/tests/stdlib/tgetaddrinfo.nim b/tests/stdlib/tgetaddrinfo.nim
new file mode 100644
index 000000000..3a90034c8
--- /dev/null
+++ b/tests/stdlib/tgetaddrinfo.nim
@@ -0,0 +1,38 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  exitcode: 0
+  output: ""
+"""
+
+# bug: https://github.com/nim-lang/Nim/issues/10198
+
+import nativesockets
+import std/assertions
+
+block DGRAM_UDP:
+  let aiList = getAddrInfo("127.0.0.1", 999.Port, AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+  doAssert aiList != nil
+  doAssert aiList.ai_addr != nil
+  doAssert aiList.ai_addrlen.SockLen == sizeof(Sockaddr_in).SockLen
+  doAssert aiList.ai_next == nil
+  freeAddrInfo aiList
+
+when defined(posix) and not defined(haiku) and not defined(freebsd) and not defined(openbsd) and not defined(netbsd):
+
+  block RAW_ICMP:
+    # the port will be ignored
+    let aiList = getAddrInfo("127.0.0.1", 999.Port, AF_INET, SOCK_RAW, IPPROTO_ICMP)
+    doAssert aiList != nil
+    doAssert aiList.ai_addr != nil
+    doAssert aiList.ai_addrlen.SockLen == sizeof(Sockaddr_in).SockLen
+    doAssert aiList.ai_next == nil
+    freeAddrInfo aiList
+
+  block RAW_ICMPV6:
+    # the port will be ignored
+    let aiList = getAddrInfo("::1", 999.Port, AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)
+    doAssert aiList != nil
+    doAssert aiList.ai_addr != nil
+    doAssert aiList.ai_addrlen.SockLen == sizeof(Sockaddr_in6).SockLen
+    doAssert aiList.ai_next == nil
+    freeAddrInfo aiList
diff --git a/tests/stdlib/tgetfileinfo.nim b/tests/stdlib/tgetfileinfo.nim
new file mode 100644
index 000000000..ae1480a4c
--- /dev/null
+++ b/tests/stdlib/tgetfileinfo.nim
@@ -0,0 +1,164 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: "pcDir\npcFile\npcLinkToDir\npcLinkToFile\n"
+  joinable: false
+"""
+
+import os, strutils
+import std/[syncio, assertions]
+# Cases
+#  1 - String : Existing File : Symlink true
+#  2 - String : Existing File : Symlink false
+#  3 - String : Non-existing File : Symlink true
+#  4 - String : Non-existing File : Symlink false
+#  5 - Handle : Valid File
+#  6 - Handle : Invalid File
+#  7 - Handle : Valid Handle
+#  8 - Handle : Invalid Handle
+
+proc genBadFileName(limit = 100): string =
+    ## Generates a filename of a nonexistent file.
+    ## Returns "" if generation fails.
+    result = "a"
+    var hitLimit = true
+
+    for i in 0..100:
+      if fileExists(result):
+        result.add("a")
+      else:
+        hitLimit = false
+        break
+    if hitLimit:
+      result = ""
+
+proc caseOneAndTwo(followLink: bool) =
+  try:
+    discard getFileInfo(getAppFilename(), followLink)
+    #echo("String : Existing File : Symlink $# : Success" % $followLink)
+  except OSError:
+    echo("String : Existing File : Symlink $# : Failure" % $followLink)
+
+proc caseThreeAndFour(followLink: bool) =
+  var invalidName = genBadFileName()
+  try:
+    discard getFileInfo(invalidName, true)
+    echo("String : Non-existing File : Symlink $# : Failure" % $followLink)
+  except OSError:
+    discard
+    #echo("String : Non-existing File : Symlink $# : Success" % $followLink)
+
+proc testGetFileInfo =
+  # Case 1
+  caseOneAndTwo(true)
+
+  # Case 2
+  caseOneAndTwo(false)
+
+  # Case 3
+  caseThreeAndFour(true)
+
+  # Case 4
+  caseThreeAndFour(false)
+
+  # Case 5 and 7
+  block:
+    let
+      testFile = open(getAppFilename())
+      testHandle = getFileHandle(testFile)
+    try:
+      discard getFileInfo(testFile)
+      #echo("Handle : Valid File : Success")
+    except IOError:
+      echo("Handle : Valid File : Failure")
+
+    try:
+      discard getFileInfo(testHandle)
+      #echo("Handle : Valid File : Success")
+    except IOError:
+      echo("Handle : Valid File : Failure")
+
+  # Case 6 and 8
+  block:
+    let
+      testFile: File = nil
+      testHandle = FileHandle(-1)
+    try:
+      discard getFileInfo(testFile)
+      echo("Handle : Invalid File : Failure")
+    except IOError, OSError:
+      discard
+      #echo("Handle : Invalid File : Success")
+
+    try:
+      discard getFileInfo(testHandle)
+      echo("Handle : Invalid File : Failure")
+    except IOError, OSError:
+      discard
+      #echo("Handle : Invalid File : Success")
+
+  # Test kind for files, directories and symlinks.
+  block:
+    let
+      tmp = getTempDir()
+      dirPath      = tmp / "test-dir"
+      filePath     = tmp / "test-file"
+      linkDirPath  = tmp / "test-link-dir"
+      linkFilePath = tmp / "test-link-file"
+
+    createDir(dirPath)
+    writeFile(filePath, "")
+    when defined(posix):
+      createSymlink(dirPath, linkDirPath)
+      createSymlink(filePath, linkFilePath)
+
+    let
+      dirInfo = getFileInfo(dirPath)
+      fileInfo = getFileInfo(filePath)
+    when defined(posix):
+      let
+        linkDirInfo = getFileInfo(linkDirPath, followSymlink = false)
+        linkFileInfo = getFileInfo(linkFilePath, followSymlink = false)
+
+    echo dirInfo.kind
+    echo fileInfo.kind
+    when defined(posix):
+      echo linkDirInfo.kind
+      echo linkFileInfo.kind
+    else:
+      echo pcLinkToDir
+      echo pcLinkToFile
+
+    doAssert dirInfo.isSpecial == false
+    doAssert fileInfo.isSpecial == false
+    when defined(posix):
+      doAssert linkDirInfo.isSpecial == false
+      doAssert linkFileInfo.isSpecial == false
+
+    removeDir(dirPath)
+    removeFile(filePath)
+    when defined(posix):
+      removeFile(linkDirPath)
+      removeFile(linkFilePath)
+
+  # Test that `isSpecial` is set correctly
+  block:
+    when defined(posix):
+      let
+        tmp = getTempDir()
+        fifoPath     = tmp / "test-fifo"
+        linkFifoPath = tmp / "test-link-fifo"
+
+      doAssert execShellCmd("mkfifo " & fifoPath) == 0
+      createSymlink(fifoPath, linkFifoPath)
+
+      let
+        fifoInfo = getFileInfo(fifoPath)
+        linkFifoInfo = getFileInfo(linkFifoPath)
+
+      doAssert fifoInfo.isSpecial == true
+      doAssert linkFifoInfo.isSpecial == true
+
+      removeFile(fifoPath)
+      removeFile(linkFifoPath)
+
+testGetFileInfo()
diff --git a/tests/stdlib/tgetprotobyname.nim b/tests/stdlib/tgetprotobyname.nim
new file mode 100644
index 000000000..1fc060ffe
--- /dev/null
+++ b/tests/stdlib/tgetprotobyname.nim
@@ -0,0 +1,19 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import nativesockets
+import std/assertions
+
+doAssert getProtoByName("ipv6") == 41
+doAssert getProtoByName("tcp") == 6
+doAssert getProtoByName("udp") == 17
+doAssert getProtoByName("icmp") == 1
+doAssert getProtoByName("ipv6-icmp") == 58
+
+when defined(windows):
+  doAssertRaises(OSError):
+    discard getProtoByName("raw")
+
+doAssertRaises(OSError):
+  discard getProtoByName("Error")
diff --git a/tests/stdlib/tglobs.nim b/tests/stdlib/tglobs.nim
new file mode 100644
index 000000000..4aa21992c
--- /dev/null
+++ b/tests/stdlib/tglobs.nim
@@ -0,0 +1,25 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/globs
+import std/assertions
+
+template main =
+  when defined(windows):
+    doAssert nativeToUnixPath("C:") == "/C"
+    doAssert nativeToUnixPath(r"D:\") == "/D/"
+    doAssert nativeToUnixPath(r"E:\a") == "/E/a"
+    doAssert nativeToUnixPath(r"E:\a1\") == "/E/a1/"
+    doAssert nativeToUnixPath(r"E:\a1\bc") == "/E/a1/bc"
+    doAssert nativeToUnixPath(r"\a1\bc") == "/a1/bc"
+    doAssert nativeToUnixPath(r"a1\bc") == "a1/bc"
+    doAssert nativeToUnixPath("a1") == "a1"
+    doAssert nativeToUnixPath("") == ""
+    doAssert nativeToUnixPath(".") == "."
+    doAssert nativeToUnixPath("..") == ".."
+    doAssert nativeToUnixPath(r"..\") == "../"
+    doAssert nativeToUnixPath(r"..\..\.\") == "../.././"
+
+static: main()
+main()
diff --git a/tests/stdlib/thashes.nim b/tests/stdlib/thashes.nim
new file mode 100644
index 000000000..4555fbcb3
--- /dev/null
+++ b/tests/stdlib/thashes.nim
@@ -0,0 +1,242 @@
+discard """
+  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
+from stdtest/testutils import disableVm, whenVMorJs
+import std/assertions
+
+when not defined(js) and not defined(cpp):
+  block:
+    var x = 12
+    iterator hello(): int {.closure.} =
+      yield x
+
+    discard hash(hello)
+
+block hashes:
+  block hashing:
+    var dummy = 0.0
+    doAssert hash(dummy) == hash(-dummy)
+
+  # "VM and runtime should make the same hash value (hashIdentity)"
+  block:
+    const hi123 = hashIdentity(123)
+    doAssert hashIdentity(123) == hi123
+
+  # "VM and runtime should make the same hash value (hashWangYi1)"
+  block:
+    const wy123 = hashWangYi1(123)
+    doAssert wy123 != 0
+    doAssert hashWangYi1(123) == wy123
+    const wyNeg123 = hashWangYi1(-123)
+    doAssert wyNeg123 != 0
+    when not defined(js): # TODO: fixme it doesn't work for JS
+      doAssert hashWangYi1(-123) == wyNeg123
+
+
+  # "hashIdentity value incorrect at 456"
+  block:
+    doAssert hashIdentity(456) == 456
+
+  # "hashWangYi1 value incorrect at 456"
+  block:
+    when Hash.sizeof < 8:
+      doAssert hashWangYi1(456) == 1293320666
+    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) == emptyStrHash
+  doAssert hash(b) == emptyStrHash
+  doAssert hash(c) == 0
+  doAssert hash(d) == emptyStrHash
+  doAssert hashIgnoreCase(a) == 0
+  doAssert hashIgnoreStyle(a) == 0
+  doAssert hash(e, 3, 2) == emptyStrHash
+
+block sameButDifferent:
+  doAssert hash("aa bb aaaa1234") == hash("aa bb aaaa1234", 0, 13)
+  doAssert hash("aa bb aaaa1234") == hash(cstring"aa bb aaaa1234")
+  doAssert hashIgnoreCase("aA bb aAAa1234") == hashIgnoreCase("aa bb aaaa1234")
+  doAssert hashIgnoreStyle("aa_bb_AAaa1234") == hashIgnoreCase("aaBBAAAa1234")
+
+block smallSize: # no multibyte hashing
+  let
+    xx = @['H', 'i']
+    ii = @[72'u8, 105]
+    ss = "Hi"
+  doAssert hash(xx) == hash(ii)
+  doAssert hash(xx) == hash(ss)
+  doAssert hash(xx) == hash(xx, 0, xx.high)
+  doAssert hash(ss) == hash(ss, 0, ss.high)
+
+block largeSize: # longer than 4 characters
+  let
+    xx = @['H', 'e', 'l', 'l', 'o']
+    xxl = @['H', 'e', 'l', 'l', 'o', 'w', 'e', 'e', 'n', 's']
+    ssl = "Helloweens"
+  doAssert hash(xxl) == hash(ssl)
+  doAssert hash(xxl) == hash(xxl, 0, xxl.high)
+  doAssert hash(ssl) == hash(ssl, 0, ssl.high)
+  doAssert hash(xx) == hash(xxl, 0, 4)
+  doAssert hash(xx) == hash(ssl, 0, 4)
+  doAssert hash(xx, 0, 3) == hash(xxl, 0, 3)
+  doAssert hash(xx, 0, 3) == hash(ssl, 0, 3)
+
+proc main() =
+  doAssert hash(0.0) == hash(0)
+  # bug #16061
+  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):
+    block:
+      var s: seq[Hash]
+      for a in [0.0, 1.0, -1.0, 1000.0, -1000.0]:
+        let b = hash(a)
+        doAssert b notin s
+        s.add b
+    when defined(js):
+      doAssert hash(0.345602) == 2035867618
+      doAssert hash(234567.45) == -20468103
+      doAssert hash(-9999.283456) == -43247422
+      doAssert hash(84375674.0) == 707542256
+    else:
+      doAssert hash(0.345602) == 387936373221941218
+      doAssert hash(234567.45) == -8179139172229468551
+      doAssert hash(-9999.283456) == 5876943921626224834
+      doAssert hash(84375674.0) == 1964453089107524848
+  else:
+    doAssert hash(0.345602) != 0
+    doAssert hash(234567.45) != 0
+    doAssert hash(-9999.283456) != 0
+    doAssert hash(84375674.0) != 0
+
+  block: # bug #16555
+    proc fn(): auto =
+      # avoids hardcoding values
+      var a = "abc\0def"
+      var b = a.cstring
+      result = (hash(a), hash(b))
+      doAssert result[0] != result[1]
+    when not defined(js):
+      doAssert fn() == static(fn())
+    else:
+      # xxx this is a tricky case; consistency of hashes for cstring's containing
+      # '\0\' matters for c backend but less for js backend since such strings
+      # are much less common in js backend; we make vm for js backend consistent
+      # with c backend instead of js backend because FFI code (or other) could
+      # run at CT, expecting c semantics.
+      discard
+
+  block: # hash(object)
+    type
+      Obj = object
+        x: int
+        y: string
+      Obj2[T] = object
+        x: int
+        y: string
+      Obj3 = object
+        x: int
+        y: string
+      Obj4 = object
+        case t: bool
+        of false:
+          x: int
+        of true:
+          y: int
+        z: int
+      Obj5 = object
+        case t: bool
+        of false:
+          x: int
+        of true:
+          y: int
+        z: int
+
+    proc hash(a: Obj2): Hash = hash(a.x)
+    proc hash(a: Obj3): Hash = hash((a.x,))
+    proc hash(a: Obj5): Hash =
+      case a.t
+      of false: hash(a.x)
+      of true: hash(a.y)
+
+    doAssert hash(Obj(x: 520, y: "Nim")) != hash(Obj(x: 520, y: "Nim2"))
+    doAssert hash(Obj2[float](x: 520, y: "Nim")) == hash(Obj2[float](x: 520, y: "Nim2"))
+    doAssert hash(Obj2[float](x: 520, y: "Nim")) != hash(Obj2[float](x: 521, y: "Nim2"))
+    doAssert hash(Obj3(x: 520, y: "Nim")) == hash(Obj3(x: 520, y: "Nim2"))
+
+    doAssert hash(Obj4(t: false, x: 1)) == hash(Obj4(t: false, x: 1))
+    doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: false, x: 2))
+    doAssert hash(Obj4(t: false, x: 1)) != hash(Obj4(t: true, y: 1))
+
+    doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: false, x: 2))
+    doAssert hash(Obj5(t: false, x: 1)) == hash(Obj5(t: true, y: 1))
+    doAssert hash(Obj5(t: false, x: 1)) != hash(Obj5(t: true, y: 2))
+
+  block: # hash(ref|ptr|pointer)
+    var a: array[10, uint8]
+    # disableVm:
+    whenVMorJs:
+      # pending fix proposed in https://github.com/nim-lang/Nim/issues/15952#issuecomment-786312417
+      discard
+    do:
+      doAssert a[0].addr.hash != a[1].addr.hash
+      doAssert cast[pointer](a[0].addr).hash == a[0].addr.hash
+
+  block: # hash(ref)
+    type A = ref object
+      x: int
+    let a = A(x: 3)
+    disableVm: # xxx Error: VM does not support 'cast' from tyRef to tyPointer
+      let ha = a.hash
+      doAssert ha != A(x: 3).hash # A(x: 3) is a different ref object from `a`.
+      a.x = 4
+      doAssert ha == a.hash # the hash only depends on the address
+
+  block: # hash(proc)
+    proc fn(a: int): auto = a*2
+    doAssert fn isnot "closure"
+    doAssert fn is (proc)
+    const fn2 = fn
+    let fn3 = fn
+    whenVMorJs: discard
+    do:
+      doAssert hash(fn2) == hash(fn)
+      doAssert hash(fn3) == hash(fn)
+
+  block: # hash(closure)
+    proc outer() =
+      var a = 0
+      proc inner() = a.inc
+      doAssert inner is "closure"
+      let inner2 = inner
+      whenVMorJs: discard
+      do:
+        doAssert hash(inner2) == hash(inner)
+    outer()
+
+static: main()
+main()
diff --git a/tests/stdlib/theapqueue.nim b/tests/stdlib/theapqueue.nim
new file mode 100644
index 000000000..afb09c7e3
--- /dev/null
+++ b/tests/stdlib/theapqueue.nim
@@ -0,0 +1,106 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/heapqueue
+import std/assertions
+
+proc toSortedSeq[T](h: HeapQueue[T]): seq[T] =
+  var tmp = h
+  result = @[]
+  while tmp.len > 0:
+    result.add(pop(tmp))
+
+proc heapProperty[T](h: HeapQueue[T]): bool =
+  for k in 0 .. h.len - 2: # the last element is always a leaf
+    let left = 2 * k + 1
+    if left < h.len and h[left] < h[k]:
+      return false
+    let right = left + 1
+    if right < h.len and h[right] < h[k]:
+      return false
+  true
+
+template main() =
+  block: # simple sanity test
+    var heap = initHeapQueue[int]()
+    let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
+    for item in data:
+      push(heap, item)
+    doAssert(heap == data.toHeapQueue)
+    doAssert(heap[0] == 0)
+    doAssert(heap.toSortedSeq == @[0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
+
+  block: # test del
+    var heap = initHeapQueue[int]()
+    let data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
+    for item in data: push(heap, item)
+
+    heap.del(0)
+    doAssert(heap[0] == 1)
+
+    heap.del(heap.find(7))
+    doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 5, 6, 8, 9])
+
+    heap.del(heap.find(5))
+    doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 6, 8, 9])
+
+    heap.del(heap.find(6))
+    doAssert(heap.toSortedSeq == @[1, 2, 3, 4, 8, 9])
+
+    heap.del(heap.find(2))
+    doAssert(heap.toSortedSeq == @[1, 3, 4, 8, 9])
+
+    doAssert(heap.find(2) == -1)
+
+  block: # test del last
+    var heap = initHeapQueue[int]()
+    let data = [1, 2, 3]
+    for item in data: push(heap, item)
+
+    heap.del(2)
+    doAssert(heap.toSortedSeq == @[1, 2])
+
+    heap.del(1)
+    doAssert(heap.toSortedSeq == @[1])
+
+    heap.del(0)
+    doAssert(heap.toSortedSeq == @[])
+
+  block: # testing the heap proeprty
+    var heap = [1, 4, 2, 5].toHeapQueue
+    doAssert heapProperty(heap)
+
+    heap.push(42)
+    doAssert heapProperty(heap)
+    heap.push(0)
+    doAssert heapProperty(heap)
+    heap.push(3)
+    doAssert heapProperty(heap)
+    heap.push(3)
+    doAssert heapProperty(heap)
+
+    # [0, 3, 1, 4, 42, 2, 3, 5]
+
+    discard heap.pop()
+    doAssert heapProperty(heap)
+    discard heap.pop()
+    doAssert heapProperty(heap)
+
+    heap.del(2)
+    doAssert heapProperty(heap)
+
+    # [2, 3, 5, 4, 42]
+
+    discard heap.replace(12)
+    doAssert heapProperty(heap)
+    discard heap.replace(1)
+    doAssert heapProperty(heap)
+
+    discard heap.pushpop(2)
+    doAssert heapProperty(heap)
+    discard heap.pushpop(0)
+    doAssert heapProperty(heap)
+
+static: main()
+main()
diff --git a/tests/stdlib/thighlite.nim b/tests/stdlib/thighlite.nim
new file mode 100644
index 000000000..0cd334254
--- /dev/null
+++ b/tests/stdlib/thighlite.nim
@@ -0,0 +1,45 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import unittest, strutils
+import ../../lib/packages/docutils/highlite
+import std/objectdollar
+
+block: # Nim tokenizing
+  test "string literals and escape seq":
+    check("\"ok1\\nok2\\nok3\"".tokenize(langNim) ==
+       @[("\"ok1", gtStringLit), ("\\n", gtEscapeSequence), ("ok2", gtStringLit),
+         ("\\n", gtEscapeSequence), ("ok3\"", gtStringLit)
+      ])
+    check("\"\"\"ok1\\nok2\\nok3\"\"\"".tokenize(langNim) ==
+       @[("\"\"\"ok1\\nok2\\nok3\"\"\"", gtLongStringLit)
+      ])
+
+  test "whitespace at beginning of line is preserved":
+    check("  discard 1".tokenize(langNim) ==
+       @[("  ", gtWhitespace), ("discard", gtKeyword), (" ", gtWhitespace),
+         ("1", gtDecNumber)
+       ])
+
+block: # Cmd (shell) tokenizing
+  test "cmd with dollar and output":
+    check(
+      dedent"""
+        $ nim c file.nim
+        out: file [SuccessX]"""
+        .tokenize(langConsole) ==
+      @[("$ ", gtPrompt), ("nim", gtProgram),
+        (" ", gtWhitespace), ("c", gtOption), (" ", gtWhitespace),
+        ("file.nim", gtIdentifier), ("\n", gtWhitespace),
+        ("out: file [SuccessX]", gtProgramOutput)
+      ])
+
+block: # bug #21232
+  let code = "/"
+  var toknizr: GeneralTokenizer
+
+  initGeneralTokenizer(toknizr, code)
+
+  getNextToken(toknizr, langC)
+  check $toknizr == """(kind: gtOperator, start: 0, length: 1, buf: "/", pos: 1, state: gtEof, lang: langC)"""
diff --git a/tests/stdlib/thtmlparser.nim b/tests/stdlib/thtmlparser.nim
new file mode 100644
index 000000000..853a1c0cc
--- /dev/null
+++ b/tests/stdlib/thtmlparser.nim
@@ -0,0 +1,159 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+  output: '''
+true
+https://example.com/test?format=jpg&name=orig##
+https://example.com/test?format=jpg&name=orig##text
+https://example.com/test?format=jpg##text
+'''
+"""
+import htmlparser
+import xmltree
+import strutils
+from streams import newStringStream
+import std/assertions
+
+block t2813:
+  const
+    html = """
+    <html>
+      <head>
+        <title>Test</title>
+      </head>
+      <body>
+        <table>
+          <thead>
+            <tr><td>A</td></tr>
+            <tr><td>B</td></tr>
+          </thead>
+          <tbody>
+            <tr><td></td>A<td></td></tr>
+            <tr><td></td>B<td></td></tr>
+            <tr><td></td>C<td></td></tr>
+          </tbody>
+          <tfoot>
+            <tr><td>A</td></tr>
+          </tfoot>
+        </table>
+      </body>
+    </html>
+    """
+  var errors: seq[string] = @[]
+  let tree = parseHtml(newStringStream(html), "test.html", errors)
+  doAssert errors.len == 0 # Errors: </thead> expected,...
+
+  var len = tree.findAll("tr").len # len = 6
+  var rows: seq[XmlNode] = @[]
+  for n in tree.findAll("table"):
+    n.findAll("tr", rows)  # len = 2
+    break
+  doAssert tree.findAll("tr").len == rows.len
+
+
+block t2814:
+  ## builds the two cases below and test that
+  ## ``//[dd,li]`` has "<p>that</p>" as children
+  ##
+  ##  <dl>
+  ##    <dt>this</dt>
+  ##    <dd>
+  ##      <p>that</p>
+  ##    </dd>
+  ##  </dl>
+
+  ##
+  ## <ul>
+  ##   <li>
+  ##     <p>that</p>
+  ##   </li>
+  ## </ul>
+  for ltype in [["dl","dd"], ["ul","li"]]:
+    let desc_item = if ltype[0]=="dl": "<dt>this</dt>" else: ""
+    let item = "$1<$2><p>that</p></$2>" % [desc_item, ltype[1]]
+    let list = """ <$1>
+     $2
+  </$1> """ % [ltype[0], item]
+
+    var errors : seq[string] = @[]
+    let parseH = parseHtml(newStringStream(list),"statichtml", errors =errors)
+
+    if $parseH.findAll(ltype[1])[0].child("p") != "<p>that</p>":
+      echo "case " & ltype[0] & " failed !"
+      quit(2)
+  echo "true"
+
+block t6154:
+  let foo = """
+  <!DOCTYPE html>
+  <html>
+      <head>
+        <title> foobar </title>
+      </head>
+      <body>
+        <p class=foo id=bar></p>
+        <p something=&#9;foo&#9;bar&#178;></p>
+        <p something=  &#9;foo&#9;bar&#178; foo  =bloo></p>
+        <p class="foo2" id="bar2"></p>
+        <p wrong= ></p>
+        <p data-foo data-bar="correct!" enabled  ></p>
+        <p quux whatever></p>
+      </body>
+  </html>
+  """
+
+  var errors: seq[string] = @[]
+  let html = parseHtml(newStringStream(foo), "statichtml", errors=errors)
+  doAssert "statichtml(11, 18) Error: attribute value expected" in errors
+  let ps = html.findAll("p")
+  doAssert ps.len == 7
+
+  doAssert ps[0].attrsLen == 2
+  doAssert ps[0].attr("class") == "foo"
+  doAssert ps[0].attr("id") == "bar"
+  doAssert ps[0].len == 0
+
+  doAssert ps[1].attrsLen == 1
+  doAssert ps[1].attr("something") == "\tfoo\tbar²"
+  doAssert ps[1].len == 0
+
+  doAssert ps[2].attrsLen == 2
+  doAssert ps[2].attr("something") == "\tfoo\tbar²"
+  doAssert ps[2].attr("foo") == "bloo"
+  doAssert ps[2].len == 0
+
+  doAssert ps[3].attrsLen == 2
+  doAssert ps[3].attr("class") == "foo2"
+  doAssert ps[3].attr("id") == "bar2"
+  doAssert ps[3].len == 0
+
+  doAssert ps[4].attrsLen == 1
+  doAssert ps[4].attr("wrong") == ""
+
+  doAssert ps[5].attrsLen == 3
+  doAssert ps[5].attr("data-foo") == ""
+  doAssert ps[5].attr("data-bar") == "correct!"
+  doAssert ps[5].attr("enabled") == ""
+  doAssert ps[5].len == 0
+
+  doAssert ps[6].attrsLen == 2
+  doAssert ps[6].attr("quux") == ""
+  doAssert ps[6].attr("whatever") == ""
+  doAssert ps[6].len == 0
+
+# bug #11713, #1034
+var content = """
+# with &
+<img src="https://example.com/test?format=jpg&name=orig" alt="">
+<img src="https://example.com/test?format=jpg&name=orig" alt="text">
+
+# without &
+<img src="https://example.com/test?format=jpg" alt="text">
+"""
+
+var
+  stream = newStringStream(content)
+  body = parseHtml(stream)
+
+for y in body.findAll("img"):
+  echo y.attr("src"), "##", y.attr("alt")
diff --git a/tests/stdlib/thttpclient.nim b/tests/stdlib/thttpclient.nim
new file mode 100644
index 000000000..0bd479670
--- /dev/null
+++ b/tests/stdlib/thttpclient.nim
@@ -0,0 +1,187 @@
+discard """
+  cmd: "nim c --threads:on -d:ssl $file"
+  disabled: "openbsd"
+  disabled: "freebsd"
+  disabled: "windows"
+"""
+
+#[
+disabled: see https://github.com/timotheecour/Nim/issues/528
+]#
+
+import strutils
+from net import TimeoutError
+
+import nativesockets, os, httpclient, asyncdispatch
+
+import std/[assertions, syncio]
+from stdtest/testutils import enableRemoteNetworking
+
+const manualTests = false
+
+proc makeIPv6HttpServer(hostname: string, port: Port,
+    message: string): AsyncFD =
+  let fd = createNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+  proc onAccept(fut: Future[AsyncFD]) {.gcsafe.} =
+    if not fut.failed:
+      let clientFd = fut.read()
+      clientFd.send(message).callback = proc() =
+        clientFd.closeSocket()
+      serverFd.accept().callback = onAccept
+  serverFd.accept().callback = onAccept
+
+proc asyncTest() {.async.} =
+  var client = newAsyncHttpClient()
+  var resp = await client.request("http://example.com/", HttpGet)
+  doAssert(resp.code.is2xx)
+  var body = await resp.body
+  body = await resp.body # Test caching
+  doAssert("<title>Example Domain</title>" in body)
+
+  resp = await client.request("http://example.com/404")
+  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/")
+    doAssert(resp.code.is2xx or resp.code.is3xx)
+
+  # getContent
+  try:
+    discard await client.getContent("https://google.com/404")
+    doAssert(false, "HttpRequestError should have been raised")
+  except HttpRequestError:
+    discard
+  except:
+    doAssert(false, "HttpRequestError should have been raised")
+
+
+  when false:
+    # w3.org now blocks travis, so disabled:
+    # Multipart test.
+    var data = newMultipartData()
+    data["output"] = "soap12"
+    data["uploaded_file"] = ("test.html", "text/html",
+      "<html><head></head><body><p>test</p></body></html>")
+    resp = await client.post("http://validator.w3.org/check", multipart = data)
+    doAssert(resp.code.is2xx)
+
+  # onProgressChanged
+  when manualTests:
+    proc onProgressChanged(total, progress, speed: BiggestInt) {.async.} =
+      echo("Downloaded ", progress, " of ", total)
+      echo("Current rate: ", speed div 1000, "kb/s")
+    client.onProgressChanged = onProgressChanged
+    await client.downloadFile("http://speedtest-ams2.digitalocean.com/100mb.test",
+                              "100mb.test")
+
+  # HTTP/1.1 without Content-Length - issue #10726
+  var serverFd = makeIPv6HttpServer("::1", Port(18473),
+     "HTTP/1.1 200 \c\L" &
+     "\c\L" &
+     "Here comes reply")
+  resp = await client.request("http://[::1]:18473/")
+  body = await resp.body
+  doAssert(body == "Here comes reply")
+  serverFd.closeSocket()
+
+  client.close()
+
+  # Proxy test
+  #when manualTests:
+  #  client = newAsyncHttpClient(proxy = newProxy("http://51.254.106.76:80/"))
+  #  var resp = await client.request("https://github.com")
+  #  echo resp
+
+proc syncTest() =
+  var client = newHttpClient()
+  var resp = client.request("http://example.com/", HttpGet)
+  doAssert(resp.code.is2xx)
+  doAssert("<title>Example Domain</title>" in resp.body)
+
+  resp = client.request("http://example.com/404")
+  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/")
+    doAssert(resp.code.is2xx or resp.code.is3xx)
+
+  # getContent
+  try:
+    discard client.getContent("https://google.com/404")
+    doAssert(false, "HttpRequestError should have been raised")
+  except HttpRequestError:
+    discard
+  except:
+    doAssert(false, "HttpRequestError should have been raised")
+
+  when false:
+    # w3.org now blocks travis, so disabled:
+    # Multipart test.
+    var data = newMultipartData()
+    data["output"] = "soap12"
+    data["uploaded_file"] = ("test.html", "text/html",
+      "<html><head></head><body><p>test</p></body></html>")
+    resp = client.post("http://validator.w3.org/check", multipart = data)
+    doAssert(resp.code.is2xx)
+
+  # onProgressChanged
+  when manualTests:
+    proc onProgressChanged(total, progress, speed: BiggestInt) =
+      echo("Downloaded ", progress, " of ", total)
+      echo("Current rate: ", speed div 1000, "kb/s")
+    client.onProgressChanged = onProgressChanged
+    client.downloadFile("http://speedtest-ams2.digitalocean.com/100mb.test",
+                        "100mb.test")
+
+  client.close()
+
+  # SIGSEGV on HEAD body read: issue #16743
+  block:
+    let client = newHttpClient()
+    let resp = client.head("http://httpbin.org/head")
+    doAssert(resp.body == "")
+
+  when false:
+    # Disabled for now because it causes troubles with AppVeyor
+    # Timeout test.
+    client = newHttpClient(timeout = 1)
+    try:
+      resp = client.request("http://example.com/")
+      doAssert false, "TimeoutError should have been raised."
+    except TimeoutError:
+      discard
+    except:
+      doAssert false, "TimeoutError should have been raised."
+
+proc ipv6Test() =
+  var client = newAsyncHttpClient()
+  let serverFd = makeIPv6HttpServer("::1", Port(18473),
+    "HTTP/1.1 200 OK\r\LContent-Length: 0\r\LConnection: Closed\r\L\r\L")
+  var resp = waitFor client.request("http://[::1]:18473/")
+  doAssert(resp.status == "200 OK")
+  serverFd.closeSocket()
+  client.close()
+
+ipv6Test()
+
+when enableRemoteNetworking:
+  syncTest()
+  waitFor(asyncTest())
diff --git a/tests/stdlib/thttpclient_ssl.nim b/tests/stdlib/thttpclient_ssl.nim
new file mode 100644
index 000000000..6b963f029
--- /dev/null
+++ b/tests/stdlib/thttpclient_ssl.nim
@@ -0,0 +1,150 @@
+discard """
+  cmd: "nim $target --mm:refc -d:ssl $options $file"
+  disabled: "openbsd"
+"""
+
+#            Nim - Basic SSL integration tests
+#        (c) Copyright 2018 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Warning: this test performs local networking.
+## Test with:
+## ./bin/nim c -d:ssl -p:. --threads:on -r tests/stdlib/thttpclient_ssl.nim
+
+
+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
+    httpclient,
+    net,
+    openssl,
+    os,
+    strutils,
+    threadpool,
+    times,
+    unittest
+
+  # bogus self-signed certificate
+  const
+    certFile = "tests/stdlib/thttpclient_ssl_cert.pem"
+    keyFile = "tests/stdlib/thttpclient_ssl_key.pem"
+
+  proc log(msg: string) =
+    when defined(ssldebug):
+      echo "    [" & $epochTime() & "] " & msg
+    # FIXME
+    echo "    [" & $epochTime() & "] " & msg
+    discard
+
+  proc runServer(port: Port): bool {.thread.} =
+    ## Run a trivial HTTPS server in a {.thread.}
+    ## Exit after serving one request
+
+    var socket = newSocket()
+    socket.setSockOpt(OptReusePort, true)
+    socket.bindAddr(port)
+
+    var ctx = newContext(certFile=certFile, keyFile=keyFile)
+
+    ##  Handle one connection
+    socket.listen()
+
+    var client: Socket
+    var address = ""
+
+    log "server: ready"
+    socket.acceptAddr(client, address)
+    log "server: incoming connection"
+
+    var ssl: SslPtr = SSL_new(ctx.context)
+    discard SSL_set_fd(ssl, client.getFd())
+    log "server: accepting connection"
+    ErrClearError()
+    if SSL_accept(ssl) <= 0:
+      ERR_print_errors_fp(stderr)
+    else:
+      const reply = "HTTP/1.0 200 OK\r\nServer: test\r\nContent-type: text/html\r\nContent-Length: 0\r\n\r\n"
+      log "server: sending reply"
+      discard SSL_write(ssl, reply.cstring, reply.len)
+
+    log "server: receiving a line"
+    let line = client.recvLine()
+    log "server: received $# bytes" % $line.len
+    log "closing"
+    SSL_free(ssl)
+    close(client)
+    close(socket)
+    log "server: exited"
+
+
+  suite "SSL self signed certificate check":
+
+    test "TCP socket":
+      const port = 12347.Port
+      let t = spawn runServer(port)
+      sleep(100)
+      var sock = newSocket()
+      var ctx = newContext()
+      ctx.wrapSocket(sock)
+      try:
+        log "client: connect"
+        sock.connect("127.0.0.1", port)
+        fail()
+      except:
+        let msg = getCurrentExceptionMsg()
+        check(msg.contains("certificate verify failed"))
+
+    test "HttpClient default: no check":
+      const port = 12345.Port
+      let t = spawn runServer(port)
+      sleep(100)
+
+      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyNone))
+      try:
+        log "client: connect"
+        discard client.getContent("https://127.0.0.1:12345")
+      except:
+        let msg = getCurrentExceptionMsg()
+        log "client: unexpected exception: " & msg
+        fail()
+
+    test "HttpClient with CVerifyPeer":
+      const port = 12346.Port
+      let t = spawn runServer(port)
+      sleep(100)
+
+      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeer))
+      try:
+        log "client: connect"
+        discard client.getContent("https://127.0.0.1:12346")
+        log "getContent should have raised an exception"
+        fail()
+      except:
+        let msg = getCurrentExceptionMsg()
+        log "client: exception: " & msg
+        # SSL_shutdown:shutdown while in init
+        if not (msg.contains("alert number 48") or
+          msg.contains("certificate verify failed")):
+          echo "CVerifyPeer exception: " & msg
+          check(false)
+
+    test "HttpClient with CVerifyPeerUseEnvVars":
+      const port = 12346.Port
+      let t = spawn runServer(port)
+      sleep(100)
+
+      putEnv("SSL_CERT_FILE", getCurrentDir() / certFile)
+      var client = newHttpClient(sslContext=newContext(verifyMode=CVerifyPeerUseEnvVars))
+      try:
+        log "client: connect"
+        discard client.getContent("https://127.0.0.1:12346")
+      except:
+        let msg = getCurrentExceptionMsg()
+        log "client: exception: " & msg
+        log "getContent should not have raised an exception"
+        fail()
diff --git a/tests/stdlib/thttpclient_ssl_cert.pem b/tests/stdlib/thttpclient_ssl_cert.pem
new file mode 100644
index 000000000..f15c15c52
--- /dev/null
+++ b/tests/stdlib/thttpclient_ssl_cert.pem
@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIFCTCCAvGgAwIBAgIURYQOmGzeh3Vy7Gk6Go4uAPwcNwAwDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE5MDEyMzAwMTgzNFoXDTQ2MDYw
+OTAwMTgzNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEAzoEVEl7yqY+RqIagXDD4JB7LyONDvh8aJvBMnJVBgjaL
+JdkfQjvPGUzUkEbU5nc6u7lqFxzEv7hXrssQCB7TwJwfS2PT1Rj14IFlYPyw4DEe
+P1RVS/awurtv3jwumarVl7LR+IQfo59kJ/P8jZt8H3HscDbyhXcHeOWI6q+XlfdV
+mTUJVvABdUuOiIFjgfFVTpo+CKxy7c5caRDK7g1s9xB1/M9PUfJvHY1WrBWFOZf0
+Bl8iwn+ahuxfIVqsFL9leqLykgi1f4L20p7RaAK95TXCo3CszZm4Fsw9zhzkjoU7
+2h0nuYl197LZvRs3u/JJjzZERmsfVPIs5BtO8/MN1MvRn6hIGU5Q3kOVWqWxSkSl
+njrf+uwUdn/24uSCnygNeDuJzwW/2q4N9YI3oovqNIGpkT3FbAm7UKwI4lwhwmqw
+7WH+92ELj0BinmsMMRPD2OqvK+vzLVqwUIQkYug+Hjys6QGXMlrL0krrj7XOKSc3
+SvZa4j0S/Y5CKkw5xuZXxITsdaV6hGi3d/kuT+1ttOSfIIXJXDEiu4pYRfziKU1a
+8EhHMEajEi6ueLw7QmEPVx398erRwiUuP2y43yZ4mwVwvN3i5jlVztl4XsglDmQ+
+hahstVdMMA34K2rK0U8q8YjdYm+z99NmGEPYrS6Qnpr1xrICN83FOWFI0k7ttyMC
+AwEAAaNTMFEwHQYDVR0OBBYEFLqMY6eP3h3gu+ANs77xDBRnElxyMB8GA1UdIwQY
+MBaAFLqMY6eP3h3gu+ANs77xDBRnElxyMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAJS+wyy0r+tVAlCa6V/xxlCDtW9n6L2nsqJXEjME0VvwGs3m
+ima68LyTQJqCSjjxSotaNOYKzUu4vRA3JssV+fUDR+NpmhpRuM74XmO05HUQkp9U
+dBEHyXp2aRQ9LSdvHo5D+RW+J4sHFb3PbU8NPx/t5Dg7il92S2QJQz1jNl+Nezc6
+2O8Vt1YbvWXfqM47URTpnQbWoo38pI44AgAuW3QagucKWsyounmhx65XcdtLn99g
+oZt496pU+hBpYu/IpXuBKNC4FvOrXTWAPkAbbYP39UFyiKwIyTosK+qdbhBlt1xi
+bBPn6N1W9L2BvUwM8fEB/qBuR9UfcMsIYJsWbbXMfyeF6lbaP7xD01rm+yU5PMMI
+Co40abixMntz4J3T2ixdCptf0He1U/UegOHwG1ZGgQzvOG6qI/xkNktDaSA75KR7
+BvPV1CmZC4ovVo1L4STrwnoRz5J49PNOHi9Okj9zJ99H7nsmsK16oxpIYkYHJWn+
+45jpG8SlDp7oev1OGGk/z+ZOTz+LcNxyvsRQVN8w5zNmjCSWiGqz+UUgppCZg8qd
+ECWokNQ5Lr20t1whynrX5bH0l887WPCQmm5VduRoyKFGhCRBSzcCtowSpiwZglUk
+CV0jgFKoteItdzZgsND5I1GaNOxZlnK3wN4H0pgZv7HlW6SP1OYd2Y67waJ7
+-----END CERTIFICATE-----
diff --git a/tests/stdlib/thttpclient_ssl_key.pem b/tests/stdlib/thttpclient_ssl_key.pem
new file mode 100644
index 000000000..6ab04122c
--- /dev/null
+++ b/tests/stdlib/thttpclient_ssl_key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDOgRUSXvKpj5Go
+hqBcMPgkHsvI40O+Hxom8EyclUGCNosl2R9CO88ZTNSQRtTmdzq7uWoXHMS/uFeu
+yxAIHtPAnB9LY9PVGPXggWVg/LDgMR4/VFVL9rC6u2/ePC6ZqtWXstH4hB+jn2Qn
+8/yNm3wfcexwNvKFdwd45Yjqr5eV91WZNQlW8AF1S46IgWOB8VVOmj4IrHLtzlxp
+EMruDWz3EHX8z09R8m8djVasFYU5l/QGXyLCf5qG7F8hWqwUv2V6ovKSCLV/gvbS
+ntFoAr3lNcKjcKzNmbgWzD3OHOSOhTvaHSe5iXX3stm9Gze78kmPNkRGax9U8izk
+G07z8w3Uy9GfqEgZTlDeQ5VapbFKRKWeOt/67BR2f/bi5IKfKA14O4nPBb/arg31
+gjeii+o0gamRPcVsCbtQrAjiXCHCarDtYf73YQuPQGKeawwxE8PY6q8r6/MtWrBQ
+hCRi6D4ePKzpAZcyWsvSSuuPtc4pJzdK9lriPRL9jkIqTDnG5lfEhOx1pXqEaLd3
++S5P7W205J8ghclcMSK7ilhF/OIpTVrwSEcwRqMSLq54vDtCYQ9XHf3x6tHCJS4/
+bLjfJnibBXC83eLmOVXO2XheyCUOZD6FqGy1V0wwDfgrasrRTyrxiN1ib7P302YY
+Q9itLpCemvXGsgI3zcU5YUjSTu23IwIDAQABAoICAQCdR60/57cUs/dxjs/2R4nH
+IPl/ELEYzeGCRMVlATz6qwZCFmN7c8ghceX32SrwOWEvd2G5Jr0ndIS76YdVV/1Z
+ls8zAV5m0HL8wjDvtKYWqvJps5afm80w+++RKO8pNPcnahgIGsFqQszqrSbux7y6
+ym8VbJQ8WNMFHnWwoXpnyxCT9tQdNgE2UAzIJRwf7SpXCp0yx/1k6CZ0E0ksFGeo
+qQ3kNhUoyegdbvfTazSkD/rZG36C+uM73i36Xm/wAXKN/CuaVC3AZ4QMGNBPUr9F
+IzQSfY/vrCOMoZR1NoZRkmJqlogaBPsnZD34jRFfAYNLIz7PD2m2rhjIx4/Tt4wQ
+5mUwga9ud0ly5wSzswudw07mTYtsLbWrUn6QdFxSwbQ0tXh9PJrqCSJDmYIptuu/
+6zjg8hQLg7y37xMDMCdKtviHx+ndVpW3StTwB/z7lDA6yuYY6nYN0dJTJS3qQheo
+maPG4Xf4FBcD4Is73BjBCf3QR6WIv0ZOG3/GZ1OqLRrPg1u/3UJkpa4LE/6qNUxf
+zdBZSPyQZExBvOqdklEI+1OcqofmWq2n7Amct45buDbFryehEhfJ1HHtkXkTEsut
+azfQeaGem/jKxcTD+1bWs/Q5Nn+QFfKr0NFjXSLoITWQkgQD1qISw3DC72jYXlsm
+S4CmCDW1dHZlmWZq+Mh34QKCAQEA+2JFRa1yYZ0tPt88sOjJYyw9yUxB9Nv9cKrs
+kdkhKHKevF+0BUbRLfp9bod+Wlv66pgQi6ZGKkGD7lCam/3FIBlmmiG8AOoXdoGy
+t17XCzlYy348mnHra2X+JBAN51ivPemdlGZShLbNMkGdL1khtjHL9vSr1KgFn3F/
+8nstVQ9nzHTCK0HWpBGn/EK3dd8lcYZDd7Fcgjz7E3xQDz/XZt0HMwwGaLnQ1L7T
+glIyeNdqLBp4v0NT6L1AAk5rQJONo57AepblwacYhoW9mR5K0bm/BMo5+xwMtYz9
+69ZuMNW8qdaWrzeEsxM1PDbcOoVqChF10w0Ih/MkhKGpN/GxUQKCAQEA0kvWUkEK
+1BBhwGyuKrMnUC3jnQ36KpsjlryMUArdjS2gVBztGW2p2CUWasEgZdxpwQmnqKyz
+4hcZaU/JUleutTI5raxzju4Ve87c+koOiamhw/zaiLCpLn2j0Rh2qxp7QvPPRO0V
+1MN347wjCTx/5/j8WffgWqWfqdrd8JheKal/OHlTZA3DG77FIVnUyov8Np+lTd1x
+NpWr/AOreZlMBq/X/kmWCe+fP901fGdi3cdsKcJcdLPv9KFciSjBlAlaLMnBgLWo
+RrIuNxdH3dRX4rzBSpdNq72n8NaH+A10eoXrlC4eWLo7vRSTe4WRgUAIbhVifnJk
+z4B5FqC/aVgkMwKCAQEAtq983h0lcbDy76z2Ay65I/xDzqU/jX3OGfHtSDS+NxHN
+L+JxBiCn5b0TKJ8JAQu1NoVaCNLGTPEdurQTF+f9OM2c1chMQ3HbqUCqKz6eEscT
+M5dC3Y6KYptVbMnKAOVfPSQoY29U6qOaTbqHS6B/slNQAeFfeoS8yVmHfSVtFVLD
+wT7c2OjY3pUCOn4Vq3CGWpETOMnJC9DbOhbua5aeqF9aWwuTIMpg7CrdtOidS1pp
+CzIVrBF2yj22ZbatlNlmZpD5Gl3NDMWtOh25Yqwz/WP6YLXCGy4QQmP7KEfF/nFl
+0RtkmGNFaYo89sx7kX/hRv3XXZAsMfhOAqElQ8W+cQKCAQAdL/lnIS/njv6CPpNN
+yd/C+RuGSNJX54BhA3pWAawOVC7Ufc9KoDXakgsydeuRN65V5IkomA+/aYVVYIWI
+sDLHY1kuCalgRRsmO+fftTefU7PoB8gtAJf6o+WAt+yAgwRonn4+Csnk5dxV917F
+gWgfQieENSsmaaZnZME5C2zGS4gkxnIUiPRzfV7O6jDmi9dNnYrL69gyw0NDjx7V
+mbk7lFxeJsh0SJXJv2IVCiRms68HfLpoWDENuvek8cssSMADR11cB9p7NW/Epa6L
+01T/W0NYnvdgxsnwW1Yzz2pDNyMjReNgXTi9XYW6tyci0UhaPw2Ujzv+sM4dneHz
+NRCRAoIBAHqXaeC1uTGSzfLvRz81ifgDRP8H9L1HLt7ZWL6XMp1ph+P6yYFXM4JK
+WeP3cdKO/kQOD/fLuhYT92T2hHEadT8CQqpsBMQt29Zlm4oYWHB7ERiZqaGX3/T0
+U1TlL0WxthoHPY2HwA6pmDTmUzDk3tFlgk+XOmLsDacBdC6EsFwA+tyEPVxmkb0J
+H+j7D4NxwysAyWCB9fWU1FV+JJJel+nz88i7Gb8uJ+kSktnFxjv/G9p+OkDYlaUt
+j8lc6LOuNOA9M7XT1BIKpZytnSVtwZWkMmu23OLMM/d07tPJYtHIa92On7XKBPc2
+6THbQsJpR5AalTVvXs3X1RnCLnHiNYg=
+-----END PRIVATE KEY-----
diff --git a/tests/stdlib/thttpclient_standalone.nim b/tests/stdlib/thttpclient_standalone.nim
new file mode 100644
index 000000000..2f432eede
--- /dev/null
+++ b/tests/stdlib/thttpclient_standalone.nim
@@ -0,0 +1,59 @@
+discard """
+  cmd: "nim c --threads:on $file"
+"""
+
+import asynchttpserver, httpclient, asyncdispatch, strutils, net
+
+import std/assertions
+
+block: # bug #16436
+  proc startServer(): AsyncHttpServer =
+    result = newAsyncHttpServer()
+    result.listen(Port(0))
+
+  proc processRequest(server: AsyncHttpServer) {.async.} =
+    proc cb(req: Request) {.async.} =
+      let headers = { "Content-length": "15"} # Provide invalid content-length
+      await req.respond(Http200, "Hello World", headers.newHttpHeaders())
+
+    await server.acceptRequest(cb)
+
+  proc runClient(port: Port) {.async.} =
+    let c = newAsyncHttpClient(headers = {"Connection": "close"}.newHttpHeaders)
+    discard await c.getContent("http://127.0.0.1:" & $port)
+    doAssert false, "should fail earlier"
+
+  let server = startServer()
+  asyncCheck processRequest(server)
+  let port = server.getPort()
+  doAssertRaises(ProtocolError):
+    waitFor runClient(port)
+
+block: # bug #14794 (And test for presence of content-length header when using postContent)
+  proc startServer(): AsyncHttpServer =
+    result = newAsyncHttpServer()
+    result.listen(Port(0))
+
+  proc runServer(server: AsyncHttpServer) {.async.} =
+    proc cb(req: Request) {.async.} =
+      doAssert(req.body.endsWith(httpNewLine), "Multipart body does not end with a newline.")
+      # this next line is probably not required because asynchttpserver does not call
+      # the callback when there is no content-length header.  It instead errors with 
+      # Error: unhandled exception: 411 Length Required
+      # Added for good measure in case the server becomes more permissive.
+      doAssert(req.headers.hasKey("content-length"), "Content-Length header is not present.")
+      asyncCheck req.respond(Http200, "OK")
+
+    await server.acceptRequest(cb)
+
+  proc runClient(port: Port) {.async.} =
+    let c = newAsyncHttpClient()
+    let data = newMultipartData()
+    data.add("file.txt", "This is intended to be an example text file.\r\nThis would be the second line.\r\n")
+    discard await c.postContent("http://127.0.0.1:" & $port, multipart = data)
+    c.close()
+
+  let server = startServer()
+  let port = server.getPort()
+  asyncCheck runServer(server)
+  waitFor runClient(port)
diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim
new file mode 100644
index 000000000..93e7d85c6
--- /dev/null
+++ b/tests/stdlib/thttpcore.nim
@@ -0,0 +1,103 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import httpcore, strutils
+import std/assertions
+
+block:
+  block HttpCode:
+    doAssert $Http418 == "418 I'm a teapot"
+    doAssert Http418.is4xx() == true
+    doAssert Http418.is2xx() == false
+
+  block headers:
+    var h = newHttpHeaders()
+    doAssert h.len == 0
+    h.add("Cookie", "foo")
+    doAssert h.len == 1
+    doAssert h.hasKey("cooKIE")
+    doAssert h["Cookie"] == "foo"
+    doAssert h["cookie"] == "foo"
+    h["cookie"] = @["bar", "x"]
+    doAssert h["Cookie"] == "bar"
+    doAssert h["Cookie", 1] == "x"
+    doAssert h["Cookie"].contains("BaR") == true
+    doAssert h["Cookie"].contains("X") == true
+    doAssert "baR" in h["cookiE"]
+    h.del("coOKie")
+    doAssert h.len == 0
+
+    # Test that header constructor works with repeated values
+    let h1 = newHttpHeaders({"a": "1", "a": "2", "A": "3"})
+
+    doAssert seq[string](h1["a"]).join(",") == "1,2,3"
+
+  block test_cookies_with_comma:
+    doAssert parseHeader("cookie: foo, bar") ==  ("cookie", @["foo, bar"])
+    doAssert parseHeader("cookie: foo, bar, prologue") == ("cookie", @["foo, bar, prologue"])
+    doAssert parseHeader("cookie: foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"])
+
+    doAssert parseHeader("cookie:   foo, bar") ==  ("cookie", @["foo, bar"])
+    doAssert parseHeader("cookie:  foo, bar, prologue") == ("cookie", @["foo, bar, prologue"])
+    doAssert parseHeader("cookie:   foo, bar, prologue, starlight") == ("cookie", @["foo, bar, prologue, starlight"])
+
+    doAssert parseHeader("Cookie: foo, bar") == (key: "Cookie", value: @["foo, bar"])
+    doAssert parseHeader("Cookie: foo, bar, prologue") == (key: "Cookie", value: @["foo, bar, prologue"])
+    doAssert parseHeader("Cookie: foo, bar, prologue, starlight") == (key: "Cookie", value: @["foo, bar, prologue, starlight"])
+
+    doAssert parseHeader("Accept: foo, bar") == (key: "Accept", value: @["foo", "bar"])
+    doAssert parseHeader("Accept: foo, bar, prologue") == (key: "Accept", value: @["foo", "bar", "prologue"])
+    doAssert parseHeader("Accept: foo, bar, prologue, starlight") == (key: "Accept", value: @["foo", "bar", "prologue", "starlight"])
+
+  block add_empty_sequence_to_HTTP_headers:
+    block:
+      var headers = newHttpHeaders()
+      headers["empty"] = @[]
+
+      doAssert not headers.hasKey("empty")
+
+    block:
+      var headers = newHttpHeaders()
+      headers["existing"] = "true"
+      headers["existing"] = @[]
+
+      doAssert not headers.hasKey("existing")
+
+    block:
+      var headers = newHttpHeaders()
+      headers["existing"] = @["true"]
+      headers["existing"] = @[]
+
+      doAssert not headers.hasKey("existing")
+
+    block:
+      var headers = newHttpHeaders()
+      headers["existing"] = @[]
+      headers["existing"] = @["true"]
+      doAssert headers.hasKey("existing")
+
+block:
+  var test = newHttpHeaders()
+  test["Connection"] = @["Upgrade", "Close"]
+  doAssert test["Connection", 0] == "Upgrade"
+  doAssert test["Connection", 1] == "Close"
+  test.add("Connection", "Test")
+  doAssert test["Connection", 2] == "Test"
+  doAssert "upgrade" in test["Connection"]
+
+  # Bug #5344.
+  doAssert parseHeader("foobar: ") == ("foobar", @[""])
+  let (key, value) = parseHeader("foobar: ")
+  test = newHttpHeaders()
+  test[key] = value
+  doAssert test["foobar"] == ""
+
+  doAssert parseHeader("foobar:") == ("foobar", @[""])
+
+  block: # test title case
+    var testTitleCase = newHttpHeaders(titleCase=true)
+    testTitleCase.add("content-length", "1")
+    doAssert testTitleCase.hasKey("Content-Length")
+    for key, val in testTitleCase:
+        doAssert key == "Content-Length"
diff --git a/tests/stdlib/timportutils.nim b/tests/stdlib/timportutils.nim
new file mode 100644
index 000000000..672092282
--- /dev/null
+++ b/tests/stdlib/timportutils.nim
@@ -0,0 +1,151 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[importutils, assertions]
+import stdtest/testutils
+import mimportutils
+
+template main =
+  block: # privateAccess
+    assertAll:
+      var a: A
+      var b = initB() # B is private
+      compiles(a.a0)
+      compiles(b.b0)
+      not compiles(a.ha1)
+      not compiles(b.hb1)
+
+    block:
+      assertAll:
+        privateAccess A
+        compiles(a.ha1)
+        a.ha1 == 0.0
+        not compiles(a.hb1)
+        privateAccess b.typeof
+        b.hb1 = 3
+        type B2 = b.typeof
+        let b2 = B2(b0: 4, hb1: 5)
+        b.hb1 == 3
+        b2 == B2(b0: 4, hb1: 5)
+
+    assertAll:
+      not compiles(a.ha1)
+      not compiles(b.hb1)
+
+    block:
+      assertAll:
+        not compiles(C(c0: 1, hc1: 2))
+        privateAccess C
+        let c = C(c0: 1, hc1: 2)
+        c.hc1 == 2
+
+    block:
+      assertAll:
+        not compiles(E[int](he1: 1))
+        privateAccess E[int]
+        var e = E[int](he1: 1)
+        e.he1 == 1
+        e.he1 = 2
+        e.he1 == 2
+        e.he1 += 3
+        e.he1 == 5
+        # xxx caveat: this currently compiles but in future, we may want
+        # to make `privateAccess E[int]` only affect a specific instantiation;
+        # note that `privateAccess E` does work to cover all instantiations.
+        var e2 = E[float](he1: 1)
+
+    block:
+      assertAll:
+        not compiles(E[int](he1: 1))
+        privateAccess E
+        var e = E[int](he1: 1)
+        e.he1 == 1
+
+    block:
+      assertAll:
+        not compiles(F[int, int](h3: 1))
+        privateAccess F[int, int]
+        var e = F[int, int](h3: 1)
+        e.h3 == 1
+
+    block:
+      assertAll:
+        not compiles(F[int, int](h3: 1))
+        privateAccess F[int, int].default[].typeof
+        var e = F[int, int](h3: 1)
+        e.h3 == 1
+
+    block:
+      assertAll:
+        var a = G[int]()
+        var b = a.addr
+        privateAccess b.type
+        discard b.he1
+        discard b[][].he1
+
+    block:
+      assertAll:
+        privateAccess H[int]
+        var a = H[int](h5: 2)
+
+    block:
+      assertAll:
+        privateAccess PA
+        var pa = PA(a0: 1, ha1: 2)
+        pa.ha1 == 2
+        pa.ha1 = 3
+        pa.ha1 == 3
+
+    block:
+      assertAll:
+        var b = BAalias()
+        not compiles(b.hb1)
+        privateAccess BAalias
+        discard b.hb1
+
+    block:
+      assertAll:
+        var a = A(a0: 1)
+        var a2 = a.addr
+        not compiles(a2.ha1)
+        privateAccess PtA
+        a2.type is PtA
+        a2.ha1 = 2
+        a2.ha1 == 2
+        a.ha1 = 3
+        a2.ha1 == 3
+
+    block:
+      disableVm:
+        assertAll:
+          var a = A.create()
+          defer: dealloc(a)
+          a is PtA
+          a.typeof is PtA
+          not compiles(a.ha1)
+          privateAccess a.typeof
+          a.ha1 = 2
+          a.ha1 == 2
+          a[].ha1 = 3
+          a.ha1 == 3
+
+    block:
+      disableVm:
+        assertAll:
+          var a = A.create()
+          defer: dealloc(a)
+          privateAccess PtA
+          a.ha1 == 0
+
+    block:
+      privateAccess PityRef
+      let x = PityRef[int](a: 1)  # works
+      doAssert x.a == 1
+
+      privateAccess Hope
+      let y = Hope[int](a: 1)
+      doAssert y.a == 1
+
+static: main()
+main()
diff --git a/tests/stdlib/tintsets.nim b/tests/stdlib/tintsets.nim
new file mode 100644
index 000000000..191ef117e
--- /dev/null
+++ b/tests/stdlib/tintsets.nim
@@ -0,0 +1,6 @@
+import ./mintsets
+
+block: # bug https://github.com/nim-lang/Nim/pull/15564#issuecomment-729878104
+  # related to bug #11167
+  test1()
+  test2()
diff --git a/tests/stdlib/tio.nim b/tests/stdlib/tio.nim
new file mode 100644
index 000000000..80a119763
--- /dev/null
+++ b/tests/stdlib/tio.nim
@@ -0,0 +1,60 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+# xxx move to here other tests that belong here; io is a proper module
+
+import std/os
+from stdtest/specialpaths import buildDir
+import std/[assertions, syncio]
+
+block: # readChars
+  let file = buildDir / "D20201118T205105.txt"
+  let s = "he\0l\0lo"
+  writeFile(file, s)
+  defer: removeFile(file)
+  let f = open(file)
+  defer: close(f)
+  let n = f.getFileInfo.blockSize
+  var buf = newString(n)
+  template fn =
+    let n2 = f.readChars(buf)
+    doAssert n2 == s.len
+    doAssert buf[0..<n2] == s
+  fn()
+  setFilePos(f, 0)
+  fn()
+
+  block:
+    setFilePos(f, 0)
+    var s2: string
+    let nSmall = 2
+    for ai in buf.mitems: ai = '\0'
+    var n2s: seq[int]
+    while true:
+      let n2 = f.readChars(toOpenArray(buf, 0, nSmall-1))
+      # xxx: maybe we could support: toOpenArray(buf, 0..nSmall)
+      n2s.add n2
+      s2.add buf[0..<n2]
+      if n2 == 0:
+        break
+    doAssert n2s == @[2,2,2,1,0]
+    doAssert s2 == s
+
+
+import std/strutils
+
+block: # bug #21273
+  let FILE = buildDir / "D20220119T134305.txt"
+
+  let hex = "313632313920313632343720313632353920313632363020313632393020323035363520323037323120323131353020323239393820323331303520323332313020323332343820323332363820"
+
+
+  writeFile FILE, parseHexStr(hex)
+
+  doAssert readFile(FILE).toHex == hex
+
+  let f = open(FILE)
+  var s = newString(80)
+  while f.readLine(s):
+    doAssert s.toHex == hex
diff --git a/tests/stdlib/tisolation.nim b/tests/stdlib/tisolation.nim
new file mode 100644
index 000000000..18b83ea2e
--- /dev/null
+++ b/tests/stdlib/tisolation.nim
@@ -0,0 +1,135 @@
+discard """
+  targets: "c cpp"
+  matrix: "--gc:refc; --gc:orc"
+"""
+
+import std/[isolation, json]
+import std/[assertions, objectdollar]
+
+
+proc main(moveZeroesOut: static bool) =
+  block:
+    type
+      Empty = ref object
+
+
+    var x = isolate(Empty())
+    discard extract(x)
+
+  block: # string literals
+    var data = isolate("string")
+    doAssert data.extract == "string"
+    if moveZeroesOut:
+      doAssert data.extract == ""
+
+  block: # string literals
+    var data = isolate("")
+    doAssert data.extract == ""
+    if moveZeroesOut:
+      doAssert data.extract == ""
+
+  block:
+    var src = "string"
+    var data = isolate(move src)
+    doAssert data.extract == "string"
+    if moveZeroesOut:
+      doAssert src.len == 0
+
+  block: # int literals
+    var data = isolate(1)
+    doAssert data.extract == 1
+    if moveZeroesOut:
+      doAssert data.extract == 0
+
+  block: # float literals
+    var data = isolate(1.6)
+    doAssert data.extract == 1.6
+    if moveZeroesOut:
+      doAssert data.extract == 0.0
+
+  block:
+    var data = isolate(@["1", "2"])
+    doAssert data.extract == @["1", "2"]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var data = isolate(@["1", "2", "3", "4", "5"])
+    doAssert data.extract == @["1", "2", "3", "4", "5"]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var data = isolate(@["", ""])
+    doAssert data.extract == @["", ""]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var src = @["1", "2"]
+    var data = isolate(move src)
+    doAssert data.extract == @["1", "2"]
+    if moveZeroesOut:
+      doAssert src.len == 0
+
+  block:
+    var data = isolate(@[1, 2])
+    doAssert data.extract == @[1, 2]
+    if moveZeroesOut:
+      doAssert data.extract == @[]
+
+  block:
+    var data = isolate(["1", "2"])
+    doAssert data.extract == ["1", "2"]
+    if moveZeroesOut:
+      doAssert data.extract == ["", ""]
+
+  block:
+    var data = isolate([1, 2])
+    doAssert data.extract == [1, 2]
+    if moveZeroesOut:
+      doAssert data.extract == [0, 0]
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var data = isolate(Test(id: 12))
+    doAssert data.extract.id == 12
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var src = Test(id: 12)
+    var data = isolate(src)
+    doAssert data.extract.id == 12
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var src = Test(id: 12)
+    var data = isolate(move src)
+    doAssert data.extract.id == 12
+
+  block:
+    type
+      Test = ref object
+        id: int
+
+    var data = isolate(Test(id: 12))
+    doAssert data.extract.id == 12
+
+  block:
+    var x: seq[Isolated[JsonNode]]
+    x.add isolate(newJString("1234"))
+
+    doAssert $x == """@[(value: "1234")]"""
+
+
+static: main(moveZeroesOut = false)
+main(moveZeroesOut = true)
diff --git a/tests/stdlib/tjsbigints.nim b/tests/stdlib/tjsbigints.nim
new file mode 100644
index 000000000..29b0ac3e7
--- /dev/null
+++ b/tests/stdlib/tjsbigints.nim
@@ -0,0 +1,46 @@
+discard """
+  targets: "js"
+"""
+
+import std/[jsbigints, assertions]
+
+
+let big1: JsBigInt = big"2147483647"
+let big2: JsBigInt = big"666"
+var big3: JsBigInt = big"2"
+
+doAssert big3 == big"2"
+doAssert (big3 xor big2) == big"664"
+doAssert (big"555" and big"2") == big"2"
+doAssert (big"555" or big"2") == big"555"
+doAssert (big1 mod big2) == big"613"
+doAssert -big1 == big"-2147483647"
+doAssert big1 div big2 == big"3224449"
+doAssert big1 + big2 == big"2147484313"
+doAssert big1 - big2 == big"2147482981"
+doAssert big1 shl big3 == big"8589934588"
+doAssert big1 shr big3 == big"536870911"
+doAssert big1 * big2 == big"1430224108902"
+doAssert $big1 == "2147483647n"
+doAssert big1.toCstring(10) == "2147483647".cstring
+doAssert big2 ** big3 == big(443556)
+var huge = big"999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
+huge.inc
+huge = huge + -999999999999999999999999999999999999999999999999999999999999999999999999999999999999999'big
+doAssert huge == big"1"
+var list: seq[JsBigInt]
+for i in big"0" .. big"5":
+  doAssert i is JsBigInt
+  list.add i
+doAssert list == @[big"0", big"1", big"2", big"3", big"4", big"5"]
+list = @[]
+for i in big"0" ..< big"5":
+  doAssert i is JsBigInt
+  list.add i
+doAssert list == @[big"0", big"1", big"2", big"3", big"4"]
+
+block:
+  let b = 2'big
+  doAssert -b ** 3'big == -8'big
+  doAssert -b ** big"2" == big"4" # not -4 because of precedence
+  doAssert -big"3" == big"-3"
diff --git a/tests/stdlib/tjson.nim b/tests/stdlib/tjson.nim
new file mode 100644
index 000000000..e425501f6
--- /dev/null
+++ b/tests/stdlib/tjson.nim
@@ -0,0 +1,382 @@
+discard """
+  matrix: "; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+"""
+
+
+#[
+Note: Macro tests are in tests/stdlib/tjsonmacro.nim
+]#
+
+import std/[json,parsejson,strutils]
+import std/private/jsutils
+from std/math import isNaN
+when not defined(js):
+  import std/streams
+import stdtest/testutils
+from std/fenv import epsilon
+import std/[assertions, objectdollar]
+
+proc testRoundtrip[T](t: T, expected: string) =
+  # checks that `T => json => T2 => json2` is such that json2 = json
+  let j = %t
+  doAssert $j == expected, $j
+  doAssert %(j.to(T)) == j
+
+proc testRoundtripVal[T](t: T, expected: string) =
+  # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T`
+  # note that this isn't always possible, e.g. for pointer-like types or nans
+  let j = %t
+  doAssert $j == expected, $j
+  let j2 = ($j).parseJson
+  doAssert $j2 == expected, $(j2, t)
+  let t2 = j2.to(T)
+  doAssert t2 == t
+  doAssert $(%* t2) == expected # sanity check, because -0.0 = 0.0 but their json representation differs
+
+let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd", "c": "\ud83c\udf83", "d": "\u00E6"}"""
+# nil passthrough
+doAssert(testJson{"doesnt_exist"}{"anything"}.isNil)
+testJson{["e", "f"]} = %true
+doAssert(testJson["e"]["f"].bval)
+
+# make sure UTF-16 decoding works.
+doAssert(testJson["c"].str == "🎃")
+doAssert(testJson["d"].str == "æ")
+
+# make sure no memory leek when parsing invalid string
+let startMemory = getOccupiedMem()
+for i in 0 .. 10000:
+  try:
+    discard parseJson"""{ invalid"""
+  except:
+    discard
+# memory diff should less than 4M
+doAssert(abs(getOccupiedMem() - startMemory) < 4 * 1024 * 1024)
+
+
+# test `$`
+let stringified = $testJson
+let parsedAgain = parseJson(stringified)
+doAssert(parsedAgain["b"].str == "asd")
+
+parsedAgain["abc"] = %5
+doAssert parsedAgain["abc"].num == 5
+
+# Bounds checking
+when compileOption("boundChecks"):
+  try:
+    let a = testJson["a"][9]
+    doAssert(false, "IndexDefect not thrown")
+  except IndexDefect:
+    discard
+  try:
+    let a = testJson["a"][-1]
+    doAssert(false, "IndexDefect not thrown")
+  except IndexDefect:
+    discard
+  try:
+    doAssert(testJson["a"][0].num == 1, "Index doesn't correspond to its value")
+  except:
+    doAssert(false, "IndexDefect thrown for valid index")
+
+doAssert(testJson{"b"}.getStr() == "asd", "Couldn't fetch a singly nested key with {}")
+doAssert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
+doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+doAssert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
+doAssert(testJson{"a"} == parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
+doAssert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
+
+# Generator:
+var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
+doAssert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+var j2 = %*
+  [
+    {
+      "name": "John",
+      "age": 30
+    },
+    {
+      "name": "Susan",
+      "age": 31
+    }
+  ]
+doAssert j2 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+var name = "John"
+let herAge = 30
+const hisAge = 31
+
+var j3 = %*
+  [ {"name": "John"
+    , "age": herAge
+    }
+  , {"name": "Susan"
+    , "age": hisAge
+    }
+  ]
+doAssert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
+
+var j4 = %*{"test": nil}
+doAssert j4 == %{"test": newJNull()}
+
+let seqOfNodes = @[%1, %2]
+let jSeqOfNodes = %seqOfNodes
+doAssert(jSeqOfNodes[1].num == 2)
+
+type MyObj = object
+  a, b: int
+  s: string
+  f32: float32
+  f64: float64
+  next: ref MyObj
+var m: MyObj
+m.s = "hi"
+m.a = 5
+let jMyObj = %m
+doAssert(jMyObj["a"].num == 5)
+doAssert(jMyObj["s"].str == "hi")
+
+# Test loading of file.
+when not defined(js):
+  var parsed = parseFile("tests/testdata/jsontest.json")
+
+  try:
+    discard parsed["key2"][12123]
+    doAssert(false)
+  except IndexDefect: doAssert(true)
+
+  var parsed2 = parseFile("tests/testdata/jsontest2.json")
+  doAssert(parsed2{"repository", "description"}.str ==
+      "IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
+
+doAssert escapeJsonUnquoted("\10Foo🎃barÄ") == "\\nFoo🎃barÄ"
+doAssert escapeJsonUnquoted("\0\7\20") == "\\u0000\\u0007\\u0014" # for #7887
+doAssert escapeJson("\10Foo🎃barÄ") == "\"\\nFoo🎃barÄ\""
+doAssert escapeJson("\0\7\20") == "\"\\u0000\\u0007\\u0014\"" # for #7887
+
+# Test with extra data
+when not defined(js):
+  try:
+    discard parseJson("123 456")
+    doAssert(false)
+  except JsonParsingError:
+    doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
+
+  try:
+    discard parseFile("tests/testdata/jsonwithextradata.json")
+    doAssert(false)
+  except JsonParsingError:
+    doAssert getCurrentExceptionMsg().contains(errorMessages[errEofExpected])
+
+# bug #6438
+doAssert($ %*[] == "[]")
+doAssert($ %*{} == "{}")
+
+doAssert(not compiles(%{"error": "No messages"}))
+
+# bug #9111
+block:
+  type
+    Bar = string
+    Foo = object
+      a: int
+      b: Bar
+
+  let
+    js = """{"a": 123, "b": "abc"}""".parseJson
+    foo = js.to Foo
+
+  doAssert(foo.b == "abc")
+
+# Generate constructors for range[T] types
+block:
+  type
+    Q1 = range[0'u8 .. 50'u8]
+    Q2 = range[0'u16 .. 50'u16]
+    Q3 = range[0'u32 .. 50'u32]
+    Q4 = range[0'i8 .. 50'i8]
+    Q5 = range[0'i16 .. 50'i16]
+    Q6 = range[0'i32 .. 50'i32]
+    Q7 = range[0'f32 .. 50'f32]
+    Q8 = range[0'f64 .. 50'f64]
+    Q9 = range[0 .. 50]
+
+    X = object
+      m1: Q1
+      m2: Q2
+      m3: Q3
+      m4: Q4
+      m5: Q5
+      m6: Q6
+      m7: Q7
+      m8: Q8
+      m9: Q9
+
+  let obj = X(
+    m1: Q1(42),
+    m2: Q2(42),
+    m3: Q3(42),
+    m4: Q4(42),
+    m5: Q5(42),
+    m6: Q6(42),
+    m7: Q7(42),
+    m8: Q8(42),
+    m9: Q9(42)
+  )
+
+  doAssert(obj == to(%obj, type(obj)))
+
+  when not defined(js):
+    const fragments = """[1,2,3] {"hi":3} 12 [] """
+    var res = ""
+    for x in parseJsonFragments(newStringStream(fragments)):
+      res.add($x)
+      res.add " "
+    doAssert res == fragments
+
+
+# test isRefSkipDistinct
+type
+  MyRef = ref object
+  MyObject = object
+  MyDistinct = distinct MyRef
+  MyOtherDistinct = distinct MyRef
+
+var x0: ref int
+var x1: MyRef
+var x2: MyObject
+var x3: MyDistinct
+var x4: MyOtherDistinct
+
+doAssert isRefSkipDistinct(x0)
+doAssert isRefSkipDistinct(x1)
+doAssert not isRefSkipDistinct(x2)
+doAssert isRefSkipDistinct(x3)
+doAssert isRefSkipDistinct(x4)
+
+
+doAssert isRefSkipDistinct(ref int)
+doAssert isRefSkipDistinct(MyRef)
+doAssert not isRefSkipDistinct(MyObject)
+doAssert isRefSkipDistinct(MyDistinct)
+doAssert isRefSkipDistinct(MyOtherDistinct)
+
+let x = parseJson("9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
+
+doAssert x.kind == JString
+
+block: # bug #15835
+  type
+    Foo = object
+      ii*: int
+      data*: JsonNode
+
+  block:
+    const jt = """{"ii": 123, "data": ["some", "data"]}"""
+    let js = parseJson(jt)
+    discard js.to(Foo)
+
+  block:
+    const jt = """{"ii": 123}"""
+    let js = parseJson(jt)
+    doAssertRaises(KeyError):
+      echo js.to(Foo)
+
+type
+  ContentNodeKind* = enum
+    P,
+    Br,
+    Text,
+  ContentNode* = object
+    case kind*: ContentNodeKind
+    of P: pChildren*: seq[ContentNode]
+    of Br: nil
+    of Text: textStr*: string
+
+let mynode = ContentNode(kind: P, pChildren: @[
+  ContentNode(kind: Text, textStr: "mychild"),
+  ContentNode(kind: Br)
+])
+
+doAssert $mynode == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])"""
+
+let jsonNode = %*mynode
+doAssert $jsonNode == """{"kind":"P","pChildren":[{"kind":"Text","textStr":"mychild"},{"kind":"Br"}]}"""
+doAssert $jsonNode.to(ContentNode) == """(kind: P, pChildren: @[(kind: Text, textStr: "mychild"), (kind: Br)])"""
+
+block: # bug #17383
+  testRoundtrip(int32.high): "2147483647"
+  testRoundtrip(uint32.high): "4294967295"
+  when int.sizeof == 4:
+    testRoundtrip(int.high): "2147483647"
+    testRoundtrip(uint.high): "4294967295"
+  else:
+    testRoundtrip(int.high): "9223372036854775807"
+    testRoundtrip(uint.high): "18446744073709551615"
+  whenJsNoBigInt64: discard
+  do:
+    testRoundtrip(int64.high): "9223372036854775807"
+    testRoundtrip(uint64.high): "18446744073709551615"
+
+block: # bug #18007
+  testRoundtrip([NaN, Inf, -Inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+  # pending https://github.com/nim-lang/Nim/issues/18025 use:
+  # testRoundtrip([float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0])
+  let inf = float32(Inf)
+  testRoundtrip([float32(NaN), inf, -inf, 0.0, -0.0, 1.0]): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+  when not defined(js): # because of Infinity vs inf
+    testRoundtripVal([inf, -inf, 0.0, -0.0, 1.0]): """["inf","-inf",0.0,-0.0,1.0]"""
+  let a = parseJson($(%NaN)).to(float)
+  doAssert a.isNaN
+
+  whenRuntimeJs: discard # refs bug #18009
+  do:
+    testRoundtripVal(0.0): "0.0"
+    testRoundtripVal(-0.0): "-0.0"
+
+block: # bug #15397, bug #13196
+  testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002"
+  testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568"
+
+block:
+  let a = "18446744073709551615"
+  let b = a.parseJson
+  doAssert b.kind == JString
+  let c = $b
+  when defined(js):
+    doAssert c == "18446744073709552000"
+  else:
+    doAssert c == "18446744073709551615"
+
+block:
+  let a = """
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+    [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
+"""
+
+  when not defined(js):
+    try:
+      discard parseJson(a)
+    except JsonParsingError:
+      doAssert getCurrentExceptionMsg().contains("] expected")
diff --git a/tests/stdlib/tjsonexternproc.nim b/tests/stdlib/tjsonexternproc.nim
new file mode 100644
index 000000000..1091d72cd
--- /dev/null
+++ b/tests/stdlib/tjsonexternproc.nim
@@ -0,0 +1,11 @@
+discard """
+output: '''
+{"data":[1]}
+'''
+"""
+
+# Test case for https://github.com/nim-lang/Nim/issues/6385
+
+import mjsonexternproc
+# import json
+foo(1)
diff --git a/tests/stdlib/tjsonmacro.nim b/tests/stdlib/tjsonmacro.nim
new file mode 100644
index 000000000..5a1b4b294
--- /dev/null
+++ b/tests/stdlib/tjsonmacro.nim
@@ -0,0 +1,650 @@
+discard """
+  output: ""
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import json, strutils, options, tables
+import std/assertions
+
+# The definition of the `%` proc needs to be here, since the `% c` calls below
+# can only find our custom `%` proc for `Pix` if defined in global scope.
+type
+  Pix = tuple[x, y: uint8, ch: uint16]
+proc `%`(p: Pix): JsonNode =
+  result = %* { "x" : % p.x,
+                "y" : % p.y,
+                "ch" : % p.ch }
+
+proc testJson() =
+  # Tests inspired by own use case (with some additional tests).
+  # This should succeed.
+  type
+    Point[T] = object
+      x, y: T
+
+    ReplayEventKind = enum
+      FoodAppeared, FoodEaten, DirectionChanged
+
+    ReplayEvent = object
+      time*: float
+      case kind*: ReplayEventKind
+      of FoodAppeared, FoodEaten:
+        foodPos*: Point[float]
+        case subKind*: bool
+        of true:
+          it: int
+        of false:
+          ot: float
+      of DirectionChanged:
+        playerPos*: float
+
+    Replay = ref object
+      events*: seq[ReplayEvent]
+      test: int
+      test2: string
+      test3: bool
+      testNil: string
+
+  var x = Replay(
+    events: @[
+      ReplayEvent(
+        time: 1.2345,
+        kind: FoodEaten,
+        foodPos: Point[float](x: 5.0, y: 1.0),
+        subKind: true,
+        it: 7
+      )
+    ],
+    test: 18827361,
+    test2: "hello world",
+    test3: true,
+    testNil: "nil"
+  )
+
+  let node = %x
+
+  let y = to(node, Replay)
+  doAssert y.events[0].time == 1.2345
+  doAssert y.events[0].kind == FoodEaten
+  doAssert y.events[0].foodPos.x == 5.0
+  doAssert y.events[0].foodPos.y == 1.0
+  doAssert y.test == 18827361
+  doAssert y.test2 == "hello world"
+  doAssert y.test3
+  doAssert y.testNil == "nil"
+
+  # Test for custom object variants (without an enum) and with an else branch.
+  block:
+    type
+      TestVariant = object
+        name: string
+        case age: uint8
+        of 2:
+          preSchool: string
+        of 8:
+          primarySchool: string
+        else:
+          other: int
+
+    var node = %{
+      "name": %"Nim",
+      "age": %8,
+      "primarySchool": %"Sandtown"
+    }
+
+    var result = to(node, TestVariant)
+    doAssert result.age == 8
+    doAssert result.name == "Nim"
+    doAssert result.primarySchool == "Sandtown"
+
+    node = %{
+      "name": %"âš”ï¸Foo☢ï¸",
+      "age": %25,
+      "other": %98
+    }
+
+    result = to(node, TestVariant)
+    doAssert result.name == node["name"].getStr()
+    doAssert result.age == node["age"].getInt().uint8
+    doAssert result.other == node["other"].getBiggestInt()
+
+  # TODO: Test object variant with set in of branch.
+  # TODO: Should we support heterogeneous arrays?
+
+  # Tests that verify the error messages for invalid data.
+  block:
+    type
+      Person = object
+        name: string
+        age: int
+
+    var node = %{
+      "name": %"Dominik"
+    }
+
+    try:
+      discard to(node, Person)
+      doAssert false
+    except KeyError as exc:
+      doAssert("age" in exc.msg)
+    except:
+      doAssert false
+
+    node["age"] = %false
+
+    try:
+      discard to(node, Person)
+      doAssert false
+    except JsonKindError as exc:
+      doAssert("age" in exc.msg)
+    except:
+      doAssert false
+
+    type
+      PersonAge = enum
+        Fifteen, Sixteen
+
+      PersonCase = object
+        name: string
+        case age: PersonAge
+        of Fifteen:
+          discard
+        of Sixteen:
+          id: string
+
+    try:
+      discard to(node, PersonCase)
+      doAssert false
+    except JsonKindError as exc:
+      doAssert("age" in exc.msg)
+    except:
+      doAssert false
+
+  # Test the example in json module.
+  block:
+    let jsonNode = parseJson("""
+      {
+        "person": {
+          "name": "Nimmer",
+          "age": 21
+        },
+        "list": [1, 2, 3, 4]
+      }
+    """)
+
+    type
+      Person = object
+        name: string
+        age: int
+
+      Data1 = object # TODO: Codegen bug when changed to ``Data``.
+        person: Person
+        list: seq[int]
+
+    var data = to(jsonNode, Data1)
+    doAssert data.person.name == "Nimmer"
+    doAssert data.person.age == 21
+    doAssert data.list == @[1, 2, 3, 4]
+
+  # Test non-variant enum fields.
+  block:
+    type
+      EnumType = enum
+        Foo, Bar
+
+      TestEnum = object
+        field: EnumType
+
+    var node = %{
+      "field": %"Bar"
+    }
+
+    var result = to(node, TestEnum)
+    doAssert result.field == Bar
+
+  # Test ref type in field.
+  block:
+    var jsonNode = parseJson("""
+      {
+        "person": {
+          "name": "Nimmer",
+          "age": 21
+        },
+        "list": [1, 2, 3, 4]
+      }
+    """)
+
+    type
+      Person = ref object
+        name: string
+        age: int
+
+      Data = object
+        person: Person
+        list: seq[int]
+
+    var data = to(jsonNode, Data)
+    doAssert data.person.name == "Nimmer"
+    doAssert data.person.age == 21
+    doAssert data.list == @[1, 2, 3, 4]
+
+    jsonNode = parseJson("""
+      {
+        "person": null,
+        "list": [1, 2, 3, 4]
+      }
+    """)
+    data = to(jsonNode, Data)
+    doAssert data.person.isNil
+
+  block:
+    type
+      FooBar = object
+        field: float
+
+    let x = parseJson("""{ "field": 5}""")
+    let data = to(x, FooBar)
+    doAssert data.field == 5.0
+
+  block:
+    type
+      BirdColor = object
+        name: string
+        rgb: array[3, float]
+
+    type
+      Bird = object
+        age: int
+        height: float
+        name: string
+        colors: array[2, BirdColor]
+
+    var red = BirdColor(name: "red", rgb: [1.0, 0.0, 0.0])
+    var blue = BirdColor(name: "blue", rgb: [0.0, 0.0, 1.0])
+    var b = Bird(age: 3, height: 1.734, name: "bardo", colors: [red, blue])
+    let jnode = %b
+    let data = jnode.to(Bird)
+    doAssert data == b
+
+  block:
+    type
+      MsgBase = ref object of RootObj
+        name*: string
+
+      MsgChallenge = ref object of MsgBase
+        challenge*: string
+
+    let data = %*{"name": "foo", "challenge": "bar"}
+    let msg = data.to(MsgChallenge)
+    doAssert msg.name == "foo"
+    doAssert msg.challenge == "bar"
+
+  block:
+    type
+      Color = enum Red, Brown
+      Thing = object
+        animal: tuple[fur: bool, legs: int]
+        color: Color
+
+    var j = parseJson("""
+      {"animal":{"fur":true,"legs":6},"color":"Red"}
+    """)
+
+    let parsed = to(j, Thing)
+    doAssert parsed.animal.fur
+    doAssert parsed.animal.legs == 6
+    doAssert parsed.color == Red
+
+  block:
+    when not defined(js):
+      # disable on js because of #12492
+      type
+        Car = object
+          engine: tuple[name: string, capacity: float]
+          model: string
+
+      let j = """
+        {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"}
+      """
+
+      var i = 0
+      proc mulTest(): JsonNode =
+        inc i
+        return parseJson(j)
+
+      let parsed = mulTest().to(Car)
+      doAssert parsed.engine.name == "V8"
+
+      doAssert i == 1
+
+  block:
+    # Option[T] support!
+    type
+      Car1 = object # TODO: Codegen bug when `Car`
+        engine: tuple[name: string, capacity: Option[float]]
+        model: string
+        year: Option[int]
+
+    let noYear = """
+      {"engine": {"name": "V8", "capacity": 5.5}, "model": "Skyline"}
+    """
+
+    let noYearParsed = parseJson(noYear)
+    let noYearDeser = to(noYearParsed, Car1)
+    doAssert noYearDeser.engine.capacity == some(5.5)
+    doAssert noYearDeser.year.isNone
+    doAssert noYearDeser.engine.name == "V8"
+
+    # Issue #7433
+    type
+      Obj2 = object
+        n1: int
+        n2: Option[string]
+        n3: bool
+
+    var j = %*[ { "n1": 4, "n2": "ABC", "n3": true },
+                { "n1": 1, "n3": false },
+                { "n1": 1, "n2": "XYZ", "n3": false } ]
+
+    let jDeser = j.to(seq[Obj2])
+    doAssert jDeser[0].n2.get() == "ABC"
+    doAssert jDeser[1].n2.isNone()
+
+    # Issue #6902
+    type
+      Obj = object
+        n1: int
+        n2: Option[int]
+        n3: Option[string]
+        n4: Option[bool]
+
+    var j0 = parseJson("""{"n1": 1, "n2": null, "n3": null, "n4": null}""")
+    let j0Deser = j0.to(Obj)
+    doAssert j0Deser.n1 == 1
+    doAssert j0Deser.n2.isNone()
+    doAssert j0Deser.n3.isNone()
+    doAssert j0Deser.n4.isNone()
+
+  # Table[T, Y] support.
+  block:
+    type
+      Friend = object
+        name: string
+        age: int
+
+      Dynamic = object
+        name: string
+        friends: Table[string, Friend]
+
+    let data = """
+      {"friends": {
+                    "John": {"name": "John", "age": 35},
+                    "Elizabeth": {"name": "Elizabeth", "age": 23}
+                  }, "name": "Dominik"}
+    """
+
+    let dataParsed = parseJson(data)
+    let dataDeser = to(dataParsed, Dynamic)
+    doAssert dataDeser.name == "Dominik"
+    doAssert dataDeser.friends["John"].age == 35
+    doAssert dataDeser.friends["Elizabeth"].age == 23
+
+  # JsonNode support
+  block:
+    type
+      Test = object
+        name: string
+        fallback: JsonNode
+
+    let data = """
+      {"name": "FooBar", "fallback": 56.42}
+    """
+
+    let dataParsed = parseJson(data)
+    let dataDeser = to(dataParsed, Test)
+    doAssert dataDeser.name == "FooBar"
+    doAssert dataDeser.fallback.kind == JFloat
+    doAssert dataDeser.fallback.getFloat() == 56.42
+
+  # int64, float64 etc support.
+  block:
+    type
+      Test1 = object
+        a: int8
+        b: int16
+        c: int32
+        d: int64
+        e: uint8
+        f: uint16
+        g: uint32
+        h: uint64
+        i: float32
+        j: float64
+
+    let data = """
+      {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5, "f": 6, "g": 7,
+       "h": 8, "i": 9.9, "j": 10.10}
+    """
+
+    let dataParsed = parseJson(data)
+    let dataDeser = to(dataParsed, Test1)
+    doAssert dataDeser.a == 1
+    doAssert dataDeser.f == 6
+    doAssert dataDeser.i == 9.9'f32
+
+  # deserialize directly into a table
+  block:
+    let s = """{"a": 1, "b": 2}"""
+    let t = parseJson(s).to(Table[string, int])
+    doAssert t["a"] == 1
+    doAssert t["b"] == 2
+
+  block:
+    # bug #8037
+    type
+      Apple = distinct string
+      String = distinct Apple
+      Email = distinct string
+      MyList = distinct seq[int]
+      MyYear = distinct Option[int]
+      MyTable = distinct Table[string, int]
+      MyArr = distinct array[3, float]
+      MyRef = ref object
+        name: string
+      MyObj = object
+        color: int
+      MyDistRef = distinct MyRef
+      MyDistObj = distinct MyObj
+      Toot = object
+        name*: String
+        email*: Email
+        list: MyList
+        year: MyYear
+        dict: MyTable
+        arr: MyArr
+        person: MyDistRef
+        distfruit: MyDistObj
+        dog: MyRef
+        fruit: MyObj
+        emails: seq[String]
+
+    var tJson = parseJson("""
+      {
+        "name":"Bongo",
+        "email":"bongo@bingo.com",
+        "list": [11,7,15],
+        "year": 1975,
+        "dict": {"a": 1, "b": 2},
+        "arr": [1.0, 2.0, 7.0],
+        "person": {"name": "boney"},
+        "dog": {"name": "honey"},
+        "fruit": {"color": 10},
+        "distfruit": {"color": 11},
+        "emails": ["abc", "123"]
+      }
+    """)
+
+    var t = to(tJson, Toot)
+    doAssert string(t.name) == "Bongo"
+    doAssert string(t.email) == "bongo@bingo.com"
+    doAssert seq[int](t.list) == @[11,7,15]
+    doAssert Option[int](t.year).get() == 1975
+    doAssert Table[string,int](t.dict)["a"] == 1
+    doAssert Table[string,int](t.dict)["b"] == 2
+    doAssert array[3, float](t.arr) == [1.0,2.0,7.0]
+
+    doAssert MyRef(t.person).name == "boney"
+    doAssert MyObj(t.distfruit).color == 11
+    doAssert t.dog.name == "honey"
+    doAssert t.fruit.color == 10
+    doAssert seq[string](t.emails) == @["abc", "123"]
+
+    block test_table:
+      var y = parseJson("""{"a": 1, "b": 2, "c": 3}""")
+      var u = y.to(MyTable)
+      var v = y.to(Table[string, int])
+      doAssert Table[string, int](u)["a"] == 1
+      doAssert Table[string, int](u)["b"] == 2
+      doAssert Table[string, int](u)["c"] == 3
+      doAssert v["a"] == 1
+
+    block primitive_string:
+      const kApple = "apple"
+      var u = newJString(kApple)
+      var v = u.to(Email)
+      var w = u.to(Apple)
+      var x = u.to(String)
+      doAssert string(v) == kApple
+      doAssert string(w) == kApple
+      doAssert string(x) == kApple
+
+    block test_option:
+      var u = newJInt(1137)
+      var v = u.to(MyYear)
+      var w = u.to(Option[int])
+      doAssert Option[int](v).get() == 1137
+      doAssert w.get() == 1137
+
+    block test_object:
+      var u = parseJson("""{"color": 987}""")
+      var v = u.to(MyObj)
+      var w = u.to(MyDistObj)
+      doAssert v.color == 987
+      doAssert MyObj(w).color == 987
+
+    block test_ref_object:
+      var u = parseJson("""{"name": "smith"}""")
+      var v = u.to(MyRef)
+      var w = u.to(MyDistRef)
+      doAssert v.name == "smith"
+      doAssert MyRef(w).name == "smith"
+
+  block:
+    # bug #12015
+    type
+      Cluster = object
+        works: tuple[x, y: uint8, ch: uint16] # working
+        fails: Pix # previously broken
+
+    let data = (x: 123'u8, y: 53'u8, ch: 1231'u16)
+    let c = Cluster(works: data, fails: data)
+    let cFromJson = (% c).to(Cluster)
+    doAssert c == cFromJson
+
+  block:
+    # bug related to #12015
+    type
+      PixInt = tuple[x, y, ch: int]
+      SomePix = Pix | PixInt
+      Cluster[T: SomePix] = seq[T]
+      ClusterObject[T: SomePix] = object
+        data: Cluster[T]
+      RecoEvent[T: SomePix] = object
+        cluster: seq[ClusterObject[T]]
+
+    let data = @[(x: 123'u8, y: 53'u8, ch: 1231'u16)]
+    var c = RecoEvent[Pix](cluster: @[ClusterObject[Pix](data: data)])
+    let cFromJson = (% c).to(RecoEvent[Pix])
+    doAssert c == cFromJson
+
+
+  block:
+    # ref objects with cycles.
+    type
+      Misdirection = object
+        cycle: Cycle
+
+      Cycle = ref object
+        foo: string
+        cycle: Misdirection
+
+    let data = """
+      {"cycle": null}
+    """
+
+    let dataParsed = parseJson(data)
+    let dataDeser = to(dataParsed, Misdirection)
+
+  block:
+    # ref object from #12316
+    type
+      Foo = ref Bar
+      Bar = object
+
+    discard "null".parseJson.to Foo
+
+  block:
+    # named array #12289
+    type Vec = array[2, int]
+    let arr = "[1,2]".parseJson.to Vec
+    doAssert arr == [1,2]
+
+  block:
+    # test error message in exception
+
+    type
+      MyType = object
+        otherMember: string
+        member: MySubType
+
+      MySubType = object
+        somethingElse: string
+        list: seq[MyData]
+
+      MyData = object
+        value: int
+
+    let jsonNode = parseJson("""
+      {
+        "otherMember": "otherValue",
+        "member": {
+          "somethingElse": "something",
+          "list": [{"value": 1}, {"value": 2}, {}]
+        }
+      }
+    """)
+
+    try:
+      let tmp = jsonNode.to(MyType)
+      doAssert false, "this should be unreachable"
+    except KeyError:
+      doAssert getCurrentExceptionMsg().contains ".member.list[2].value"
+
+  block:
+    # Enum indexed array test
+    type Test = enum
+      one, two, three, four, five
+    let a = [
+      one: 300,
+      two: 20,
+      three: 10,
+      four: 0,
+      five: -10
+    ]
+    doAssert (%* a).to(a.typeof) == a
+
+
+testJson()
+static:
+  testJson()
diff --git a/tests/stdlib/tjsonmacro_reject.nim b/tests/stdlib/tjsonmacro_reject.nim
new file mode 100644
index 000000000..ada365d7d
--- /dev/null
+++ b/tests/stdlib/tjsonmacro_reject.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "Use a named tuple instead of: (string, float)"
+  file: "tjsonmacro_reject.nim"
+  line: 11
+"""
+
+import json
+
+type
+  Car = object
+    engine: (string, float)
+    model: string
+
+let j = """
+  {"engine": {"name": "V8", "capacity": 5.5}, model: "Skyline"}
+"""
+let parsed = parseJson(j)
+echo(to(parsed, Car))
diff --git a/tests/stdlib/tjsontestsuite.nim b/tests/stdlib/tjsontestsuite.nim
new file mode 100644
index 000000000..db31963fd
--- /dev/null
+++ b/tests/stdlib/tjsontestsuite.nim
@@ -0,0 +1,388 @@
+discard """
+disabled: true
+"""
+
+## JSON tests based on https://github.com/nst/JSONTestSuite
+
+import unittest,
+  json,
+  strutils
+
+let parsing_testdata = {
+  "i_number_neg_int_huge_exp": """[-1e+9999]""",
+  "i_number_pos_double_huge_exp": """[1.5e+9999]""",
+  "i_object_key_lone_2nd_surrogate": """{"\uDFAA":0}""",
+  "i_string_1st_surrogate_but_2nd_missing": """["\uDADA"]""",
+  "i_string_1st_valid_surrogate_2nd_invalid": """["\uD888\u1234"]""",
+  "i_string_incomplete_surrogate_and_escape_valid": """["\uD800\n"]""",
+  "i_string_incomplete_surrogate_pair": """["\uDd1ea"]""",
+  "i_string_incomplete_surrogates_escape_valid": """["\uD800\uD800\n"]""",
+  "i_string_inverted_surrogates_U+1D11E": """["\uDd1e\uD834"]""",
+  "i_string_lone_second_surrogate": """["\uDFAA"]""",
+  "i_string_not_in_unicode_range": """["ô¿¿¿"]""",
+  "i_string_truncated-utf-8": """["àÿ"]""",
+  "i_string_unicode_U+10FFFE_nonchar": """["\uDBFF\uDFFE"]""",
+  "i_string_unicode_U+1FFFE_nonchar": """["\uD83F\uDFFE"]""",
+  "i_string_unicode_U+FDD0_nonchar": """["\uFDD0"]""",
+  "i_string_unicode_U+FFFE_nonchar": """["\uFFFE"]""",
+  "i_string_UTF-16_invalid_lonely_surrogate": """["\ud800"]""",
+  "i_string_UTF-16_invalid_surrogate": """["\ud800abc"]""",
+  "i_string_UTF-8_invalid_sequence": """["日шú"]""",
+  "i_structure_500_nested_arrays": """[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]""",
+  "i_structure_UTF-8_BOM_empty_object": """{}""",
+  "n_array_1_true_without_comma": """[1 true]""",
+  "n_array_a_invalid_utf8": """[aå]""",
+  "n_array_colon_instead_of_comma": """["": 1]""",
+  "n_array_comma_after_close": """[""],""",
+  "n_array_comma_and_number": """[,1]""",
+  "n_array_double_comma": """[1,,2]""",
+  "n_array_double_extra_comma": """["x",,]""",
+  "n_array_extra_close": """["x"]]""",
+  "n_array_extra_comma": """["",]""",
+  "n_array_incomplete_invalid_value": """[x""",
+  "n_array_incomplete": """["x"""",
+  "n_array_inner_array_no_comma": """[3[4]]""",
+  "n_array_invalid_utf8": """[ÿ]""",
+  "n_array_items_separated_by_semicolon": """[1:2]""",
+  "n_array_just_comma": """[,]""",
+  "n_array_just_minus": """[-]""",
+  "n_array_missing_value": """[   , ""]""",
+  "n_array_newlines_unclosed": """["a",""",
+  "n_array_newlines_unclosed": """4""",
+  "n_array_newlines_unclosed": """,1,""",
+  "n_array_number_and_comma": """[1,]""",
+  "n_array_number_and_several_commas": """[1,,]""",
+  "n_array_spaces_vertical_tab_formfeed": """["a"\f]""",
+  "n_array_star_inside": """[*]""",
+  "n_array_unclosed": """[""""",
+  "n_array_unclosed_trailing_comma": """[1,""",
+  "n_array_unclosed_with_new_lines": """[1,""",
+  "n_array_unclosed_with_new_lines": """1""",
+  "n_array_unclosed_with_new_lines": """,1""",
+  "n_array_unclosed_with_object_inside": """[{}""",
+  "n_incomplete_false": """[fals]""",
+  "n_incomplete_null": """[nul]""",
+  "n_incomplete_true": """[tru]""",
+  "n_number_0.1.2": """[0.1.2]""",
+  "n_number_-01": """[-01]""",
+  "n_number_0.3e": """[0.3e]""",
+  "n_number_0.3e+": """[0.3e+]""",
+  "n_number_0_capital_E": """[0E]""",
+  "n_number_0_capital_E+": """[0E+]""",
+  "n_number_0.e1": """[0.e1]""",
+  "n_number_0e": """[0e]""",
+  "n_number_0e+": """[0e+]""",
+  "n_number_1_000": """[1 000.0]""",
+  "n_number_1.0e-": """[1.0e-]""",
+  "n_number_1.0e": """[1.0e]""",
+  "n_number_1.0e+": """[1.0e+]""",
+  "n_number_-1.0.": """[-1.0.]""",
+  "n_number_1eE2": """[1eE2]""",
+  "n_number_.-1": """[.-1]""",
+  "n_number_+1": """[+1]""",
+  "n_number_.2e-3": """[.2e-3]""",
+  "n_number_2.e-3": """[2.e-3]""",
+  "n_number_2.e+3": """[2.e+3]""",
+  "n_number_2.e3": """[2.e3]""",
+  "n_number_-2.": """[-2.]""",
+  "n_number_9.e+": """[9.e+]""",
+  "n_number_expression": """[1+2]""",
+  "n_number_hex_1_digit": """[0x1]""",
+  "n_number_hex_2_digits": """[0x42]""",
+  "n_number_infinity": """[Infinity]""",
+  "n_number_+Inf": """[+Inf]""",
+  "n_number_Inf": """[Inf]""",
+  "n_number_invalid+-": """[0e+-1]""",
+  "n_number_invalid-negative-real": """[-123.123foo]""",
+  "n_number_invalid-utf-8-in-bigger-int": """[123å]""",
+  "n_number_invalid-utf-8-in-exponent": """[1e1å]""",
+  "n_number_invalid-utf-8-in-int": """[0å]""",
+  "n_number_++": """[++1234]""",
+  "n_number_minus_infinity": """[-Infinity]""",
+  "n_number_minus_sign_with_trailing_garbage": """[-foo]""",
+  "n_number_minus_space_1": """[- 1]""",
+  "n_number_-NaN": """[-NaN]""",
+  "n_number_NaN": """[NaN]""",
+  "n_number_neg_int_starting_with_zero": """[-012]""",
+  "n_number_neg_real_without_int_part": """[-.123]""",
+  "n_number_neg_with_garbage_at_end": """[-1x]""",
+  "n_number_real_garbage_after_e": """[1ea]""",
+  "n_number_real_with_invalid_utf8_after_e": """[1eå]""",
+  "n_number_real_without_fractional_part": """[1.]""",
+  "n_number_starting_with_dot": """[.123]""",
+  "n_number_then_00": """1\x00""",
+  "n_number_U+FF11_fullwidth_digit_one": """[1]""",
+  "n_number_with_alpha_char": """[1.8011670033376514H-308]""",
+  "n_number_with_alpha": """[1.2a-3]""",
+  "n_number_with_leading_zero": """[012]""",
+  "n_object_bad_value": """["x", truth]""",
+  "n_object_bracket_key": """{[: "x"}""",
+  "n_object_comma_instead_of_colon": """{"x", null}""",
+  "n_object_double_colon": """{"x"::"b"}""",
+  "n_object_emoji": """{🇨🇭}""",
+  "n_object_garbage_at_end": """{"a":"a" 123}""",
+  "n_object_key_with_single_quotes": """{key: 'value'}""",
+  "n_object_missing_colon": """{"a" b}""",
+  "n_object_missing_key": """{:"b"}""",
+  "n_object_missing_semicolon": """{"a" "b"}""",
+  "n_object_missing_value": """{"a":""",
+  "n_object_no-colon": """{"a"""",
+  "n_object_non_string_key_but_huge_number_instead": """{9999E9999:1}""",
+  "n_object_non_string_key": """{1:1}""",
+  "n_object_pi_in_key_and_trailing_comma": """{"¹":"0",}""",
+  "n_object_repeated_null_null": """{null:null,null:null}""",
+  "n_object_several_trailing_commas": """{"id":0,,,,,}""",
+  "n_object_single_quote": """{'a':0}""",
+  "n_object_trailing_comma": """{"id":0,}""",
+  "n_object_trailing_comment": """{"a":"b"}/**/""",
+  "n_object_trailing_comment_open": """{"a":"b"}/**//""",
+  "n_object_trailing_comment_slash_open_incomplete": """{"a":"b"}/""",
+  "n_object_trailing_comment_slash_open": """{"a":"b"}//""",
+  "n_object_two_commas_in_a_row": """{"a":"b",,"c":"d"}""",
+  "n_object_unquoted_key": """{a: "b"}""",
+  "n_object_unterminated-value": """{"a":"a""",
+  "n_object_with_single_string": """{ "foo" : "bar", "a" }""",
+  "n_object_with_trailing_garbage": """{"a":"b"}#""",
+  "n_single_space": """ """,
+  "n_string_1_surrogate_then_escape": """["\uD800\"]""",
+  "n_string_1_surrogate_then_escape u1": """["\uD800\u1"]""",
+  "n_string_1_surrogate_then_escape u1x": """["\uD800\u1x"]""",
+  "n_string_1_surrogate_then_escape u": """["\uD800\u"]""",
+  "n_string_accentuated_char_no_quotes": """[é]""",
+  "n_string_backslash_00": """["\\x00"]""",
+  "n_string_escaped_backslash_bad": """["\\\"]""",
+  "n_string_escaped_ctrl_char_tab": """["\	"]""",
+  "n_string_escaped_emoji": """["\🌀"]""",
+  "n_string_escape_x": """["\x00"]""",
+  "n_string_incomplete_escaped_character": """["\u00A"]""",
+  "n_string_incomplete_escape": """["\"]""",
+  "n_string_incomplete_surrogate_escape_invalid": """["\uD800\uD800\x"]""",
+  "n_string_invalid_backslash_esc": """["\a"]""",
+  "n_string_invalid_unicode_escape": """["\uqqqq"]""",
+  "n_string_invalid_utf8_after_escape": """["\å"]""",
+  "n_string_invalid-utf-8-in-escape": """["\uå"]""",
+  "n_string_invalid_utf-8": """["ÿ"]""",
+  "n_string_iso_latin_1": """["é"]""",
+  "n_string_leading_uescaped_thinspace": """[\u0020"asd"]""",
+  "n_string_lone_utf8_continuation_byte": """[""]""",
+  "n_string_no_quotes_with_bad_escape": """[\n]""",
+  "n_string_overlong_sequence_2_bytes": """["À¯"]""",
+  "n_string_overlong_sequence_6_bytes": """["üƒ¿¿¿¿"]""",
+  "n_string_overlong_sequence_6_bytes_null": """["ü€€€€€"]""",
+  "n_string_single_doublequote": """"""",
+  "n_string_single_quote": """['single quote']""",
+  "n_string_single_string_no_double_quotes": """abc""",
+  "n_string_start_escape_unclosed": """["\""",
+  "n_string_unescaped_ctrl_char": """["a\x00a"]""",
+  "n_string_unescaped_newline": """["new
+line"]""",
+  "n_string_unescaped_tab": """["	"]""",
+  "n_string_unicode_CapitalU": """"\UA66D"""",
+  "n_string_UTF-16_incomplete_surrogate": """["\uD834\uDd"]""",
+  "n_string_UTF8_surrogate_U+D800": """["í €"]""",
+  "n_string_with_trailing_garbage": """""x""",
+  "n_structure_array_trailing_garbage": """[1]x""",
+  "n_structure_array_with_extra_array_close": """[1]]""",
+  "n_structure_array_with_unclosed_string": """["asd]""",
+  "n_structure_ascii-unicode-identifier": """aå""",
+  "n_structure_capitalized_True": """[True]""",
+  "n_structure_close_unopened_array": """1]""",
+  "n_structure_comma_instead_of_closing_brace": """{"x": true,""",
+  "n_structure_double_array": """[][]""",
+  "n_structure_end_array": """]""",
+  "n_structure_incomplete_UTF8_BOM": """ï»{}""",
+  "n_structure_<.>": """<.>""",
+  "n_structure_lone-invalid-utf-8": """å""",
+  "n_structure_lone-open-bracket": """[""",
+  "n_structure_null-byte-outside-string": """[\00]""",
+  "n_structure_<null>": """[<null>]""",
+  "n_structure_number_with_trailing_garbage": """2@""",
+  "n_structure_object_followed_by_closing_object": """{}}""",
+  "n_structure_object_unclosed_no_value": """{"":""",
+  "n_structure_object_with_comment": """{"a":/*comment*/"b"}""",
+  "n_structure_object_with_trailing_garbage": """{"a": true} "x"""",
+  "n_structure_open_array_apostrophe": """['""",
+  "n_structure_open_array_comma": """[,""",
+  "n_structure_open_array_open_object": """[{""",
+  "n_structure_open_array_open_string": """["a""",
+  "n_structure_open_array_string": """["a"""",
+  "n_structure_open_object_close_array": """{]""",
+  "n_structure_open_object_comma": """{,""",
+  "n_structure_open_object": """{""",
+  "n_structure_open_object_open_array": """{[""",
+  "n_structure_open_object_open_string": """{"a""",
+  "n_structure_open_object_string_with_apostrophes": """{'a'""",
+  "n_structure_open_open": """["\{["\{["\{["\{""",
+  "n_structure_single_point": """é""",
+  "n_structure_single_star": """*""",
+  "n_structure_trailing_#": """{"a":"b"}#{}""",
+  "n_structure_U+2060_word_joined": """[â ]""",
+  "n_structure_uescaped_LF_before_string": """[\u000A""]""",
+  "n_structure_unclosed_array": """[1""",
+  "n_structure_unclosed_array_partial_null": """[ false, nul""",
+  "n_structure_unclosed_array_unfinished_false": """[ true, fals""",
+  "n_structure_unclosed_array_unfinished_true": """[ false, tru""",
+  "n_structure_unclosed_object": """{"asd":"asd"""",
+  "n_structure_unicode-identifier": """Ã¥""",
+  "n_structure_UTF8_BOM_no_data": """""",
+  "n_structure_whitespace_formfeed": """[]""",
+  "n_structure_whitespace_U+2060_word_joiner": """[â ]""",
+  "y_array_arraysWithSpaces": """[[]   ]""",
+  "y_array_empty": """[]""",
+  "y_array_empty-string": """[""]""",
+  "y_array_ending_with_newline": """["a"]""",
+  "y_array_false": """[false]""",
+  "y_array_heterogeneous": """[null, 1, "1", {}]""",
+  "y_array_null": """[null]""",
+  "y_array_with_1_and_newline": """[1
+]""",
+  "y_array_with_leading_space": """ [1]""",
+  "y_array_with_several_null": """[1,null,null,null,2]""",
+  "y_array_with_trailing_space": """[2] """,
+  "y_number_0e+1": """[0e+1]""",
+  "y_number_0e1": """[0e1]""",
+  "y_number_after_space": """[ 4]""",
+  "y_number_double_close_to_zero": """[-0.000000000000000000000000000000000000000000000000000000000000000000000000000001]""",
+  "y_number_double_huge_neg_exp": """[123.456e-789]""",
+  "y_number_huge_exp": """[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]""",
+  "y_number_int_with_exp": """[20e1]""",
+  "y_number": """[123e65]""",
+  "y_number_minus_zero": """[-0]""",
+  "y_number_negative_int": """[-123]""",
+  "y_number_negative_one": """[-1]""",
+  "y_number_negative_zero": """[-0]""",
+  "y_number_real_capital_e": """[1E22]""",
+  "y_number_real_capital_e_neg_exp": """[1E-2]""",
+  "y_number_real_capital_e_pos_exp": """[1E+2]""",
+  "y_number_real_exponent": """[123e45]""",
+  "y_number_real_fraction_exponent": """[123.456e78]""",
+  "y_number_real_neg_exp": """[1e-2]""",
+  "y_number_real_neg_overflow": """[-123123e100000]""",
+  "y_number_real_pos_exponent": """[1e+2]""",
+  "y_number_real_pos_overflow": """[123123e100000]""",
+  "y_number_real_underflow": """[123e-10000000]""",
+  "y_number_simple_int": """[123]""",
+  "y_number_simple_real": """[123.456789]""",
+  "y_number_too_big_neg_int": """[-123123123123123123123123123123]""",
+  "y_number_too_big_pos_int": """[100000000000000000000]""",
+  "y_number_very_big_negative_int": """[-237462374673276894279832749832423479823246327846]""",
+  "y_object_basic": """{"asd":"sdf"}""",
+  "y_object_duplicated_key_and_value": """{"a":"b","a":"b"}""",
+  "y_object_duplicated_key": """{"a":"b","a":"c"}""",
+  "y_object_empty": """{}""",
+  "y_object_empty_key": """{"":0}""",
+  "y_object_escaped_null_in_key": """{"foo\u0000bar": 42}""",
+  "y_object_extreme_numbers": """{ "min": -1.0e+28, "max": 1.0e+28 }""",
+  "y_object": """{"asd":"sdf", "dfg":"fgh"}""",
+  "y_object_long_strings": """{"x":[{"id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}], "id": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}""",
+  "y_object_simple": """{"a":[]}""",
+  "y_object_string_unicode": """{"title":"\u041f\u043e\u043b\u0442\u043e\u0440\u0430 \u0417\u0435\u043c\u043b\u0435\u043a\u043e\u043f\u0430" }""",
+  "y_object_with_newlines": """{
+"a": "b"
+}""",
+  "y_string_1_2_3_bytes_UTF-8_sequences": """["\u0060\u012a\u12AB"]""",
+  "y_string_accepted_surrogate_pair": """["\uD801\udc37"]""",
+  "y_string_accepted_surrogate_pairs": """["\ud83d\ude39\ud83d\udc8d"]""",
+  "y_string_allowed_escapes": """["\"\\\/\b\f\n\r\t"]""",
+  "y_string_backslash_and_u_escaped_zero": """["\\u0000"]""",
+  "y_string_backslash_doublequotes": """["\""]""",
+  "y_string_comments": """["a/*b*/c/*d//e"]""",
+  "y_string_double_escape_a": """["\\a"]""",
+  "y_string_double_escape_n": """["\\n"]""",
+  "y_string_escaped_control_character": """["\u0012"]""",
+  "y_string_escaped_noncharacter": """["\uFFFF"]""",
+  "y_string_in_array": """["asd"]""",
+  "y_string_in_array_with_leading_space": """[ "asd"]""",
+  "y_string_last_surrogates_1_and_2": """["\uDBFF\uDFFF"]""",
+  "y_string_newline_uescaped": """["new\u00A0line"]""",
+  "y_string_nonCharacterInUTF-8_U+10FFFF": """["ô¿¿"]""",
+  "y_string_nonCharacterInUTF-8_U+1FFFF": """["𛿿"]""",
+  "y_string_nonCharacterInUTF-8_U+FFFF": """["ï¿¿"]""",
+  "y_string_null_escape": """["\u0000"]""",
+  "y_string_one-byte-utf-8": """["\u002c"]""",
+  "y_string_pi": """["Ï€"]""",
+  "y_string_simple_ascii": """["asd "]""",
+  "y_string_space": """" """",
+  "y_string_three-byte-utf-8": """["\u0821"]""",
+  "y_string_two-byte-utf-8": """["\u0123"]""",
+  "y_string_u+2028_line_sep": """["
"]""",
+  "y_string_u+2029_par_sep": """["
"]""",
+  "y_string_uEscape": """["\u0061\u30af\u30EA\u30b9"]""",
+  "y_string_unescaped_char_delete": """[""]""",
+  "y_string_unicode_2": """["â‚㈴â‚"]""",
+  "y_string_unicodeEscapedBackslash": """["\u005C"]""",
+  "y_string_unicode_escaped_double_quote": """["\u0022"]""",
+  "y_string_unicode": """["\uA66D"]""",
+  "y_string_unicode_U+200B_ZERO_WIDTH_SPACE": """["\u200B"]""",
+  "y_string_unicode_U+2064_invisible_plus": """["\u2064"]""",
+  "y_string_UTF-16_Surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF": """["\uD834\uDd1e"]""",
+  "y_string_utf8": """["€ð„ž"]""",
+  "y_string_with_del_character": """["aa"]""",
+  "y_structure_lonely_false": """false""",
+  "y_structure_lonely_int": """42""",
+  "y_structure_lonely_negative_real": """-0.1""",
+  "y_structure_lonely_null": """null""",
+  "y_structure_lonely_string": """"asd"""",
+  "y_structure_lonely_true": """true""",
+  "y_structure_string_empty": """""""",
+  "y_structure_trailing_newline": """["a"]""",
+  "y_structure_true_in_array": """[true]""",
+  "y_structure_whitespace_array": """ [] """,
+}
+
+
+suite "JSON":
+
+  test "Multiple parsing tests":
+    var test_is_failed = false
+    for test_item in parsing_testdata:
+
+      let name = test_item[0]
+      let data = test_item[1]
+      var
+        parsed_successfully = false
+        parsed: JsonNode
+        exception_while_parsing = ""
+        exception_while_rendering = ""
+
+      try:
+        parsed = parseJson(data)
+        parsed_successfully = true
+      except:
+        exception_while_parsing = getCurrentExceptionMsg()
+
+
+      proc echo_summary(msg: string) =
+        var rendered = ""
+        var render_successfully = false
+        if parsed_successfully:
+          try:
+            rendered = $parsed
+            render_successfully = true
+          except:
+            rendered = "[Fail to render:<$#>]" % getCurrentExceptionMsg()
+        else:
+          rendered = "<$#>" % exception_while_parsing
+
+        echo name, repeat(' ', 60 - name.len), "[$#]" % msg, " ", rendered
+
+      case name[0]
+      of 'y':
+        # Tests starting with y_ must parse
+        if not parsed_successfully:
+          echo_summary "Failed to parse"
+          test_is_failed = true
+      of 'n':
+        # Tests starting with n_ should not parse
+        if parsed_successfully:
+          echo_summary "Failed to raise exception"
+      of 'i':
+        if parsed_successfully:
+          echo_summary "OK"
+        else:
+          echo_summary "Not parsed"
+
+      else: discard
+
+    # FIXME: temporarily disabled until "y_" tests will succeed
+    # if test_is_failed: fail()
diff --git a/tests/stdlib/tjsonutils.nim b/tests/stdlib/tjsonutils.nim
new file mode 100644
index 000000000..9acf4c9e5
--- /dev/null
+++ b/tests/stdlib/tjsonutils.nim
@@ -0,0 +1,476 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/jsonutils
+import std/json
+from std/math import isNaN, signbit
+from std/fenv import epsilon
+from stdtest/testutils import whenRuntimeJs
+import std/[assertions, objectdollar]
+
+proc testRoundtrip[T](t: T, expected: string) =
+  # checks that `T => json => T2 => json2` is such that json2 = json
+  let j = t.toJson
+  doAssert $j == expected, "\n" & $j & "\n" & expected
+  doAssert j.jsonTo(T).toJson == j
+  var t2: T
+  t2.fromJson(j)
+  doAssert t2.toJson == j
+
+proc testRoundtripVal[T](t: T, expected: string) =
+  # similar to testRoundtrip, but also checks that the `T => json => T2` is such that `T2 == T`
+  # note that this isn't always possible, e.g. for pointer-like types.
+  let j = t.toJson
+  let j2 = $j
+  doAssert j2 == expected, j2
+  let j3 = j2.parseJson
+  let t2 = j3.jsonTo(T)
+  doAssert t2 == t
+  doAssert $t2.toJson == j2 # still needed, because -0.0 = 0.0 but their json representation differs
+
+import tables, sets, algorithm, sequtils, options, strtabs
+from strutils import contains
+
+type Foo = ref object
+  id: int
+
+proc `==`(a, b: Foo): bool =
+  a.id == b.id
+
+type MyEnum = enum me0, me1 = "me1Alt", me2, me3, me4
+
+proc `$`(a: MyEnum): string =
+  # putting this here pending https://github.com/nim-lang/Nim/issues/13747
+  if a == me2: "me2Modif"
+  else: system.`$`(a)
+
+template fn() =
+  block: # toJson, jsonTo
+    type Foo = distinct float
+    testRoundtrip('x', """120""")
+    when not defined(js):
+      testRoundtrip(cast[pointer](12345)): """12345"""
+      when nimvm:
+        discard
+        # bugs:
+        # Error: unhandled exception: 'intVal' is not accessible using discriminant 'kind' of type 'TNode' [
+        # Error: VM does not support 'cast' from tyNil to tyPointer
+      else:
+        testRoundtrip(pointer(nil)): """0"""
+        testRoundtrip(cast[pointer](nil)): """0"""
+
+    # refs bug #9423
+    testRoundtrip(Foo(1.5)): """1.5"""
+
+  block: # OrderedTable
+    testRoundtrip({"z": "Z", "y": "Y"}.toOrderedTable): """{"z":"Z","y":"Y"}"""
+    doAssert toJson({"z": 10, "": 11}.newTable).`$`.contains """"":11""" # allows hash to change
+    testRoundtrip({"z".cstring: 1, "".cstring: 2}.toOrderedTable): """{"z":1,"":2}"""
+    testRoundtrip({"z": (f1: 'f'), }.toTable): """{"z":{"f1":102}}"""
+
+  block: # StringTable
+    testRoundtrip({"name": "John", "city": "Monaco"}.newStringTable): """{"mode":"modeCaseSensitive","table":{"city":"Monaco","name":"John"}}"""
+
+  block: # complex example
+    let t = {"z": "Z", "y": "Y"}.newStringTable
+    type A = ref object
+      a1: string
+    let a = (1.1, "fo", 'x', @[10,11], [true, false], [t,newStringTable()], [0'i8,3'i8], -4'i16, (foo: 0.5'f32, bar: A(a1: "abc"), bar2: A.default, cstring1: "foo", cstring2: "", cstring3: cstring(nil)))
+    testRoundtrip(a):
+      """[1.1,"fo",120,[10,11],[true,false],[{"mode":"modeCaseSensitive","table":{"y":"Y","z":"Z"}},{"mode":"modeCaseSensitive","table":{}}],[0,3],-4,{"foo":0.5,"bar":{"a1":"abc"},"bar2":null,"cstring1":"foo","cstring2":"","cstring3":null}]"""
+
+  block:
+    # edge case when user defined `==` doesn't handle `nil` well, e.g.:
+    # https://github.com/nim-lang/nimble/blob/63695f490728e3935692c29f3d71944d83bb1e83/src/nimblepkg/version.nim#L105
+    testRoundtrip(@[Foo(id: 10), nil]): """[{"id":10},null]"""
+
+  block: # enum
+    type Foo = enum f1, f2, f3, f4, f5
+    type Bar = enum b1, b2, b3, b4
+    let a = [f2: b2, f3: b3, f4: b4]
+    doAssert b2.ord == 1 # explains the `1`
+    testRoundtrip(a): """[1,2,3]"""
+
+  block: # JsonNode
+    let a = ((1, 2.5, "abc").toJson, (3, 4.5, "foo"))
+    testRoundtripVal(a): """[[1,2.5,"abc"],[3,4.5,"foo"]]"""
+
+    block:
+      template toInt(a): untyped = cast[int](a)
+
+      let a = 3.toJson
+      let b = (a, a)
+
+      let c1 = b.toJson
+      doAssert c1[0].toInt == a.toInt
+      doAssert c1[1].toInt == a.toInt
+
+      let c2 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsCopy))
+      doAssert c2[0].toInt != a.toInt
+      doAssert c2[1].toInt != c2[0].toInt
+      doAssert c2[1] == c2[0]
+
+      let c3 = b.toJson(ToJsonOptions(jsonNodeMode: joptJsonNodeAsObject))
+      doAssert $c3 == """[{"isUnquoted":false,"kind":2,"num":3},{"isUnquoted":false,"kind":2,"num":3}]"""
+
+  block: # ToJsonOptions
+    let a = (me1, me2)
+    doAssert $a.toJson() == "[1,2]"
+    doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumSymbol)) == """["me1","me2"]"""
+    doAssert $a.toJson(ToJsonOptions(enumMode: joptEnumString)) == """["me1Alt","me2Modif"]"""
+
+  block: # set
+    type Foo = enum f1, f2, f3, f4, f5
+    type Goo = enum g1 = 10, g2 = 15, g3 = 17, g4
+    let a = ({f1, f3}, {1'u8, 7'u8}, {'0'..'9'}, {123'u16, 456, 789, 1121, 1122, 1542}, {g2, g3})
+    testRoundtrip(a): """[[0,2],[1,7],[48,49,50,51,52,53,54,55,56,57],[123,456,789,1121,1122,1542],[15,17]]"""
+
+  block: # bug #17383
+    block:
+      let a = (int32.high, uint32.high)
+      testRoundtrip(a): "[2147483647,4294967295]"
+    when int.sizeof > 4:
+      block:
+        let a = (int64.high, uint64.high)
+        testRoundtrip(a): "[9223372036854775807,18446744073709551615]"
+    block:
+      let a = (int.high, uint.high)
+      when int.sizeof == 4:
+        testRoundtrip(a): "[2147483647,4294967295]"
+      else:
+        testRoundtrip(a): "[9223372036854775807,18446744073709551615]"
+
+  block: # bug #18007
+    testRoundtrip((NaN, Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+    testRoundtrip((float32(NaN), Inf, -Inf, 0.0, -0.0, 1.0)): """["nan","inf","-inf",0.0,-0.0,1.0]"""
+    testRoundtripVal((Inf, -Inf, 0.0, -0.0, 1.0)): """["inf","-inf",0.0,-0.0,1.0]"""
+    doAssert ($NaN.toJson).parseJson.jsonTo(float).isNaN
+
+  block: # bug #18009; unfixable unless we change parseJson (which would have overhead),
+         # but at least we can guarantee that the distinction between 0.0 and -0.0 is preserved.
+    let a = (0, 0.0, -0.0, 0.5, 1, 1.0)
+    testRoundtripVal(a): "[0,0.0,-0.0,0.5,1,1.0]"
+    let a2 = $($a.toJson).parseJson
+    whenRuntimeJs:
+      doAssert a2 == "[0,0,-0.0,0.5,1,1]"
+    do:
+      doAssert a2 == "[0,0.0,-0.0,0.5,1,1.0]"
+    let b = a2.parseJson.jsonTo(type(a))
+    doAssert not b[1].signbit
+    doAssert b[2].signbit
+    doAssert not b[3].signbit
+
+  block: # bug #15397, bug #13196
+    let a = 0.1
+    let x = 0.12345678901234567890123456789
+    let b = (a + 0.2, 0.3, x)
+    testRoundtripVal(b): "[0.30000000000000004,0.3,0.12345678901234568]"
+
+    testRoundtripVal(0.12345678901234567890123456789): "0.12345678901234568"
+    testRoundtripVal(epsilon(float64)): "2.220446049250313e-16"
+    testRoundtripVal(1.0 + epsilon(float64)): "1.0000000000000002"
+
+  block: # case object
+    type Foo = object
+      x0: float
+      case t1: bool
+      of true: z1: int8
+      of false: z2: uint16
+      x1: string
+    testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}"""
+    testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+    type PFoo = ref Foo
+    testRoundtrip(PFoo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+
+  block: # ref case object
+    type Foo = ref object
+      x0: float
+      case t1: bool
+      of true: z1: int8
+      of false: z2: uint16
+      x1: string
+    testRoundtrip(Foo(t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}"""
+    testRoundtrip(Foo(x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+
+  block: # generic case object
+    type Foo[T] = ref object
+      x0: float
+      case t1: bool
+      of true: z1: int8
+      of false: z2: uint16
+      x1: string
+    testRoundtrip(Foo[float](t1: true, z1: 5, x1: "bar")): """{"x0":0.0,"t1":true,"z1":5,"x1":"bar"}"""
+    testRoundtrip(Foo[int](x0: 1.5, t1: false, z2: 6)): """{"x0":1.5,"t1":false,"z2":6,"x1":""}"""
+    # sanity check: nesting inside a tuple
+    testRoundtrip((Foo[int](x0: 1.5, t1: false, z2: 6), "foo")): """[{"x0":1.5,"t1":false,"z2":6,"x1":""},"foo"]"""
+
+  block: # case object: 2 discriminants, `when` branch, range discriminant
+    type Foo[T] = object
+      case t1: bool
+      of true:
+        z1: int8
+      of false:
+        z2: uint16
+      when T is float:
+        case t2: range[0..3]
+        of 0: z3: int8
+        of 2,3: z4: uint16
+        else: discard
+    testRoundtrip(Foo[float](t1: true, z1: 5, t2: 3, z4: 12)): """{"t1":true,"z1":5,"t2":3,"z4":12}"""
+    testRoundtrip(Foo[int](t1: false, z2: 7)): """{"t1":false,"z2":7}"""
+    # pending https://github.com/nim-lang/Nim/issues/14698, test with `type Foo[T] = ref object`
+
+  block: # bug: pass opt params in fromJson
+    type Foo = object
+      a: int
+      b: string
+      c: float
+    type Bar = object
+      foo: Foo
+      boo: string
+    var f: seq[Foo]
+    try:
+      fromJson(f, parseJson """[{"b": "bbb"}]""")
+      doAssert false
+    except ValueError:
+      doAssert true
+    fromJson(f, parseJson """[{"b": "bbb"}]""", Joptions(allowExtraKeys: true, allowMissingKeys: true))
+    doAssert f == @[Foo(a: 0, b: "bbb", c: 0.0)]
+    var b: Bar
+    fromJson(b, parseJson """{"foo": {"b": "bbb"}}""", Joptions(allowExtraKeys: true, allowMissingKeys: true))
+    doAssert b == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0))
+    block: # jsonTo with `opt`
+      let b2 = """{"foo": {"b": "bbb"}}""".parseJson.jsonTo(Bar,  Joptions(allowExtraKeys: true, allowMissingKeys: true))
+      doAssert b2 == Bar(foo: Foo(a: 0, b: "bbb", c: 0.0))
+
+  block testHashSet:
+    testRoundtrip(HashSet[string]()): "[]"
+    testRoundtrip([""].toHashSet): """[""]"""
+    testRoundtrip(["one"].toHashSet): """["one"]"""
+
+    var s: HashSet[string]
+    fromJson(s, parseJson("""["one","two"]"""))
+    doAssert s == ["one", "two"].toHashSet
+
+    let jsonNode = toJson(s)
+    doAssert jsonNode.elems.mapIt(it.str).sorted == @["one", "two"]
+
+  block testOrderedSet:
+    testRoundtrip(["one", "two", "three"].toOrderedSet):
+      """["one","two","three"]"""
+
+  block testOption:
+    testRoundtrip(some("test")): "\"test\""
+    testRoundtrip(none[string]()): "null"
+    testRoundtrip(some(42)): "42"
+    testRoundtrip(none[int]()): "null"
+
+  block testStrtabs:
+    testRoundtrip(newStringTable(modeStyleInsensitive)):
+      """{"mode":"modeStyleInsensitive","table":{}}"""
+
+    testRoundtrip(
+      newStringTable("name", "John", "surname", "Doe", modeCaseSensitive)):
+        """{"mode":"modeCaseSensitive","table":{"name":"John","surname":"Doe"}}"""
+
+  block testJoptions:
+    type
+      AboutLifeUniverseAndEverythingElse = object
+        question: string
+        answer: int
+
+    block testExceptionOnExtraKeys:
+      var guide: AboutLifeUniverseAndEverythingElse
+      let json = parseJson(
+        """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""")
+      doAssertRaises ValueError, fromJson(guide, json)
+      doAssertRaises ValueError,
+                     fromJson(guide, json, Joptions(allowMissingKeys: true))
+
+      type
+        A = object
+          a1,a2,a3: int
+      var a: A
+      let j = parseJson("""{"a3": 1, "a4": 2}""")
+      doAssertRaises ValueError,
+                     fromJson(a, j, Joptions(allowMissingKeys: true))
+
+    block testExceptionOnMissingKeys:
+      var guide: AboutLifeUniverseAndEverythingElse
+      let json = parseJson("""{"answer":42}""")
+      doAssertRaises ValueError, fromJson(guide, json)
+      doAssertRaises ValueError,
+                     fromJson(guide, json, Joptions(allowExtraKeys: true))
+
+    block testAllowExtraKeys:
+      var guide: AboutLifeUniverseAndEverythingElse
+      let json = parseJson(
+        """{"question":"6*9=?","answer":42,"author":"Douglas Adams"}""")
+      fromJson(guide, json, Joptions(allowExtraKeys: true))
+      doAssert guide == AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 42)
+
+      block refObject: #bug 17986
+        type A = ref object
+          case is_a: bool
+          of true:
+            a: int
+          else:
+            b: int
+
+        var a = A()
+        fromJson(a, """{"is_a": true, "a":1, "extra_key": 1}""".parseJson, Joptions(allowExtraKeys: true))
+        doAssert $a[] == "(is_a: true, a: 1)"
+
+    block testAllowMissingKeys:
+      var guide = AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 54)
+      let json = parseJson("""{"answer":42}""")
+      fromJson(guide, json, Joptions(allowMissingKeys: true))
+      doAssert guide == AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 42)
+
+    block testAllowExtraAndMissingKeys:
+      var guide = AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 54)
+      let json = parseJson(
+        """{"answer":42,"author":"Douglas Adams"}""")
+      fromJson(guide, json, Joptions(
+        allowExtraKeys: true, allowMissingKeys: true))
+      doAssert guide == AboutLifeUniverseAndEverythingElse(
+        question: "6*9=?", answer: 42)
+
+    type
+      Foo = object
+        a: array[2, string]
+        case b: bool
+        of false: f: float
+        of true: t: tuple[i: int, s: string]
+        case c: range[0 .. 2]
+        of 0: c0: int
+        of 1: c1: float
+        of 2: c2: string
+
+    block testExceptionOnMissingDiscriminantKey:
+      var foo: Foo
+      let json = parseJson("""{"a":["one","two"]}""")
+      doAssertRaises ValueError, fromJson(foo, json)
+
+    block testDoNotResetMissingFieldsWhenHaveDiscriminantKey:
+      var foo = Foo(a: ["one", "two"], b: true, t: (i: 42, s: "s"),
+                    c: 0, c0: 1)
+      let json = parseJson("""{"b":true,"c":2}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true))
+      doAssert foo.a == ["one", "two"]
+      doAssert foo.b
+      doAssert foo.t == (i: 42, s: "s")
+      doAssert foo.c == 2
+      doAssert foo.c2 == ""
+
+    block testAllowMissingDiscriminantKeys:
+      var foo: Foo
+      let json = parseJson("""{"a":["one","two"],"c":1,"c1":3.14159}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true))
+      doAssert foo.a == ["one", "two"]
+      doAssert not foo.b
+      doAssert foo.f == 0.0
+      doAssert foo.c == 1
+      doAssert foo.c1 == 3.14159
+
+    block testExceptionOnWrongDiscirminatBranchInJson:
+      var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42)
+      let json = parseJson("""{"c2": "hello"}""")
+      doAssertRaises ValueError,
+                     fromJson(foo, json, Joptions(allowMissingKeys: true))
+      # Test that the original fields are not reset.
+      doAssert not foo.b
+      doAssert foo.f == 3.14159
+      doAssert foo.c == 0
+      doAssert foo.c0 == 42
+
+    block testNoExceptionOnRightDiscriminantBranchInJson:
+      var foo = Foo(b: false, f: 0, c:1, c1: 0)
+      let json = parseJson("""{"f":2.71828,"c1": 3.14159}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true))
+      doAssert not foo.b
+      doAssert foo.f == 2.71828
+      doAssert foo.c == 1
+      doAssert foo.c1 == 3.14159
+
+    block testAllowExtraKeysInJsonOnWrongDisciriminatBranch:
+      var foo = Foo(b: false, f: 3.14159, c: 0, c0: 42)
+      let json = parseJson("""{"c2": "hello"}""")
+      fromJson(foo, json, Joptions(allowMissingKeys: true,
+                                   allowExtraKeys: true))
+      # Test that the original fields are not reset.
+      doAssert not foo.b
+      doAssert foo.f == 3.14159
+      doAssert foo.c == 0
+      doAssert foo.c0 == 42
+
+
+    block testInvalidTupleLength:
+      let json = parseJson("[0]")
+      # Should raise ValueError instead of index error
+      doAssertRaises(ValueError):
+        discard json.jsonTo((int, int))
+
+    type
+      InnerEnum = enum
+        A
+        B
+        C
+      InnerObject = object
+        x: string
+        y: InnerEnum
+
+    block testOptionsArePassedWhenDeserialising:
+      let json = parseJson("""{"x": "hello"}""")
+      let inner = json.jsonTo(Option[InnerObject], Joptions(allowMissingKeys: true))
+      doAssert inner.isSome()
+      doAssert inner.get().x == "hello"
+      doAssert inner.get().y == A
+
+    block testOptionsArePassedWhenSerialising:
+      let inner = some InnerObject(x: "hello", y: A)
+      let json = inner.toJson(ToJsonOptions(enumMode: joptEnumSymbol))
+      doAssert $json == """{"x":"hello","y":"A"}"""
+
+    block: # bug #21638
+      type Something = object
+
+      doAssert "{}".parseJson.jsonTo(Something) == Something()
+
+    when false:
+      ## TODO: Implement support for nested variant objects allowing the tests
+      ## bellow to pass.
+      block testNestedVariantObjects:
+        type
+          Variant = object
+            case b: bool
+            of false:
+              case bf: bool
+              of false: bff: int
+              of true: bft: float
+            of true:
+              case bt: bool
+              of false: btf: string
+              of true: btt: char
+
+        testRoundtrip(Variant(b: false, bf: false, bff: 42)):
+          """{"b": false, "bf": false, "bff": 42}"""
+        testRoundtrip(Variant(b: false, bf: true, bft: 3.14159)):
+          """{"b": false, "bf": true, "bft": 3.14159}"""
+        testRoundtrip(Variant(b: true, bt: false, btf: "test")):
+          """{"b": true, "bt": false, "btf": "test"}"""
+        testRoundtrip(Variant(b: true, bt: true, btt: 'c')):
+          """{"b": true, "bt": true, "btt": "c"}"""
+
+        # TODO: Add additional tests with missing and extra JSON keys, both when
+        # allowed and forbidden analogous to the tests for the not nested
+        # variant objects.
+
+static: fn()
+fn()
diff --git a/tests/stdlib/tlists.nim b/tests/stdlib/tlists.nim
new file mode 100644
index 000000000..5993278c7
--- /dev/null
+++ b/tests/stdlib/tlists.nim
@@ -0,0 +1,277 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/[lists, sequtils]
+import std/assertions
+
+const
+  data = [1, 2, 3, 4, 5, 6]
+
+
+template main =
+  block SinglyLinkedListTest1:
+    var L: SinglyLinkedList[int]
+    for d in items(data): L.prepend(d)
+    for d in items(data): L.add(d)
+    doAssert($L == "[6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6]")
+
+    doAssert(4 in L)
+
+  block SinglyLinkedListTest2:
+    var L: SinglyLinkedList[string]
+    for d in items(data): L.prepend($d)
+    doAssert($L == """["6", "5", "4", "3", "2", "1"]""")
+
+    doAssert("4" in L)
+
+
+  block DoublyLinkedListTest1:
+    var L: DoublyLinkedList[int]
+    for d in items(data): L.prepend(d)
+    for d in items(data): L.add(d)
+    L.remove(L.find(1))
+    doAssert($L == "[6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6]")
+
+    doAssert(4 in L)
+
+  block SinglyLinkedRingTest1:
+    var L: SinglyLinkedRing[int]
+    L.prepend(4)
+    doAssert($L == "[4]")
+    L.prepend(4)
+
+    doAssert($L == "[4, 4]")
+    doAssert(4 in L)
+
+
+  block DoublyLinkedRingTest1:
+    var L: DoublyLinkedRing[int]
+    L.prepend(4)
+    doAssert($L == "[4]")
+    L.prepend(4)
+
+    doAssert($L == "[4, 4]")
+    doAssert(4 in L)
+
+    L.add(3)
+    L.add(5)
+    doAssert($L == "[4, 4, 3, 5]")
+
+    L.remove(L.find(3))
+    L.remove(L.find(5))
+    L.remove(L.find(4))
+    L.remove(L.find(4))
+    doAssert($L == "[]")
+    doAssert(4 notin L)
+
+  block tlistsToString:
+    block:
+      var l = initDoublyLinkedList[int]()
+      l.add(1)
+      l.add(2)
+      l.add(3)
+      doAssert $l == "[1, 2, 3]"
+    block:
+      var l = initDoublyLinkedList[string]()
+      l.add("1")
+      l.add("2")
+      l.add("3")
+      doAssert $l == """["1", "2", "3"]"""
+    block:
+      var l = initDoublyLinkedList[char]()
+      l.add('1')
+      l.add('2')
+      l.add('3')
+      doAssert $l == """['1', '2', '3']"""
+
+  # Copied here until it is merged into sequtils
+  template take(a: untyped, max: int): untyped =
+    type T = typeof(block: (for ai in a: ai))
+    var ret: seq[T]
+    var i = 0
+    if max > 0:
+      for ai in a:
+        ret.add ai
+        i.inc
+        if i >= max: break
+    ret
+
+  template testCommon(initList, toList) =
+
+    block: # toSinglyLinkedList, toDoublyLinkedList
+      let l = seq[int].default
+      doAssert l.toList.toSeq == []
+      doAssert [1].toList.toSeq == [1]
+      doAssert [1, 2, 3].toList.toSeq == [1, 2, 3]
+
+    block copy:
+      doAssert array[0, int].default.toList.copy.toSeq == []
+      doAssert [1].toList.copy.toSeq == [1]
+      doAssert [1, 2].toList.copy.toSeq == [1, 2]
+      doAssert [1, 2, 3].toList.copy.toSeq == [1, 2, 3]
+      type Foo = ref object
+        x: int
+      var f0 = Foo(x: 0)
+      let f1 = Foo(x: 1)
+      var a = [f0].toList
+      var b = a.copy
+      b.add f1
+      doAssert a.toSeq == [f0]
+      doAssert b.toSeq == [f0, f1]
+      f0.x = 42
+      doAssert a.head.value.x == 42
+      doAssert b.head.value.x == 42
+
+    block: # add, addMoved
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l0.add l3
+        l1.add l3
+        l2.addMoved l3
+        doAssert l0.toSeq == [4, 5, 6]
+        doAssert l1.toSeq == [1, 4, 5, 6]
+        doAssert l2.toSeq == [2, 3, 4, 5, 6]
+        doAssert l3.toSeq == []
+        l2.add l3 # re-adding l3 that was destroyed is now a no-op
+        doAssert l2.toSeq == [2, 3, 4, 5, 6]
+        doAssert l3.toSeq == []
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l3.addMoved l0
+        l2.addMoved l1
+        doAssert l3.toSeq == [4, 5, 6]
+        doAssert l2.toSeq == [2, 3, 1]
+        l3.add l0
+        doAssert l3.toSeq == [4, 5, 6]
+      block:
+        var c = [0, 1].toList
+        c.addMoved c
+        doAssert c.take(6) == [0, 1, 0, 1, 0, 1]
+
+    block: # prepend, prependMoved
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l0.prepend l3
+        l1.prepend l3
+        doAssert l3.toSeq == [4, 5, 6]
+        l2.prependMoved l3
+        doAssert l0.toSeq == [4, 5, 6]
+        doAssert l1.toSeq == [4, 5, 6, 1]
+        doAssert l2.toSeq == [4, 5, 6, 2, 3]
+        doAssert l3.toSeq == []
+        l2.prepend l3 # re-prepending l3 that was destroyed is now a no-op
+        doAssert l2.toSeq == [4, 5, 6, 2, 3]
+        doAssert l3.toSeq == []
+      block:
+        var
+          l0 = initList[int]()
+          l1 = [1].toList
+          l2 = [2, 3].toList
+          l3 = [4, 5, 6].toList
+        l3.prependMoved l0
+        l2.prependMoved l1
+        doAssert l3.toSeq == [4, 5, 6]
+        doAssert l2.toSeq == [1, 2, 3]
+        l3.prepend l0
+        doAssert l3.toSeq == [4, 5, 6]
+      block:
+        var c = [0, 1].toList
+        c.prependMoved c
+        doAssert c.take(6) == [0, 1, 0, 1, 0, 1]
+
+    block remove:
+      var l = [0, 1, 2, 3].toList
+      let
+        l0 = l.head
+        l1 = l0.next
+        l2 = l1.next
+        l3 = l2.next
+      l.remove l0
+      doAssert l.toSeq == [1, 2, 3]
+      l.remove l2
+      doAssert l.toSeq == [1, 3]
+      l.remove l2
+      doAssert l.toSeq == [1, 3]
+      l.remove l3
+      doAssert l.toSeq == [1]
+      l.remove l1
+      doAssert l.toSeq == []
+      # Cycle preservation
+      var a = [10, 11, 12].toList
+      a.addMoved a
+      doAssert a.take(6) == @[10, 11, 12, 10, 11, 12]
+      a.remove a.head.next
+      doAssert a.take(6) == @[10, 12, 10, 12, 10, 12]
+      a.remove a.head
+      doAssert a.take(6) == @[12, 12, 12, 12, 12, 12]
+
+  testCommon initSinglyLinkedList, toSinglyLinkedList
+  testCommon initDoublyLinkedList, toDoublyLinkedList
+
+  block remove: # return value check
+    var l = [0, 1, 2, 3].toSinglyLinkedList
+    let n = l.head.next.next
+    doAssert l.remove(n) == true
+    doAssert l.toSeq == [0, 1, 3]
+    doAssert l.remove(n) == false
+    doAssert l.toSeq == [0, 1, 3]
+    doAssert l.remove(l.head) == true
+    doAssert l.toSeq == [1, 3]
+    doAssert l.remove(l.head.next) == true
+    doAssert l.toSeq == [1]
+    doAssert l.remove(l.head) == true
+    doAssert l.toSeq == []
+  
+  block issue19297: # add (appends a shallow copy)
+    var a: SinglyLinkedList[int]
+    var b: SinglyLinkedList[int]
+
+    doAssert a.toSeq == @[]
+    a.add(1)
+    doAssert a.toSeq == @[1]
+    a.add(b)
+    doAssert a.toSeq == @[1]
+    a.add(2)
+    doAssert a.toSeq == @[1, 2]
+  
+  block issue19314: # add (appends a shallow copy)
+    var a: DoublyLinkedList[int]
+    var b: DoublyLinkedList[int]
+
+    doAssert a.toSeq == @[]
+    a.add(1)
+    doAssert a.toSeq == @[1]
+    a.add(b)
+    doAssert a.toSeq == @[1]
+    a.add(2)
+    doAssert a.toSeq == @[1, 2]
+
+  block RemoveLastNodeFromSinglyLinkedList:
+    var list = initSinglyLinkedList[string]()
+    let n1 = newSinglyLinkedNode("sonic")
+    let n2 = newSinglyLinkedNode("the")
+    let n3 = newSinglyLinkedNode("tiger")
+    let n4 = newSinglyLinkedNode("hedgehog")
+    list.add(n1)
+    list.add(n2)
+    list.add(n3)
+    list.remove(n3)
+    list.add(n4)
+    doAssert list.toSeq == @["sonic", "the", "hedgehog"]
+
+static: main()
+main()
diff --git a/tests/stdlib/tlocks.nim b/tests/stdlib/tlocks.nim
new file mode 100644
index 000000000..1c5f67119
--- /dev/null
+++ b/tests/stdlib/tlocks.nim
@@ -0,0 +1,11 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+#bug #6049
+import uselocks
+import std/assertions
+
+var m = createMyType[int]()
+doAssert m.use() == 3
diff --git a/tests/stdlib/tlwip.nim b/tests/stdlib/tlwip.nim
new file mode 100644
index 000000000..fc53be592
--- /dev/null
+++ b/tests/stdlib/tlwip.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "c"
+  cmd: "nim $target --compileOnly --os:freertos --gc:arc $options $file"
+  disabled: "bsd"
+  disabled: "windows"
+  action: compile
+"""
+
+# Note:
+#   This file tests FreeRTOS/LwIP cross-compilation on UNIX platforms
+#   Windows should run when compiled with esp-idf, however I'm not
+#   sure how to test for only compilation on Windows without running 
+#   a test exe
+# 
+# Note:
+#   disabling *BSDs since they're not playing well with `gcc`
+
+import net
+import asynchttpserver, asyncdispatch
+
+proc cb*(req: Request) {.async.} =
+  await req.respond(Http200, "Hello World")
+
+proc run_http_server*() {.exportc.} =
+  echo "starting http server"
+  var server = newAsyncHttpServer()
+
+  waitFor server.serve(Port(8181), cb)
+
+echo("ok")
diff --git a/tests/stdlib/tmacros.nim b/tests/stdlib/tmacros.nim
new file mode 100644
index 000000000..06a9a9c27
--- /dev/null
+++ b/tests/stdlib/tmacros.nim
@@ -0,0 +1,349 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+#[
+xxx macros tests need to be reorganized to makes sure each API is tested once
+See also:
+  tests/macros/tdumpast.nim for treeRepr + friends
+]#
+
+import std/macros
+import std/assertions
+
+block: # hasArgOfName
+  macro m(u: untyped): untyped =
+    for name in ["s","i","j","k","b","xs","ys"]:
+      doAssert hasArgOfName(params u,name)
+    doAssert not hasArgOfName(params u,"nonexistent")
+
+  proc p(s: string; i,j,k: int; b: bool; xs,ys: seq[int] = @[]) {.m.} = discard
+
+block: # bug #17454
+  proc f(v: NimNode): string {.raises: [].} = $v
+
+block: # unpackVarargs
+  block:
+    proc bar1(a: varargs[int]): string =
+      for ai in a: result.add " " & $ai
+    proc bar2(a: varargs[int]) =
+      let s1 = bar1(a)
+      let s2 = unpackVarargs(bar1, a) # `unpackVarargs` makes no difference here
+      doAssert s1 == s2
+    bar2(1, 2, 3)
+    bar2(1)
+    bar2()
+
+  block:
+    template call1(fun: typed; args: varargs[untyped]): untyped =
+      unpackVarargs(fun, args)
+    template call2(fun: typed; args: varargs[untyped]): untyped =
+      # fun(args) # works except for last case with empty `args`, pending bug #9996
+      when varargsLen(args) > 0: fun(args)
+      else: fun()
+
+    proc fn1(a = 0, b = 1) = discard (a, b)
+
+    call1(fn1)
+    call1(fn1, 10)
+    call1(fn1, 10, 11)
+
+    call2(fn1)
+    call2(fn1, 10)
+    call2(fn1, 10, 11)
+
+  block:
+    template call1(fun: typed; args: varargs[typed]): untyped =
+      unpackVarargs(fun, args)
+    template call2(fun: typed; args: varargs[typed]): untyped =
+      # xxx this would give a confusing error message:
+      # required type for a: varargs[typed] [varargs] but expression '[10]' is of type: varargs[typed] [varargs]
+      when varargsLen(args) > 0: fun(args)
+      else: fun()
+    macro toString(a: varargs[typed, `$`]): string =
+      var msg = genSym(nskVar, "msg")
+      result = newStmtList()
+      result.add quote do:
+        var `msg` = ""
+      for ai in a:
+        result.add quote do: `msg`.add $`ai`
+      result.add quote do: `msg`
+    doAssert call1(toString) == ""
+    doAssert call1(toString, 10) == "10"
+    doAssert call1(toString, 10, 11) == "1011"
+
+block: # SameType
+  type
+    A = int
+    B = distinct int
+    C = object
+    Generic[T, Y] = object
+  macro isSameType(a, b: typed): untyped =
+    newLit(sameType(a, b))
+
+  static:
+    assert Generic[int, int].isSameType(Generic[int, int])
+    assert Generic[A, string].isSameType(Generic[int, string])
+    assert not Generic[A, string].isSameType(Generic[B, string])
+    assert not Generic[int, string].isSameType(Generic[int, int])
+    assert isSameType(int, A)
+    assert isSameType(10, 20)
+    assert isSameType("Hello", "world")
+    assert not isSameType("Hello", cstring"world")
+    assert not isSameType(int, B)
+    assert not isSameType(int, Generic[int, int])
+    assert not isSameType(C, string)
+    assert not isSameType(C, int)
+
+
+  #[
+    # compiler sameType fails for the following, read more in `types.nim`'s `sameTypeAux`.
+    type
+      D[T] = C
+      G[T] = T
+    static:
+      assert isSameType(D[int], C)
+      assert isSameType(D[int], D[float])
+      assert isSameType(G[float](1.0), float(1.0))
+      assert isSameType(float(1.0), G[float](1.0))
+  ]#
+
+  type Tensor[T] = object
+    data: T
+
+  macro testTensorInt(x: typed): untyped =
+    let
+      tensorIntType = getTypeInst(Tensor[int])[1]
+      xTyp = x.getTypeInst
+    
+    newLit(xTyp.sameType(tensorIntType))
+
+  var
+    x: Tensor[int]
+    x1 = Tensor[float]()
+    x2 = Tensor[A]()
+    x3 = Tensor[B]()
+
+  static: 
+    assert testTensorInt(x)
+    assert not testTensorInt(x1)
+    assert testTensorInt(x2)
+    assert not testTensorInt(x3)
+
+block: # extractDocCommentsAndRunnables
+  macro checkRunnables(prc: untyped) =
+    let runnables = prc.body.extractDocCommentsAndRunnables()
+    doAssert runnables[0][0].eqIdent("runnableExamples")
+
+  macro checkComments(comment: static[string], prc: untyped) =
+    let comments = prc.body.extractDocCommentsAndRunnables()
+    doAssert comments[0].strVal == comment
+    
+  proc a() {.checkRunnables.} =
+    runnableExamples: discard
+    discard
+
+  proc b() {.checkRunnables.} =
+    runnableExamples "-d:ssl": discard
+    discard
+    
+  proc c() {.checkComments("Hello world").} =
+    ## Hello world
+
+block: # bug #19020
+  type
+    foo = object
+
+  template typ(T:typedesc) {.pragma.}
+
+  proc bar() {.typ: foo.} = discard
+
+  static:
+    doAssert $bar.getCustomPragmaVal(typ) == "foo"
+  doAssert $bar.getCustomPragmaVal(typ) == "foo"
+
+block hasCustomPragmaGeneric:
+  template examplePragma() {.pragma.}
+  type
+    Foo[T] {.examplePragma.} = object
+      x {.examplePragma.}: T
+  var f: Foo[string]
+  doAssert f.hasCustomPragma(examplePragma)
+  doAssert f.x.hasCustomPragma(examplePragma)
+
+block getCustomPragmaValGeneric:
+  template examplePragma(x: int) {.pragma.}
+  type
+    Foo[T] {.examplePragma(42).} = object
+      x {.examplePragma(25).}: T
+  var f: Foo[string]
+  doAssert f.getCustomPragmaVal(examplePragma) == 42
+  doAssert f.x.getCustomPragmaVal(examplePragma) == 25
+
+block: # bug #21326
+  macro foo(body: untyped): untyped =
+    let a = body.lineInfoObj()
+    let aLit = a.newLit
+    result = quote do:
+      doAssert $`a` == $`aLit`
+
+  foo:
+    let c = 1
+
+  template name(a: LineInfo): untyped =
+    discard a # `aLit` works though
+
+  macro foo3(body: untyped): untyped =
+    let a = body.lineInfoObj()
+    # let ax = newLit(a)
+    result = getAst(name(a))
+
+  foo3:
+    let c = 1
+
+block: # bug #7375
+  macro fails(b: static[bool]): untyped =
+    doAssert b == false
+    result = newStmtList()
+
+  macro foo(): untyped =
+
+    var b = false
+
+    ## Fails
+    result = quote do:
+      fails(`b`)
+
+  foo()
+
+  macro someMacro(): untyped =
+    template tmpl(boolean: bool) =
+      when boolean:
+        discard "it's true!"
+      else:
+        doAssert false
+    result = getAst(tmpl(true))
+
+  someMacro()
+
+block:
+  macro foo(): untyped =
+    result = quote do: `littleEndian`
+
+  doAssert littleEndian == foo()
+
+block:
+  macro eqSym(x, y: untyped): untyped =
+    let eq = $x == $y # Unfortunately eqIdent compares to string.
+    result = quote do: `eq`
+
+  var r, a, b: int
+
+  template fma(result: var int, a, b: int, op: untyped) =
+    # fused multiple-add
+    when eqSym(op, `+=`):
+      discard "+="
+    else:
+      discard "+"
+
+  fma(r, a, b, `+=`)
+
+block:
+  template test(boolArg: bool) =
+    static:
+      doAssert typeof(boolArg) is bool
+    let x: bool = boolArg # compile error here, because boolArg became an int
+
+  macro testWrapped1(boolArg: bool): untyped =
+    # forwarding boolArg directly works
+    result = getAst(test(boolArg))
+
+  macro testWrapped2(boolArg: bool): untyped =
+    # forwarding boolArg via a local variable also works
+    let b = boolArg
+    result = getAst(test(b))
+
+  macro testWrapped3(boolArg: bool): untyped =
+    # but using a literal `true` as a local variable will be converted to int
+    let b = true
+    result = getAst(test(b))
+
+  test(true) # ok
+  testWrapped1(true) # ok
+  testWrapped2(true) # ok
+  testWrapped3(true) 
+
+block:
+  macro foo(): untyped =
+    var s = { 'a', 'b' }
+    quote do:              
+      let t = `s`         
+      doAssert $typeof(t) == "set[char]"
+
+  foo()
+
+block: # bug #9607
+  proc fun1(info:LineInfo): string = "bar"
+  proc fun2(info:int): string = "bar"
+
+  macro echoL(args: varargs[untyped]): untyped =
+    let info = args.lineInfoObj
+    let fun1 = bindSym"fun1"
+    let fun2 = bindSym"fun2"
+
+    # this would work instead
+    # result = newCall(bindSym"fun2", info.line.newLit)
+
+    result = quote do:
+
+      # BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil
+      `fun1`(`info`)
+
+  macro echoM(args: varargs[untyped]): untyped =
+    let info = args.lineInfoObj
+    let fun1 = bindSym"fun1"
+    let fun2 = bindSym"fun2"
+
+    # this would work instead
+    # result = newCall(bindSym"fun2", info.line.newLit)
+
+    result = quote do:
+
+      # BUG1: ???(0, 0) Error: internal error: genLiteral: ty is nil
+      `fun2`(`info`.line)
+
+
+  doAssert echoL() == "bar"
+  doAssert echoM() == "bar"
+
+block:
+  macro hello[T](x: T): untyped =
+    result = quote do:
+      let m: `T` = `x`
+      discard m
+
+  hello(12)
+
+block:
+  proc hello(x: int, y: typedesc) =
+    discard
+
+  macro main =
+    let x = 12
+    result = quote do:
+      `hello`(12, type(x))
+
+  main()
+
+block: # bug #22947
+  macro bar[N: static int](a: var array[N, int]) =
+    result = quote do:
+      for i in 0 ..< `N`:
+        `a`[i] = i
+
+  func foo[N: static int](a: var array[N, int]) =
+    bar(a)
+
+
+  var a: array[4, int]
+  foo(a)
diff --git a/tests/stdlib/tmarshal.nim b/tests/stdlib/tmarshal.nim
new file mode 100644
index 000000000..32991ccc9
--- /dev/null
+++ b/tests/stdlib/tmarshal.nim
@@ -0,0 +1,233 @@
+discard """
+  matrix: "--mm:orc; --mm:refc"
+"""
+
+import std/marshal
+import std/[assertions, objectdollar, streams]
+
+# TODO: add static tests
+
+proc testit[T](x: T): string = $$to[T]($$x)
+
+template check1 =
+  let test1: array[0..1, array[0..4, string]] = [
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]
+  doAssert testit(test1) ==
+    """[["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"]]"""
+  let test2: tuple[name: string, s: int] = ("tuple test", 56)
+  doAssert testit(test2) == """{"Field0": "tuple test", "Field1": 56}"""
+
+static: check1()
+check1()
+
+type
+  TE = enum
+    blah, blah2
+
+  TestObj = object
+    test, asd: int
+    case test2: TE
+    of blah:
+      help: string
+    else:
+      discard
+
+  PNode = ref TNode
+  TNode = object
+    next, prev: PNode
+    data: string
+
+proc buildList(): PNode =
+  new(result)
+  new(result.next)
+  new(result.prev)
+  result.data = "middle"
+  result.next.data = "next"
+  result.prev.data = "prev"
+  result.next.next = result.prev
+  result.next.prev = result
+  result.prev.next = result
+  result.prev.prev = result.next
+
+let test3 = TestObj(test: 42, test2: blah)
+doAssert testit(test3) ==
+  """{"test": 42, "asd": 0, "test2": "blah", "help": ""}"""
+
+var test4: ref tuple[a, b: string]
+new(test4)
+test4.a = "ref string test: A"
+test4.b = "ref string test: B"
+discard testit(test4) # serialization uses the pointer address, which is not consistent
+
+let test5 = @[(0,1),(2,3),(4,5)]
+doAssert testit(test5) ==
+  """[{"Field0": 0, "Field1": 1}, {"Field0": 2, "Field1": 3}, {"Field0": 4, "Field1": 5}]"""
+
+let test6: set[char] = {'A'..'Z', '_'}
+doAssert testit(test6) ==
+  """[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 95]"""
+
+let test7 = buildList()
+discard testit(test7) # serialization uses the pointer address, which is not consistent
+
+
+# bug #1352
+block:
+  type
+    Entity = object of RootObj
+      name: string
+
+    Person = object of Entity
+      age: int
+      bio: string
+      blob: string
+
+  let instance1 = Person(name: "Cletus", age: 12,
+                         bio: "Я Cletus",
+                         blob: "ABC\x80")
+  doAssert $$instance1 == """{"age": 12, "bio": "Я Cletus", "blob": [65, 66, 67, 128], "name": "Cletus"}"""
+  doAssert to[Person]($$instance1).bio == instance1.bio
+  doAssert to[Person]($$instance1).blob == instance1.blob
+
+# bug #5757
+block:
+  type
+    Something = object
+      x: string
+      y: int
+
+  let data1 = """{"x": "alpha", "y": 100}"""
+  let data2 = """{"x": "omega", "y": 200}"""
+
+  var r = to[Something](data1)
+  doAssert $r.x & " " & $r.y == "alpha 100"
+  r = to[Something](data2)
+  doAssert $r.x & " " & $r.y == "omega 200"
+
+block:
+  type
+    Foo = object
+      a1: string
+      a2: string
+      a3: seq[string]
+      a4: seq[int]
+      a5: seq[int]
+      a6: seq[int]
+  var foo = Foo(a2: "", a4: @[], a6: @[1])
+  foo.a6.setLen 0
+  doAssert $$foo == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}"""
+  doAssert testit(foo) == """{"a1": "", "a2": "", "a3": [], "a4": [], "a5": [], "a6": []}"""
+
+import std/[options, json]
+
+# bug #15934
+block:
+  let
+    a1 = some(newJNull())
+    a2 = none(JsonNode)
+  doAssert $($$a1).to[:Option[JsonNode]] == "some(null)"
+  doAssert $($$a2).to[:Option[JsonNode]] == "none(JsonNode)"
+  doAssert ($$a1).to[:Option[JsonNode]] == some(newJNull())
+  doAssert ($$a2).to[:Option[JsonNode]] == none(JsonNode)
+
+# bug #15620
+block:
+  let str = """{"numeric": null}"""
+
+  type
+    LegacyEntry = object
+      numeric: string
+
+  let test = to[LegacyEntry](str)
+  doAssert $test == """(numeric: "")"""
+
+block:
+  let str = """{"numeric": null}"""
+
+  type
+    LegacyEntry = object
+      numeric: seq[int]
+
+  var test = to[LegacyEntry](str)
+  doAssert $test == """(numeric: @[])"""
+
+# bug #16022
+block:
+  let p: proc (): string = proc (): string = "hello world"
+  let poc = to[typeof(p)]($$p)
+  doAssert poc() == "hello world"
+
+block:
+  type
+    A {.inheritable.} = object
+    B = object of A
+      f: int
+
+  let a: ref A = new(B)
+  doAssert $$a[] == "{}" # not "{f: 0}"
+
+# bug #16496
+block:
+  type
+    A = ref object
+      data: seq[int]
+
+    B = ref object
+      x: A
+  let o = A(data: @[1, 2, 3, 4])
+  let s1 = @[B(x: o), B(x: o)]
+  let m  = $$ s1
+  let s2 = to[seq[B]](m)
+  doAssert s2[0].x.data == s2[1].x.data
+  doAssert s1[0].x.data == s2[1].x.data
+
+
+block:
+  type
+    Obj = ref object
+      i: int
+      b: bool
+
+  let
+    strm = newStringStream()
+
+  var
+    o = Obj(i: 1, b: false)
+    t1 = @[o, o]
+    t2: seq[Obj]
+
+  doAssert t1[0] == t1[1]
+
+  strm.store(t1)
+  strm.setPosition(0)
+  strm.load(t2)
+  strm.close()
+
+  doAssert t2[0] == t2[1]
+
+
+template checkMarshal(data: typed) =
+  let orig = data
+  let m = $$orig
+
+  let old = to[typeof(orig)](m)
+  doAssert data == old
+
+template main() =
+  type
+    Book = object
+      page: int
+      name: string
+
+  let book = Book(page: 12, name: "persona")
+
+  checkMarshal(486)
+  checkMarshal(3.14)
+  checkMarshal("azure sky")
+  checkMarshal(book)
+  checkMarshal([1, 2, 3])
+  checkMarshal(@[1.5, 2.7, 3.9, 4.2])
+  checkMarshal(@["dream", "is", "possible"])
+
+static: main()
+main()
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/tmath.nim b/tests/stdlib/tmath.nim
new file mode 100644
index 000000000..22e5f7d88
--- /dev/null
+++ b/tests/stdlib/tmath.nim
@@ -0,0 +1,473 @@
+discard """
+  targets: "c cpp js"
+  matrix:"; -d:danger; --mm:refc"
+"""
+
+# xxx: there should be a test with `-d:nimTmathCase2 -d:danger --passc:-ffast-math`,
+# but it requires disabling certain lines with `when not defined(nimTmathCase2)`
+
+import std/math
+import std/assertions
+
+
+# Function for approximate comparison of floats
+proc `==~`(x, y: float): bool = abs(x - y) < 1e-9
+
+
+template main() =
+  block:
+    when not defined(js):
+      # check for no side effect annotation
+      proc mySqrt(num: float): float {.noSideEffect.} =
+        # xxx unused
+        sqrt(num)
+
+      # check gamma function
+      doAssert gamma(5.0) == 24.0 # 4!
+      doAssert almostEqual(gamma(0.5), sqrt(PI))
+      doAssert almostEqual(gamma(-0.5), -2 * sqrt(PI))
+      doAssert lgamma(1.0) == 0.0 # ln(1.0) == 0.0
+      doAssert almostEqual(lgamma(0.5), 0.5 * ln(PI))
+      doAssert erf(6.0) > erf(5.0)
+      doAssert erfc(6.0) < erfc(5.0)
+
+  block: # sgn() tests
+    doAssert sgn(1'i8) == 1
+    doAssert sgn(1'i16) == 1
+    doAssert sgn(1'i32) == 1
+    doAssert sgn(1'i64) == 1
+    doAssert sgn(1'u8) == 1
+    doAssert sgn(1'u16) == 1
+    doAssert sgn(1'u32) == 1
+    doAssert sgn(1'u64) == 1
+    doAssert sgn(-12342.8844'f32) == -1
+    doAssert sgn(123.9834'f64) == 1
+    doAssert sgn(0'i32) == 0
+    doAssert sgn(0'f32) == 0
+    doAssert sgn(-0.0'f64) == 0
+    doAssert sgn(NegInf) == -1
+    doAssert sgn(Inf) == 1
+    doAssert sgn(NaN) == 0
+
+  block: # fac() tests
+    when nimvm: discard
+    else:
+      try:
+        discard fac(-1)
+      except AssertionDefect:
+        discard
+
+    doAssert fac(0) == 1
+    doAssert fac(1) == 1
+    doAssert fac(2) == 2
+    doAssert fac(3) == 6
+    doAssert fac(4) == 24
+    doAssert fac(5) == 120
+
+  block: # floorMod/floorDiv
+    doAssert floorDiv(8, 3) == 2
+    doAssert floorMod(8, 3) == 2
+
+    doAssert floorDiv(8, -3) == -3
+    doAssert floorMod(8, -3) == -1
+
+    doAssert floorDiv(-8, 3) == -3
+    doAssert floorMod(-8, 3) == 1
+
+    doAssert floorDiv(-8, -3) == 2
+    doAssert floorMod(-8, -3) == -2
+
+    doAssert floorMod(8.0, -3.0) == -1.0
+    doAssert floorMod(-8.5, 3.0) == 0.5
+
+  block: # euclDiv/euclMod
+    doAssert euclDiv(8, 3) == 2
+    doAssert euclMod(8, 3) == 2
+
+    doAssert euclDiv(8, -3) == -2
+    doAssert euclMod(8, -3) == 2
+
+    doAssert euclDiv(-8, 3) == -3
+    doAssert euclMod(-8, 3) == 1
+
+    doAssert euclDiv(-8, -3) == 3
+    doAssert euclMod(-8, -3) == 1
+
+    doAssert euclMod(8.0, -3.0) == 2.0
+    doAssert euclMod(-8.5, 3.0) == 0.5
+
+    doAssert euclDiv(9, 3) == 3
+    doAssert euclMod(9, 3) == 0
+
+    doAssert euclDiv(9, -3) == -3
+    doAssert euclMod(9, -3) == 0
+
+    doAssert euclDiv(-9, 3) == -3
+    doAssert euclMod(-9, 3) == 0
+
+    doAssert euclDiv(-9, -3) == 3
+    doAssert euclMod(-9, -3) == 0
+
+  block: # ceilDiv
+    doAssert ceilDiv(8,  3) ==  3
+    doAssert ceilDiv(8,  4) ==  2
+    doAssert ceilDiv(8,  5) ==  2
+    doAssert ceilDiv(11, 3) ==  4
+    doAssert ceilDiv(12, 3) ==  4
+    doAssert ceilDiv(13, 3) ==  5
+    doAssert ceilDiv(41, 7) ==  6
+    doAssert ceilDiv(0,  1) ==  0
+    doAssert ceilDiv(1,  1) ==  1
+    doAssert ceilDiv(1,  2) ==  1
+    doAssert ceilDiv(2,  1) ==  2
+    doAssert ceilDiv(2,  2) ==  1
+    doAssert ceilDiv(0, high(int)) == 0
+    doAssert ceilDiv(1, high(int)) == 1
+    doAssert ceilDiv(0, high(int) - 1) == 0
+    doAssert ceilDiv(1, high(int) - 1) == 1
+    doAssert ceilDiv(high(int) div 2, high(int) div 2 + 1) == 1
+    doAssert ceilDiv(high(int) div 2, high(int) div 2 + 2) == 1
+    doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2) == 2
+    doAssert ceilDiv(high(int) div 2 + 2, high(int) div 2) == 2
+    doAssert ceilDiv(high(int) div 2 + 1, high(int) div 2 + 1) == 1
+    doAssert ceilDiv(high(int), 1) == high(int)
+    doAssert ceilDiv(high(int) - 1, 1) == high(int) - 1
+    doAssert ceilDiv(high(int) - 1, 2) == high(int) div 2
+    doAssert ceilDiv(high(int) - 1, high(int)) == 1
+    doAssert ceilDiv(high(int) - 1, high(int) - 1) == 1
+    doAssert ceilDiv(high(int) - 1, high(int) - 2) == 2
+    doAssert ceilDiv(high(int), high(int)) == 1
+    doAssert ceilDiv(high(int), high(int) - 1) == 2
+    doAssert ceilDiv(255'u8,  1'u8) == 255'u8
+    doAssert ceilDiv(254'u8,  2'u8) == 127'u8
+    when not defined(danger):
+      doAssertRaises(AssertionDefect): discard ceilDiv(41,  0)
+      doAssertRaises(AssertionDefect): discard ceilDiv(41, -1)
+      doAssertRaises(AssertionDefect): discard ceilDiv(-1,  1)
+      doAssertRaises(AssertionDefect): discard ceilDiv(-1, -1)
+      doAssertRaises(AssertionDefect): discard ceilDiv(254'u8, 3'u8)
+      doAssertRaises(AssertionDefect): discard ceilDiv(255'u8, 2'u8)
+
+  block: # splitDecimal() tests
+    doAssert splitDecimal(54.674).intpart == 54.0
+    doAssert splitDecimal(54.674).floatpart ==~ 0.674
+    doAssert splitDecimal(-693.4356).intpart == -693.0
+    doAssert splitDecimal(-693.4356).floatpart ==~ -0.4356
+    doAssert splitDecimal(0.0).intpart == 0.0
+    doAssert splitDecimal(0.0).floatpart == 0.0
+
+  block: # trunc tests for vcc
+    doAssert trunc(-1.1) == -1
+    doAssert trunc(1.1) == 1
+    doAssert trunc(-0.1) == -0
+    doAssert trunc(0.1) == 0
+
+    # special case
+    doAssert classify(trunc(1e1000000)) == fcInf
+    doAssert classify(trunc(-1e1000000)) == fcNegInf
+    when not defined(nimTmathCase2):
+      doAssert classify(trunc(0.0/0.0)) == fcNan
+    doAssert classify(trunc(0.0)) == fcZero
+
+    # trick the compiler to produce signed zero
+    let
+      f_neg_one = -1.0
+      f_zero = 0.0
+      f_nan = f_zero / f_zero
+
+    doAssert classify(trunc(f_neg_one*f_zero)) == fcNegZero
+
+    doAssert trunc(-1.1'f32) == -1
+    doAssert trunc(1.1'f32) == 1
+    doAssert trunc(-0.1'f32) == -0
+    doAssert trunc(0.1'f32) == 0
+    doAssert classify(trunc(1e1000000'f32)) == fcInf
+    doAssert classify(trunc(-1e1000000'f32)) == fcNegInf
+    when not defined(nimTmathCase2):
+      doAssert classify(trunc(f_nan.float32)) == fcNan
+    doAssert classify(trunc(0.0'f32)) == fcZero
+  
+  block: # divmod
+    doAssert divmod(int.high, 1) == (int.high, 0)
+    doAssert divmod(-1073741823, 17) == (-63161283, -12)
+    doAssert divmod(int32.high, 1.int32) == (int32.high, 0.int32)
+    doAssert divmod(1073741823.int32, 5.int32) == (214748364.int32, 3.int32)
+    doAssert divmod(4611686018427387903.int64, 5.int64) == (922337203685477580.int64, 3.int64)
+    when not defined(js) and (not compileOption("panics")) and compileOption("overflowChecks"):
+      when nimvm:
+        discard # cannot catch OverflowDefect here
+      else:
+        doAssertRaises(OverflowDefect, (discard divmod(cint.low, -1.cint)))
+        doAssertRaises(OverflowDefect, (discard divmod(clong.low, -1.clong)))
+        doAssertRaises(OverflowDefect, (discard divmod(clonglong.low, -1.clonglong)))
+        doAssertRaises(DivByZeroDefect, (discard divmod(1, 0)))
+  
+  block: # log
+    doAssert log(4.0, 3.0) ==~ ln(4.0) / ln(3.0)
+    doAssert log2(8.0'f64) == 3.0'f64
+    doAssert log2(4.0'f64) == 2.0'f64
+    doAssert log2(2.0'f64) == 1.0'f64
+    doAssert log2(1.0'f64) == 0.0'f64
+    doAssert classify(log2(0.0'f64)) == fcNegInf
+
+    doAssert log2(8.0'f32) == 3.0'f32
+    doAssert log2(4.0'f32) == 2.0'f32
+    doAssert log2(2.0'f32) == 1.0'f32
+    doAssert log2(1.0'f32) == 0.0'f32
+    doAssert classify(log2(0.0'f32)) == fcNegInf
+
+  block: # cumsum
+    block: # cumsum int seq return
+      let counts = [1, 2, 3, 4]
+      doAssert counts.cumsummed == @[1, 3, 6, 10]
+      let empty: seq[int] = @[]
+      doAssert empty.cumsummed == @[]
+
+    block: # cumsum float seq return
+      let counts = [1.0, 2.0, 3.0, 4.0]
+      doAssert counts.cumsummed == @[1.0, 3.0, 6.0, 10.0]
+      let empty: seq[float] = @[]
+      doAssert empty.cumsummed == @[]
+
+    block: # cumsum int in-place
+      var counts = [1, 2, 3, 4]
+      counts.cumsum
+      doAssert counts == [1, 3, 6, 10]
+      var empty: seq[int] = @[]
+      empty.cumsum
+      doAssert empty == @[]
+
+    block: # cumsum float in-place
+      var counts = [1.0, 2.0, 3.0, 4.0]
+      counts.cumsum
+      doAssert counts == [1.0, 3.0, 6.0, 10.0]
+      var empty: seq[float] = @[]
+      empty.cumsum
+      doAssert empty == @[]
+
+  block: # ^ compiles for valid types
+    doAssert: compiles(5 ^ 2)
+    doAssert: compiles(5.5 ^ 2)
+    doAssert: compiles(5.5 ^ 2.int8)
+    doAssert: compiles(5.5 ^ 2.uint)
+    doAssert: compiles(5.5 ^ 2.uint8)
+    doAssert: not compiles(5.5 ^ 2.2)
+
+  block: # isNaN
+    doAssert NaN.isNaN
+    doAssert not Inf.isNaN
+    doAssert isNaN(Inf - Inf)
+    doAssert not isNaN(0.0)
+    doAssert not isNaN(3.1415926)
+    doAssert not isNaN(0'f32)
+
+  block: # signbit
+    doAssert not signbit(0.0)
+    doAssert signbit(-0.0)
+    doAssert signbit(-0.1)
+    doAssert not signbit(0.1)
+
+    doAssert not signbit(Inf)
+    doAssert signbit(-Inf)
+    doAssert not signbit(NaN)
+
+    let x1 = NaN
+    let x2 = -NaN
+    let x3 = -x1
+
+    doAssert isNaN(x1)
+    doAssert isNaN(x2)
+    doAssert isNaN(x3)
+    doAssert not signbit(x1)
+    doAssert signbit(x2)
+    doAssert signbit(x3)
+
+  block: # copySign
+    doAssert copySign(10.0, 1.0) == 10.0
+    doAssert copySign(10.0, -1.0) == -10.0
+    doAssert copySign(-10.0, -1.0) == -10.0
+    doAssert copySign(-10.0, 1.0) == 10.0
+    doAssert copySign(float(10), -1.0) == -10.0
+
+    doAssert copySign(10.0'f64, 1.0) == 10.0
+    doAssert copySign(10.0'f64, -1.0) == -10.0
+    doAssert copySign(-10.0'f64, -1.0) == -10.0
+    doAssert copySign(-10.0'f64, 1.0) == 10.0
+    doAssert copySign(10'f64, -1.0) == -10.0
+
+    doAssert copySign(10.0'f32, 1.0) == 10.0
+    doAssert copySign(10.0'f32, -1.0) == -10.0
+    doAssert copySign(-10.0'f32, -1.0) == -10.0
+    doAssert copySign(-10.0'f32, 1.0) == 10.0
+    doAssert copySign(10'f32, -1.0) == -10.0
+
+    doAssert copySign(Inf, -1.0) == -Inf
+    doAssert copySign(-Inf, 1.0) == Inf
+    doAssert copySign(Inf, 1.0) == Inf
+    doAssert copySign(-Inf, -1.0) == -Inf
+    doAssert copySign(Inf, 0.0) == Inf
+    doAssert copySign(Inf, -0.0) == -Inf
+    doAssert copySign(-Inf, 0.0) == Inf
+    doAssert copySign(-Inf, -0.0) == -Inf
+    doAssert copySign(1.0, -0.0) == -1.0
+    doAssert copySign(0.0, -0.0) == -0.0
+    doAssert copySign(-1.0, 0.0) == 1.0
+    doAssert copySign(10.0, 0.0) == 10.0
+    doAssert copySign(-1.0, NaN) == 1.0
+    doAssert copySign(10.0, NaN) == 10.0
+
+    doAssert copySign(NaN, NaN).isNaN
+    doAssert copySign(-NaN, NaN).isNaN
+    doAssert copySign(NaN, -NaN).isNaN
+    doAssert copySign(-NaN, -NaN).isNaN
+    doAssert copySign(NaN, 0.0).isNaN
+    doAssert copySign(NaN, -0.0).isNaN
+    doAssert copySign(-NaN, 0.0).isNaN
+    doAssert copySign(-NaN, -0.0).isNaN
+
+    doAssert copySign(-1.0, NaN) == 1.0
+    doAssert copySign(-1.0, -NaN) == -1.0
+    doAssert copySign(1.0, copySign(NaN, -1.0)) == -1.0
+
+  block: # almostEqual
+    doAssert almostEqual(3.141592653589793, 3.1415926535897936)
+    doAssert almostEqual(1.6777215e7'f32, 1.6777216e7'f32)
+    doAssert almostEqual(Inf, Inf)
+    doAssert almostEqual(-Inf, -Inf)
+    doAssert not almostEqual(Inf, -Inf)
+    doAssert not almostEqual(-Inf, Inf)
+    doAssert not almostEqual(Inf, NaN)
+    doAssert not almostEqual(NaN, NaN)
+
+  block: # round
+    block: # Round to 0 decimal places
+      doAssert round(54.652) == 55.0
+      doAssert round(54.352) == 54.0
+      doAssert round(-54.652) == -55.0
+      doAssert round(-54.352) == -54.0
+      doAssert round(0.0) == 0.0
+      doAssert 1 / round(0.0) == Inf
+      doAssert 1 / round(-0.0) == -Inf
+      doAssert round(Inf) == Inf
+      doAssert round(-Inf) == -Inf
+      doAssert round(NaN).isNaN
+      doAssert round(-NaN).isNaN
+      doAssert round(-0.5) == -1.0
+      doAssert round(0.5) == 1.0
+      doAssert round(-1.5) == -2.0
+      doAssert round(1.5) == 2.0
+      doAssert round(-2.5) == -3.0
+      doAssert round(2.5) == 3.0
+      doAssert round(2.5'f32) == 3.0'f32
+      doAssert round(2.5'f64) == 3.0'f64
+
+    block: # func round*[T: float32|float64](x: T, places: int): T
+      doAssert round(54.345, 0) == 54.0
+      template fn(x) =
+        doAssert round(x, 2).almostEqual 54.35
+        doAssert round(x, 2).almostEqual 54.35
+        doAssert round(x, -1).almostEqual 50.0
+        doAssert round(x, -2).almostEqual 100.0
+        doAssert round(x, -3).almostEqual 0.0
+      fn(54.346)
+      fn(54.346'f32)
+
+  block: # abs
+    doAssert 1.0 / abs(-0.0) == Inf
+    doAssert 1.0 / abs(0.0) == Inf
+    doAssert -1.0 / abs(-0.0) == -Inf
+    doAssert -1.0 / abs(0.0) == -Inf
+    doAssert abs(0.0) == 0.0
+    doAssert abs(0.0'f32) == 0.0'f32
+
+    doAssert abs(Inf) == Inf
+    doAssert abs(-Inf) == Inf
+    doAssert abs(NaN).isNaN
+    doAssert abs(-NaN).isNaN
+
+  block: # classify
+    doAssert classify(0.3) == fcNormal
+    doAssert classify(-0.3) == fcNormal
+    doAssert classify(5.0e-324) == fcSubnormal
+    doAssert classify(-5.0e-324) == fcSubnormal
+    doAssert classify(0.0) == fcZero
+    doAssert classify(-0.0) == fcNegZero
+    doAssert classify(NaN) == fcNan
+    doAssert classify(0.3 / 0.0) == fcInf
+    doAssert classify(Inf) == fcInf
+    doAssert classify(-0.3 / 0.0) == fcNegInf
+    doAssert classify(-Inf) == fcNegInf
+
+  block: # sum
+    let empty: seq[int] = @[]
+    doAssert sum(empty) == 0
+    doAssert sum([1, 2, 3, 4]) == 10
+    doAssert sum([-4, 3, 5]) == 4
+
+  block: # prod
+    let empty: seq[int] = @[]
+    doAssert prod(empty) == 1
+    doAssert prod([1, 2, 3, 4]) == 24
+    doAssert prod([-4, 3, 5]) == -60
+    doAssert almostEqual(prod([1.5, 3.4]), 5.1)
+    let x: seq[float] = @[]
+    doAssert prod(x) == 1.0
+
+  block: # clamp range
+    doAssert clamp(10, 1..5) == 5
+    doAssert clamp(3, 1..5) == 3
+    doAssert clamp(5, 1..5) == 5
+    doAssert clamp(42.0, 1.0 .. 3.1415926535) == 3.1415926535
+    doAssert clamp(NaN, 1.0 .. 2.0).isNaN
+    doAssert clamp(-Inf, -Inf .. -1.0) == -Inf
+    type A = enum a0, a1, a2, a3, a4, a5
+    doAssert a1.clamp(a2..a4) == a2
+    doAssert clamp((3, 0), (1, 0) .. (2, 9)) == (2, 9)
+
+  block: # edge cases
+    doAssert sqrt(-4.0).isNaN
+
+    doAssert ln(0.0) == -Inf
+    doAssert ln(-0.0) == -Inf
+    doAssert ln(-12.0).isNaN
+
+    doAssert log10(0.0) == -Inf
+    doAssert log10(-0.0) == -Inf
+    doAssert log10(-12.0).isNaN
+
+    doAssert log2(0.0) == -Inf
+    doAssert log2(-0.0) == -Inf
+    doAssert log2(-12.0).isNaN
+
+    when nimvm: discard
+    else:
+      doAssert frexp(0.0) == (0.0, 0)
+      doAssert frexp(-0.0) == (-0.0, 0)
+      doAssert classify(frexp(-0.0)[0]) == fcNegZero
+
+    when not defined(js):
+      doAssert gamma(0.0) == Inf
+      doAssert gamma(-0.0) == -Inf
+      doAssert gamma(-1.0).isNaN
+
+      doAssert lgamma(0.0) == Inf
+      doAssert lgamma(-0.0) == Inf
+      doAssert lgamma(-1.0) == Inf
+
+static: main()
+main()
+
+when not defined(js) and not defined(danger):
+  block: # bug #21792
+    block:
+      type Digit = 0..9
+      var x = [Digit 4, 7]
+
+      doAssertRaises(RangeDefect):
+        discard sum(x)
+
+    block:
+      var x = [int8 124, 127]
+
+      doAssertRaises(OverflowDefect):
+        discard sum(x)
diff --git a/tests/stdlib/tmemfiles1.nim b/tests/stdlib/tmemfiles1.nim
new file mode 100644
index 000000000..33657256c
--- /dev/null
+++ b/tests/stdlib/tmemfiles1.nim
@@ -0,0 +1,11 @@
+import memfiles, os
+import std/syncio
+
+var
+  mm: MemFile
+  fn = "test.mmap"
+# Create a new file
+mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 20)
+mm.close()
+# mm.close()
+if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemfiles2.nim b/tests/stdlib/tmemfiles2.nim
new file mode 100644
index 000000000..c79f85ebf
--- /dev/null
+++ b/tests/stdlib/tmemfiles2.nim
@@ -0,0 +1,43 @@
+discard """
+  disabled: "Windows"
+  output: '''Full read size: 20
+Half read size: 10 Data: Hello'''
+"""
+import memfiles, os
+import std/syncio
+
+
+const
+  fn = "test.mmap"
+var
+  mm, mm_full, mm_half: MemFile
+  p: pointer
+
+if fileExists(fn): removeFile(fn)
+
+# Create a new file, data all zeros, starting at size 10
+mm = memfiles.open(fn, mode = fmReadWrite, newFileSize = 10, allowRemap=true)
+mm.resize 20  # resize up to 20
+mm.close()
+
+# read, change
+mm_full = memfiles.open(fn, mode = fmWrite, mappedSize = -1, allowRemap = true)
+let size = mm_full.size
+p = mm_full.mapMem(fmReadWrite, 20, 0)
+echo "Full read size: ", size
+var p2 = cast[cstring](p)
+p2[0] = 'H'
+p2[1] = 'e'
+p2[2] = 'l'
+p2[3] = 'l'
+p2[4] = 'o'
+p2[5] = '\0'
+mm_full.unmapMem(p, 20)
+mm_full.close()
+
+# read half, and verify data change
+mm_half = memfiles.open(fn, mode = fmRead, mappedSize = 10)
+echo "Half read size: ", mm_half.size, " Data: ", cast[cstring](mm_half.mem)
+mm_half.close()
+
+if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemlines.nim b/tests/stdlib/tmemlines.nim
new file mode 100644
index 000000000..98e03b5bb
--- /dev/null
+++ b/tests/stdlib/tmemlines.nim
@@ -0,0 +1,9 @@
+discard """
+outputsub: ""
+"""
+
+import memfiles
+var inp = memfiles.open("tests/stdlib/tmemlines.nim")
+for line in lines(inp):
+  echo("#" & line & "#")
+close(inp)
diff --git a/tests/stdlib/tmemlinesBuf.nim b/tests/stdlib/tmemlinesBuf.nim
new file mode 100644
index 000000000..7bd89d4f2
--- /dev/null
+++ b/tests/stdlib/tmemlinesBuf.nim
@@ -0,0 +1,9 @@
+import std/[memfiles, assertions]
+var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim")
+var buffer: string = ""
+var lineCount = 0
+for line in lines(inp, buffer):
+  lineCount += 1
+
+close(inp)
+doAssert lineCount == 9, $lineCount # this file's number of lines
diff --git a/tests/stdlib/tmemmapstreams.nim b/tests/stdlib/tmemmapstreams.nim
new file mode 100644
index 000000000..9cfae62c7
--- /dev/null
+++ b/tests/stdlib/tmemmapstreams.nim
@@ -0,0 +1,55 @@
+discard """
+output: '''
+Created size: 10
+Position after writing: 5
+Position after writing one char: 6
+Peeked data: Hello
+Position after peeking: 0
+Readed data: Hello!
+Position after reading line: 7
+Position after setting position: 6
+Readed line: Hello!
+Position after reading line: 7'''
+"""
+import os, streams, memfiles
+import std/syncio
+
+const
+  fn = "test.mmapstream"
+var
+  mms: MemMapFileStream
+
+if fileExists(fn): removeFile(fn)
+
+# Create a new memory mapped file, data all zeros
+mms = newMemMapFileStream(fn, mode = fmReadWrite, fileSize = 10)
+mms.close()
+if fileExists(fn): echo "Created size: ", getFileSize(fn)
+
+# write, flush, peek, read
+mms = newMemMapFileStream(fn, mode = fmReadWrite)
+let s = "Hello"
+
+mms.write(s)
+mms.flush
+echo "Position after writing: ", mms.getPosition()
+mms.write('!')
+mms.flush
+echo "Position after writing one char: ", mms.getPosition()
+mms.close()
+
+mms = newMemMapFileStream(fn, mode = fmRead)
+echo "Peeked data: ", mms.peekStr(s.len)
+echo "Position after peeking: ", mms.getPosition()
+echo "Readed data: ", mms.readLine
+echo "Position after reading line: ", mms.getPosition()
+mms.setPosition(mms.getPosition() - 1)
+echo "Position after setting position: ", mms.getPosition()
+
+mms.setPosition(0)
+echo "Readed line: ", mms.readLine
+echo "Position after reading line: ", mms.getPosition()
+
+mms.close()
+
+if fileExists(fn): removeFile(fn)
diff --git a/tests/stdlib/tmemslices.nim b/tests/stdlib/tmemslices.nim
new file mode 100644
index 000000000..c0d6d3960
--- /dev/null
+++ b/tests/stdlib/tmemslices.nim
@@ -0,0 +1,12 @@
+discard """
+outputsub: "rlwuiadtrnzb"
+"""
+
+# chatever the sub pattern it will find itself
+
+import memfiles
+var inp = memfiles.open("tests/stdlib/tmemslices.nim")
+for mem in memSlices(inp):
+  if mem.size > 3:
+    echo("#" & $mem & "#")
+close(inp)
diff --git a/tests/stdlib/tmersenne.nim b/tests/stdlib/tmersenne.nim
new file mode 100644
index 000000000..64450a045
--- /dev/null
+++ b/tests/stdlib/tmersenne.nim
@@ -0,0 +1,13 @@
+import std/mersenne
+import std/assertions
+
+template main() =
+  var mt = newMersenneTwister(2525)
+
+  doAssert mt.getNum == 407788156'u32
+  doAssert mt.getNum == 1071751096'u32
+  doAssert mt.getNum == 3805347140'u32
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tmget.nim b/tests/stdlib/tmget.nim
new file mode 100644
index 000000000..f41963f02
--- /dev/null
+++ b/tests/stdlib/tmget.nim
@@ -0,0 +1,158 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''Can't access 6
+10
+11
+2
+Can't access 6
+10
+11
+2
+Can't access 6
+10
+11
+2
+Can't access 6
+10
+11
+2
+0
+10
+11
+0
+10
+11
+Can't access 6
+5
+Can't access 6
+10
+11
+Can't access 6
+10
+11'''
+"""
+
+import tables
+
+block:
+  var x = initTable[int, int]()
+  x[5] = 10
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+  x[5] += 1
+  var c = x[5]
+  echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
+
+block:
+  var x = newTable[int, int]()
+  x[5] = 10
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+  x[5] += 1
+  var c = x[5]
+  echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
+
+block:
+  var x = initOrderedTable[int, int]()
+  x[5] = 10
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+  x[5] += 1
+  var c = x[5]
+  echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
+
+block:
+  var x = newOrderedTable[int, int]()
+  x[5] = 10
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+  x[5] += 1
+  var c = x[5]
+  echo c
+  x.mgetOrPut(7).inc
+  x.mgetOrPut(7).inc
+  echo x[7]
+
+block:
+  var x = initCountTable[int]()
+  x[5] = 10
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+  x.inc 5, 1
+  var c = x[5]
+  echo c
+
+block:
+  var x = newCountTable[int]()
+  x[5] = 10
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+  x.inc 5, 1
+  var c = x[5]
+  echo c
+
+import sets
+
+block:
+  var x = initHashSet[int]()
+  x.incl 5
+  try:
+    echo x[6]
+  except KeyError:
+    echo "Can't access 6"
+  echo x[5]
+
+import critbits
+
+block:
+  var x: CritBitTree[int]
+  x["5"] = 10
+  try:
+    echo x["6"]
+  except KeyError:
+    echo "Can't access 6"
+  echo x["5"]
+  x["5"] += 1
+  var c = x["5"]
+  echo c
+
+import strtabs
+
+block:
+  var x = newStringTable()
+  x["5"] = "10"
+  try:
+    echo x["6"]
+  except KeyError:
+    echo "Can't access 6"
+  echo x["5"]
+  x["5"][1] = '1'
+  var c = x["5"]
+  echo c
diff --git a/tests/stdlib/tmimetypes.nim b/tests/stdlib/tmimetypes.nim
new file mode 100644
index 000000000..fd66ebd97
--- /dev/null
+++ b/tests/stdlib/tmimetypes.nim
@@ -0,0 +1,28 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/mimetypes
+import std/assertions
+
+
+template main() =
+  var m = newMimetypes()
+  doAssert m.getMimetype("mp4") == "video/mp4"
+  doAssert m.getExt("application/json") == "json"
+  doAssert m.getMimetype("json") == "application/json"
+  m.register("foo", "baa")
+  doAssert m.getMimetype("foo") == "baa"
+  doAssert m.getMimetype("txt") == "text/plain"
+  doAssert m.getExt("text/plain") == "txt"
+  # 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/tmisc_issues.nim b/tests/stdlib/tmisc_issues.nim
new file mode 100644
index 000000000..86dcf4162
--- /dev/null
+++ b/tests/stdlib/tmisc_issues.nim
@@ -0,0 +1,39 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/assertions
+
+# bug #20227
+type
+  Data = object
+    id: int
+
+  Test = distinct Data
+
+  Object = object
+    data: Test
+
+
+var x: Object = Object(data: Test(Data(id: 12)))
+doAssert Data(x.data).id == 12
+
+block: # bug #16771
+  type A = object
+    n: int
+
+  proc foo(a, b: var A) =
+    swap a, b
+
+  var a, b: A
+  a.n = 42
+  b.n = 1
+  doAssert a.n == 42
+  doAssert b.n == 1
+  a.swap b
+  doAssert a.n == 1
+  doAssert b.n == 42
+  a.foo b
+  doAssert a.n == 42
+  doAssert b.n == 1
diff --git a/tests/stdlib/tmitems.nim b/tests/stdlib/tmitems.nim
new file mode 100644
index 000000000..cc515a175
--- /dev/null
+++ b/tests/stdlib/tmitems.nim
@@ -0,0 +1,164 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''@[11, 12, 13]
+@[11, 12, 13]
+@[1, 3, 5]
+@[1, 3, 5]
+gppcbs
+gppcbs
+fpqeew
+fpqeew
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+[11, 12, 13]
+11 12 13
+[11,12,13]
+<Students>
+  <Student Name="Aprilfoo" />
+  <Student Name="bar" />
+</Students>
+<chapter>
+    <title>This is a Docbook title</title>
+    <para>
+        This is a Docbook paragraph containing <emphasis>emphasized</emphasis>,
+        <literal>literal</literal> and <replaceable>replaceable</replaceable>
+        text. Sometimes scrunched together like this:
+        <literal>literal</literal><replaceable>replaceable</replaceable>
+        and sometimes not:
+        <literal>literal</literal> <replaceable>replaceable</replaceable>
+    </para>
+</chapter>'''
+"""
+
+block:
+  var xs = @[1,2,3]
+  for x in xs.mitems:
+    x += 10
+  echo xs
+
+block:
+  var xs = [1,2,3]
+  for x in xs.mitems:
+    x += 10
+  echo(@xs)
+
+block:
+  var xs = @[1,2,3]
+  for i, x in xs.mpairs:
+    x += i
+  echo xs
+
+block:
+  var xs = [1,2,3]
+  for i, x in xs.mpairs:
+    x += i
+  echo(@xs)
+
+block:
+  var x = "foobar"
+  for c in x.mitems:
+    inc c
+  echo x
+
+block:
+  var x = "foobar"
+  prepareMutation(x)
+  var y = cast[cstring](addr x[0])
+  for c in y.mitems:
+    inc c
+  echo x
+
+block:
+  var x = "foobar"
+  for i, c in x.mpairs:
+    inc c, i
+  echo x
+
+block:
+  var x = "foobar"
+  prepareMutation(x)
+  var y = cast[cstring](addr x[0])
+  for i, c in y.mpairs:
+    inc c, i
+  echo x
+
+import lists
+
+block:
+  var sl = initSinglyLinkedList[int]()
+  sl.prepend(3)
+  sl.prepend(2)
+  sl.prepend(1)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+block:
+  var sl = initDoublyLinkedList[int]()
+  sl.append(1)
+  sl.append(2)
+  sl.append(3)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+block:
+  var sl = initDoublyLinkedRing[int]()
+  sl.append(1)
+  sl.append(2)
+  sl.append(3)
+  for x in sl.mitems:
+    x += 10
+  echo sl
+
+import deques
+
+block:
+  var q = initDeque[int]()
+  q.addLast(1)
+  q.addLast(2)
+  q.addLast(3)
+  for x in q.mitems:
+    x += 10
+  echo q
+
+import json
+
+block:
+  var j = parseJson """{"key1": 1, "key2": 2, "key3": 3}"""
+  for key,val in j.pairs:
+    val.num += 10
+  echo j["key1"], " ", j["key2"], " ", j["key3"]
+
+block:
+  var j = parseJson """[1, 2, 3]"""
+  for x in j.mitems:
+    x.num += 10
+  echo j
+
+import xmltree, xmlparser, parsexml, streams, strtabs
+
+block:
+  var d = parseXml(newStringStream """<Students>
+    <Student Name="April" Gender="F" DateOfBirth="1989-01-02" />
+    <Student Name="Bob" Gender="M"  DateOfBirth="1990-03-04" />
+  </Students>""")
+  for x in d.mitems:
+    x = <>Student(Name=x.attrs["Name"] & "foo")
+  d[1].attrs["Name"] = "bar"
+  echo d
+
+block:
+  var d = parseXml(newStringStream """<chapter>
+    <title>This is a Docbook title</title>
+    <para>
+        This is a Docbook paragraph containing <emphasis>emphasized</emphasis>,
+        <literal>literal</literal> and <replaceable>replaceable</replaceable>
+        text. Sometimes scrunched together like this:
+        <literal>literal</literal><replaceable>replaceable</replaceable>
+        and sometimes not:
+        <literal>literal</literal> <replaceable>replaceable</replaceable>
+    </para>
+</chapter>""",{reportComments, reportWhitespace})
+  echo d
diff --git a/tests/stdlib/tmonotimes.nim b/tests/stdlib/tmonotimes.nim
new file mode 100644
index 000000000..1366dbfe9
--- /dev/null
+++ b/tests/stdlib/tmonotimes.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/[monotimes, times]
+import std/assertions
+
+let d = initDuration(nanoseconds = 10)
+let t1 = getMonoTime()
+let t2 = t1 + d
+
+doAssert t2 - t1 == d
+doAssert t1 == t1
+doAssert t1 != t2
+doAssert t2 - d == t1
+doAssert t1 < t2
+doAssert t1 <= t2
+doAssert t1 <= t1
+doAssert not(t2 < t1)
+doAssert t1 < high(MonoTime)
+doAssert low(MonoTime) < t1
diff --git a/tests/stdlib/tnativesockets.nim b/tests/stdlib/tnativesockets.nim
new file mode 100644
index 000000000..8242beb83
--- /dev/null
+++ b/tests/stdlib/tnativesockets.nim
@@ -0,0 +1,30 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/nativesockets
+import stdtest/testutils
+import std/assertions
+
+block:
+  let hostname = getHostname()
+  doAssert hostname.len > 0
+
+when defined(windows):
+  assertAll:
+    toInt(IPPROTO_IP) == 0
+    toInt(IPPROTO_ICMP) == 1
+    toInt(IPPROTO_TCP) == 6
+    toInt(IPPROTO_UDP) == 17
+    toInt(IPPROTO_IPV6) == 41
+    toInt(IPPROTO_ICMPV6) == 58
+    toInt(IPPROTO_RAW) == 20
+
+    # no changes to enum value
+    ord(IPPROTO_TCP) == 6
+    ord(IPPROTO_UDP) == 17
+    ord(IPPROTO_IP) == 18
+    ord(IPPROTO_IPV6) == 19
+    ord(IPPROTO_RAW) == 20
+    ord(IPPROTO_ICMP) == 21
+    ord(IPPROTO_ICMPV6) == 22
diff --git a/tests/stdlib/tnet.nim b/tests/stdlib/tnet.nim
new file mode 100644
index 000000000..27a6ac49c
--- /dev/null
+++ b/tests/stdlib/tnet.nim
@@ -0,0 +1,130 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+outputsub: ""
+"""
+
+import net, nativesockets
+import unittest
+import std/assertions
+
+block: # isIpAddress tests
+  block: # 127.0.0.1 is valid
+    check isIpAddress("127.0.0.1") == true
+
+  block: # ipv6 localhost is valid
+    check isIpAddress("::1") == true
+
+  block: # fqdn is not an ip address
+    check isIpAddress("example.com") == false
+
+  block: # random string is not an ipaddress
+    check isIpAddress("foo bar") == false
+
+  block: # 5127.0.0.1 is invalid
+    check isIpAddress("5127.0.0.1") == false
+
+  block: # ipv6 is valid
+    check isIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652") == true
+
+  block: # invalid ipv6
+    check isIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652") == false
+
+
+block: # parseIpAddress tests
+  block: # 127.0.0.1 is valid
+    discard parseIpAddress("127.0.0.1")
+
+  block: # ipv6 localhost is valid
+    discard parseIpAddress("::1")
+
+  block: # fqdn is not an ip address
+    expect(ValueError):
+      discard parseIpAddress("example.com")
+
+  block: # random string is not an ipaddress
+    expect(ValueError):
+      discard parseIpAddress("foo bar")
+
+  block: # ipv6 is valid
+    discard parseIpAddress("2001:cdba:0000:0000:0000:0000:3257:9652")
+
+  block: # invalid ipv6
+    expect(ValueError):
+      discard parseIpAddress("gggg:cdba:0000:0000:0000:0000:3257:9652")
+
+  block: # ipv4-compatible ipv6 address (embedded ipv4 address)
+    check parseIpAddress("::ffff:10.0.0.23") == parseIpAddress("::ffff:0a00:0017")
+
+  block: # octal number in ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("010.8.8.8")
+    expect(ValueError):
+      discard parseIpAddress("8.010.8.8")
+
+  block: # hexadecimal number in ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("0xc0.168.0.1")
+    expect(ValueError):
+      discard parseIpAddress("192.0xa8.0.1")
+
+  block: # less than 4 numbers in ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("127.0.1")
+
+  block: # octal number in embedded ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("::ffff:010.8.8.8")
+    expect(ValueError):
+      discard parseIpAddress("::ffff:8.010.8.8")
+
+  block: # hexadecimal number in embedded ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("::ffff:0xc0.168.0.1")
+    expect(ValueError):
+      discard parseIpAddress("::ffff:192.0xa8.0.1")
+
+  block: # less than 4 numbers in embedded ipv4 address
+    expect(ValueError):
+      discard parseIpAddress("::ffff:127.0.1")
+
+block: # "IpAddress/Sockaddr conversion"
+  proc test(ipaddrstr: string) =
+    var ipaddr_1 = parseIpAddress(ipaddrstr)
+    # echo ipaddrstr, " ", $ipaddr_1
+
+    doAssert($ipaddrstr == $ipaddr_1)
+
+    var sockaddr: Sockaddr_storage
+    var socklen: SockLen
+    var ipaddr_2: IpAddress
+    var port_2: Port
+
+    toSockAddr(ipaddr_1, Port(0), sockaddr, socklen)
+    fromSockAddr(sockaddr, socklen, ipaddr_2, port_2)
+
+    doAssert(ipaddrstr == $ipaddr_1)
+
+    doAssert(ipaddr_1 == ipaddr_2)
+    doAssert($ipaddr_1 == $ipaddr_2)
+
+    if sockaddr.ss_family.cint == AF_INET.toInt:
+      var sockaddr4: Sockaddr_in
+      copyMem(addr sockaddr4, addr sockaddr, sizeof(sockaddr4))
+      fromSockAddr(sockaddr4, socklen, ipaddr_2, port_2)
+    elif sockaddr.ss_family.cint == AF_INET6.toInt:
+      var sockaddr6: Sockaddr_in6
+      copyMem(addr sockaddr6, addr sockaddr, sizeof(sockaddr6))
+      fromSockAddr(sockaddr6, socklen, ipaddr_2, port_2)
+
+    doAssert(ipaddr_1 == ipaddr_2)
+    doAssert($ipaddr_1 == $ipaddr_2)
+
+
+  # ipv6 address of example.com
+  test("2606:2800:220:1:248:1893:25c8:1946")
+  # ipv6 address of localhost
+  test("::1")
+  # ipv4 address of example.com
+  test("93.184.216.34")
+  # ipv4 address of localhost
+  test("127.0.0.1")
diff --git a/tests/stdlib/tnet_ll.nim b/tests/stdlib/tnet_ll.nim
new file mode 100644
index 000000000..199946482
--- /dev/null
+++ b/tests/stdlib/tnet_ll.nim
@@ -0,0 +1,52 @@
+discard """
+  action: run
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+
+[Suite] inet_ntop tests
+'''
+"""
+
+when defined(windows):
+  import winlean
+elif defined(posix):
+  import posix
+else:
+  {.error: "Unsupported OS".}
+
+import unittest, strutils
+
+suite "inet_ntop tests":
+
+  setup:
+    when defined(windows):
+      var wsa: WSAData
+      discard wsaStartup(0x101'i16, wsa.addr)
+  
+  test "IP V4":
+    # regular
+    var ip4 = InAddr()
+    ip4.s_addr = 0x10111213'u32
+    check: ip4.s_addr == 0x10111213'u32
+
+    var buff: array[0..255, char]
+    let r = inet_ntop(AF_INET, cast[pointer](ip4.s_addr.addr), cast[cstring](buff[0].addr), buff.len.int32)
+    let res = if r == nil: "" else: $r
+    check: res == "19.18.17.16"
+      
+  test "IP V6":
+    when defined(windows):
+      let ipv6Support = (getVersion() and 0xff) > 0x5
+    else:
+      let ipv6Support = true
+          
+    var ip6 = [0x1000'u16, 0x1001, 0x2000, 0x2001, 0x3000, 0x3001, 0x4000, 0x4001]
+    var buff: array[0..255, char]
+    let r = inet_ntop(AF_INET6, cast[pointer](ip6[0].addr), cast[cstring](buff[0].addr), buff.len.int32)
+    let res = if r == nil: "" else: $r
+    check: not ipv6Support or res == "10:110:20:120:30:130:40:140"
+
+  test "InAddr":
+    # issue 19244
+    var ip4 = InAddr(s_addr: 0x10111213'u32)
+    check: ip4.s_addr == 0x10111213'u32
diff --git a/tests/stdlib/tnetbind.nim b/tests/stdlib/tnetbind.nim
new file mode 100644
index 000000000..84f9ac464
--- /dev/null
+++ b/tests/stdlib/tnetbind.nim
@@ -0,0 +1,25 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+joinable: false
+"""
+
+#[
+joinable: false
+otherwise:
+Error: unhandled exception: Address already in use [OSError]
+]#
+
+import net
+
+## Test for net.bindAddr
+
+proc test() =
+  # IPv4 TCP
+  newSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1900), "0.0.0.0")
+  newSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1901))
+
+  # IPv6 TCP
+  newSocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1902), "::")
+  newSocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP).bindAddr(Port(1903))
+
+test()
diff --git a/tests/stdlib/tnetconnect.nim b/tests/stdlib/tnetconnect.nim
new file mode 100644
index 000000000..ae654aed9
--- /dev/null
+++ b/tests/stdlib/tnetconnect.nim
@@ -0,0 +1,30 @@
+discard """
+  disabled: "i386"
+  matrix: "-d:ssl"
+"""
+
+import std/net
+from std/strutils import `%`
+from stdtest/testutils import enableRemoteNetworking
+
+# bug #15215
+proc test() =
+  let ctx = newContext()
+
+  proc fn(url: string) =
+    let socket = newSocket()
+    defer: close(socket)
+    connect(socket, url, Port(443), 5000) # typically 20 could be enough
+    send(socket, "GET / HTTP/1.0\nHost: $#\nConnection: close\n\n" % [url])
+    wrapSocket(ctx, socket)
+
+  # trying 2 sites makes it more resilent: refs #17458 this could give:
+  # * Call to 'connect' timed out. [TimeoutError]
+  # * No route to host [OSError]
+  try:
+    fn("www.nim-lang.org")
+  except TimeoutError, OSError:
+    fn("www.google.com")
+
+when enableRemoteNetworking:
+  test()
diff --git a/tests/stdlib/tnetdial.nim b/tests/stdlib/tnetdial.nim
new file mode 100644
index 000000000..a1e147ad5
--- /dev/null
+++ b/tests/stdlib/tnetdial.nim
@@ -0,0 +1,62 @@
+discard """
+  cmd: "nim c --threads:on $file"
+  exitcode: 0
+  output: "OK"
+"""
+
+import os, net, nativesockets, asyncdispatch
+import std/[assertions, typedthreads]
+
+## Test for net.dial
+
+const port = Port(28431)
+
+proc initIPv6Server(hostname: string, port: Port): AsyncFD =
+  let fd = createNativeSocket(AF_INET6)
+  setSockOptInt(fd, SOL_SOCKET, SO_REUSEADDR, 1)
+  var aiList = getAddrInfo(hostname, port, AF_INET6)
+  if bindAddr(fd, aiList.ai_addr, aiList.ai_addrlen.SockLen) < 0'i32:
+    freeAddrInfo(aiList)
+    raiseOSError(osLastError())
+  freeAddrInfo(aiList)
+  if listen(fd) != 0:
+    raiseOSError(osLastError())
+  setBlocking(fd, false)
+
+  var serverFd = fd.AsyncFD
+  register(serverFd)
+  result = serverFd
+
+# Since net.dial is synchronous, we use main thread to setup server,
+# and dial to it from another thread.
+
+proc testThread() {.thread.} =
+  let fd = net.dial("::1", port)
+  var s = newString(5)
+  doAssert fd.recv(addr s[0], 5) == 5
+  if s == "Hello":
+    echo "OK"
+  fd.close()
+
+proc test() =
+  let serverFd = initIPv6Server("::1", port)
+  var t: Thread[void]
+  createThread(t, testThread)
+
+  var done = false
+
+  serverFd.accept().callback = proc(fut: Future[AsyncFD]) =
+    serverFd.closeSocket()
+    if not fut.failed:
+      let fd = fut.read()
+      fd.send("Hello").callback = proc() =
+        fd.closeSocket()
+        done = true
+
+  while not done:
+    poll()
+
+  joinThread(t)
+
+# this would cause #13132 `for i in 0..<10000: test()`
+test()
diff --git a/tests/stdlib/tnre.nim b/tests/stdlib/tnre.nim
new file mode 100644
index 000000000..3b40e9e83
--- /dev/null
+++ b/tests/stdlib/tnre.nim
@@ -0,0 +1,16 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+# Since the tests for nre are all bundled together we treat failure in one test as an nre failure
+# When running 'testament/tester' a failed check() in the test suite will cause the exit
+# codes to differ and be reported as a failure
+"""
+
+import nre
+import nre/init
+import nre/captures
+import nre/find
+import nre/split
+import nre/match
+import nre/replace
+import nre/escape
+import nre/misc
diff --git a/tests/stdlib/tntpath.nim b/tests/stdlib/tntpath.nim
new file mode 100644
index 000000000..8efdd6bd0
--- /dev/null
+++ b/tests/stdlib/tntpath.nim
@@ -0,0 +1,50 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/ntpath
+import std/assertions
+
+block: # From Python's `Lib/test/test_ntpath.py`
+  doAssert splitDrive(r"c:\foo\bar") == (r"c:", r"\foo\bar")
+  doAssert splitDrive(r"c:/foo/bar") == (r"c:", r"/foo/bar")
+  doAssert splitDrive(r"\\conky\mountpoint\foo\bar") == (r"\\conky\mountpoint", r"\foo\bar")
+  doAssert splitDrive(r"//conky/mountpoint/foo/bar") == (r"//conky/mountpoint", r"/foo/bar")
+  doAssert splitDrive(r"\\\conky\mountpoint\foo\bar") == (r"", r"\\\conky\mountpoint\foo\bar")
+  doAssert splitDrive(r"///conky/mountpoint/foo/bar") == (r"", r"///conky/mountpoint/foo/bar")
+  doAssert splitDrive(r"\\conky\\mountpoint\foo\bar") == (r"", r"\\conky\\mountpoint\foo\bar")
+  doAssert splitDrive(r"//conky//mountpoint/foo/bar") == (r"", r"//conky//mountpoint/foo/bar")
+  # Issue #19911: UNC part containing U+0130
+  doAssert splitDrive(r"//conky/MOUNTPOİNT/foo/bar") == (r"//conky/MOUNTPOİNT", r"/foo/bar")
+  # gh-81790: support device namespace, including UNC drives.
+  doAssert splitDrive(r"//?/c:") == (r"//?/c:", r"")
+  doAssert splitDrive(r"//?/c:/") == (r"//?/c:", r"/")
+  doAssert splitDrive(r"//?/c:/dir") == (r"//?/c:", r"/dir")
+  doAssert splitDrive(r"//?/UNC") == (r"", r"//?/UNC")
+  doAssert splitDrive(r"//?/UNC/") == (r"", r"//?/UNC/")
+  doAssert splitDrive(r"//?/UNC/server/") == (r"//?/UNC/server/", r"")
+  doAssert splitDrive(r"//?/UNC/server/share") == (r"//?/UNC/server/share", r"")
+  doAssert splitDrive(r"//?/UNC/server/share/dir") == (r"//?/UNC/server/share", r"/dir")
+  doAssert splitDrive(r"//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam") == (r"//?/VOLUME{00000000-0000-0000-0000-000000000000}", r"/spam")
+  doAssert splitDrive(r"//?/BootPartition/") == (r"//?/BootPartition", r"/")
+
+  doAssert splitDrive(r"\\?\c:") == (r"\\?\c:", r"")
+  doAssert splitDrive(r"\\?\c:\") == (r"\\?\c:", r"\")
+  doAssert splitDrive(r"\\?\c:\dir") == (r"\\?\c:", r"\dir")
+  doAssert splitDrive(r"\\?\UNC") == (r"", r"\\?\UNC")
+  doAssert splitDrive(r"\\?\UNC\") == (r"", r"\\?\UNC\")
+  doAssert splitDrive(r"\\?\UNC\server\") == (r"\\?\UNC\server\", r"")
+  doAssert splitDrive(r"\\?\UNC\server\share") == (r"\\?\UNC\server\share", r"")
+  doAssert splitDrive(r"\\?\UNC\server\share\dir") == (r"\\?\UNC\server\share", r"\dir")
+  doAssert splitDrive(r"\\?\VOLUME{00000000-0000-0000-0000-000000000000}\spam") == (r"\\?\VOLUME{00000000-0000-0000-0000-000000000000}", r"\spam")
+  doAssert splitDrive(r"\\?\BootPartition\") == (r"\\?\BootPartition", r"\")
+
+block:
+  doAssert splitDrive(r"C:") == (r"C:", r"")
+  doAssert splitDrive(r"C:\") == (r"C:", r"\")
+  doAssert splitDrive(r"non/absolute/path") == (r"", r"non/absolute/path")
+
+  # Special for `\`-rooted paths on Windows. I don't know if this is correct,
+  # rbut `\` is not recognized as a drive, in contrast to `C:` or `\?\c:`.
+  # This behavior is the same for Python's `splitdrive` function.
+  doAssert splitDrive(r"\\") == (r"", r"\\")
diff --git a/tests/stdlib/tobjectdollar.nim b/tests/stdlib/tobjectdollar.nim
new file mode 100644
index 000000000..cf78fa255
--- /dev/null
+++ b/tests/stdlib/tobjectdollar.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "-d:nimPreviewSlimSystem"
+"""
+
+import std/assertions
+
+type Foo = object
+  a, b: int
+
+let x = Foo(a: 23, b: 45)
+doAssert not compiles($x)
+import std/objectdollar
+doAssert compiles($x)
+doAssert $x == "(a: 23, b: 45)"
diff --git a/tests/stdlib/toids.nim b/tests/stdlib/toids.nim
new file mode 100644
index 000000000..dd5b84c51
--- /dev/null
+++ b/tests/stdlib/toids.nim
@@ -0,0 +1,15 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/oids
+import std/assertions
+
+block: # genOid
+  let x = genOid()
+  doAssert ($x).len == 24
+
+block:
+  let x = genOid()
+  let y = parseOid(cstring($x))
+  doAssert x == y
diff --git a/tests/stdlib/topenssl.nim b/tests/stdlib/topenssl.nim
new file mode 100644
index 000000000..af259627f
--- /dev/null
+++ b/tests/stdlib/topenssl.nim
@@ -0,0 +1,46 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/wordwrap
+import openssl
+import std/assertions
+
+const PubKey = r"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAknKWvrdnncCIzBnIGrZ5qtZrPH+Yo3t7ag9WZIu6Gmc/JgIDDaZhJeyGW0YSnifeAEhooWvM4jDWhTEARzktalSHqYtmwI/1Oxwp6NTYH8akMe2LCpZ5pX9FVA6m9o2tkbdXatbDKRqeD4UA8Ow7Iyrdo6eb1SU8vk+26i+uXHTtsb25p8uf2ppOJrJCy+1vr8Gsnuwny1UdoYZTxMsxRFPf+UX/LrSXMHVq/oPVa3SJ4VHMpYrG/httAugVP6K58xiZ93jst63/dd0JL85mWJu1uS3uz92aL5O97xzth3wR4BbdmDUlN4LuTIwi6DtEcC7gUOTnOzH4zgp2b5RyHwIDAQAB"
+const PrivateKey = r"MIIEpAIBAAKCAQEAknKWvrdnncCIzBnIGrZ5qtZrPH+Yo3t7ag9WZIu6Gmc/JgIDDaZhJeyGW0YSnifeAEhooWvM4jDWhTEARzktalSHqYtmwI/1Oxwp6NTYH8akMe2LCpZ5pX9FVA6m9o2tkbdXatbDKRqeD4UA8Ow7Iyrdo6eb1SU8vk+26i+uXHTtsb25p8uf2ppOJrJCy+1vr8Gsnuwny1UdoYZTxMsxRFPf+UX/LrSXMHVq/oPVa3SJ4VHMpYrG/httAugVP6K58xiZ93jst63/dd0JL85mWJu1uS3uz92aL5O97xzth3wR4BbdmDUlN4LuTIwi6DtEcC7gUOTnOzH4zgp2b5RyHwIDAQABAoIBACSOxmLFlfAjaALLTNCeTLEA5bQshgYJhT1sprxixQpiS7lJN0npBsdYzBFs5KjmetzHNpdVOcgdOO/204L0Gwo4H8WLLxNS3HztAulEeM813zc3fUYfWi6eHshk//j8VR/TDNd21TElm99z7FA4KGsXAE0iQhxrN0aqz5aWYIhjprtHA5KxXIiESnTkof5Cud8oXEnPiwPGNhq93QeQzh7xQIKSaDKBcdAa6edTFhzc4RLUQRfrik/GqJzouEDQ9v6H/uiOLTB3FxxwErQIf6dvSVhD9gs1nSLQfyj3S2Hxe9S2zglTl07EsawTQUxtVQkdZUOok67c7CPBxecZ2wECgYEA2c31gr/UJwczT+P/AE52GkHHETXMxqE3Hnh9n4CitfAFSD5X0VwZvGjZIlln2WjisTd92Ymf65eDylX2kCm93nzZ2GfXgS4zl4oY1N87+VeNQlx9f2+6GU7Hs0HFdfu8bGd+0sOuWA1PFqQCobxCACMPTkuzsG9M7knUTN59HS8CgYEArCEoP4ReYoOFveXUE0AteTPb4hryvR9VDEolP+LMoiPe8AzBMeB5fP493TPdjtnWmrPCXNLc7UAFSj2CZsRhau4PuiqnNrsb5iz/7iXVl3E8wZvS4w7WYpO4m33L0cijA6MdcdqilQu4Z5tw4nG45lAW9UYyOc9D4hJTzgtGHhECgYA6QyDoj931brSoK0ocT+DB11Sj4utbOuberMaV8zgTSRhwodSl+WgdAUMMMDRacPcrBrgQiAMSZ15msqYZHEFhEa7Id8arFKvSXquTzf9iDKyJ0unzO/ThLjS3W+GxVNyrdufzA0tQ3IaKfOcDUrOpC7fdbtyrVqqSl4dF5MI9GwKBgQCl3OF6qyOEDDZgsUk1L59h7k3QR6VmBf4e9IeGUxZamvQlHjU/yY1nm1mjgGnbUB/SPKtqZKoMV6eBTVoNiuhQcItpGda9D3mnx+7p3T0/TBd+fJeuwcplfPDjrEktogcq5w/leQc3Ve7gr1EMcwb3r28f8/9L42QHQR/OKODs8QKBgQCFAvxDRPyYg7V/AgD9rt1KzXi4+b3Pls5NXZa2g/w+hmdhHUNxV5IGmHlqFnptGyshgYgQGxMMkW0iJ1j8nLamFnkbFQOp5/UKbdPLRKiB86oPpxsqYtPXucDUqEfcMsp57mD1CpGVODbspogFpSUvQpMECkhvI0XLMbolMdo53g=="
+
+proc rsaPublicEncrypt(fr: string): string =
+  let mKey = "-----BEGIN PUBLIC KEY-----\n" & PubKey.wrapWords(64) & "\n-----END PUBLIC KEY-----"
+  let bio = bioNew(bioSMem())
+  doAssert BIO_write(bio, mKey.cstring, mKey.len.cint) >= 0
+  let rsa = PEM_read_bio_RSA_PUBKEY(bio, nil, nil, nil)
+  doAssert rsa != nil
+  doAssert BIO_free(bio) >= 0
+  result = newString(RSA_size(rsa))
+  let frdata = cast[ptr uint8](fr.cstring)
+  var todata = cast[ptr uint8](result.cstring)
+  doAssert RSA_public_encrypt(fr.len.cint, frdata, todata, rsa, RSA_PKCS1_PADDING) != -1
+  RSA_free(rsa)
+
+proc rasPrivateDecrypt(fr: string): string =
+  let mKey = "-----BEGIN RSA PRIVATE KEY-----\n" & PrivateKey.wrapWords(64) & "\n-----END RSA PRIVATE KEY-----"
+  let bio = bioNew(bioSMem())
+  doAssert BIO_write(bio, mKey.cstring, mKey.len.cint) >= 0
+  let rsa = PEM_read_bio_RSAPrivateKey(bio, nil, nil, nil)
+  doAssert rsa != nil
+  doAssert BIO_free(bio) >= 0
+  let rsaLen = RSA_size(rsa)
+  result = newString(rsaLen)
+  let frdata = cast[ptr uint8](fr.cstring)
+  var todata = cast[ptr uint8](result.cstring)
+  let lenOrig = RSA_private_decrypt(rsaLen, frdata, todata, rsa, RSA_PKCS1_PADDING)
+  doAssert lenOrig >= 0 and lenOrig < result.len
+  doAssert result[lenOrig] == '\0'
+  result.setLen lenOrig
+  RSA_free(rsa)
+
+let res = "TEST"
+let miwen = rsaPublicEncrypt(res)
+let mingwen = rasPrivateDecrypt(miwen)
+doAssert mingwen == res
+
diff --git a/tests/stdlib/toptions.nim b/tests/stdlib/toptions.nim
new file mode 100644
index 000000000..63a10e746
--- /dev/null
+++ b/tests/stdlib/toptions.nim
@@ -0,0 +1,207 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/[json, options]
+
+import std/assertions
+import std/objectdollar
+
+
+# RefPerson is used to test that overloaded `==` operator is not called by
+# options. It is defined here in the global scope, because otherwise the test
+# will not even consider the `==` operator. Different bug?
+type RefPerson = ref object
+  name: string
+
+proc `==`(a, b: RefPerson): bool =
+  assert(not a.isNil and not b.isNil)
+  a.name == b.name
+
+
+template disableJsVm(body) =
+  # something doesn't work in JS VM
+  when defined(js):
+    when nimvm: discard
+    else: body
+  else:
+    body
+
+proc main() =
+  type
+    Foo = ref object
+      test: string
+    Test = object
+      foo: Option[Foo]
+
+  let js = """{"foo": {"test": "123"}}"""
+  let parsed = parseJson(js)
+  let a = parsed.to(Test)
+  doAssert $(%*a) == """{"foo":{"test":"123"}}"""
+
+  block options:
+    # work around a bug in unittest
+    let intNone = none(int)
+    let stringNone = none(string)
+
+    block example:
+      proc find(haystack: string, needle: char): Option[int] =
+        for i, c in haystack:
+          if c == needle:
+            return some i
+
+      doAssert("abc".find('c').get() == 2)
+
+      let result = "team".find('i')
+
+      doAssert result == intNone
+      doAssert result.isNone
+
+    block some:
+      doAssert some(6).get() == 6
+      doAssert some("a").unsafeGet() == "a"
+      doAssert some(6).isSome
+      doAssert some("a").isSome
+
+    block none:
+      doAssertRaises UnpackDefect:
+        discard none(int).get()
+      doAssert(none(int).isNone)
+      doAssert(not none(string).isSome)
+
+    block equality:
+      doAssert some("a") == some("a")
+      doAssert some(7) != some(6)
+      doAssert some("a") != stringNone
+      doAssert intNone == intNone
+
+      when compiles(some("a") == some(5)):
+        doAssert false
+      when compiles(none(string) == none(int)):
+        doAssert false
+
+    block get_with_a_default_value:
+      doAssert(some("Correct").get("Wrong") == "Correct")
+      doAssert(stringNone.get("Correct") == "Correct")
+
+    block stringify:
+      doAssert($(some("Correct")) == "some(\"Correct\")")
+      doAssert($(stringNone) == "none(string)")
+
+    disableJsVm:
+      block map_with_a_void_result:
+        var procRan = 0
+        # TODO closure anonymous functions doesn't work in VM with JS
+        # Error: cannot evaluate at compile time: procRan
+        some(123).map(proc (v: int) = procRan = v)
+        doAssert procRan == 123
+        intNone.map(proc (v: int) = doAssert false)
+
+    block map:
+      doAssert(some(123).map(proc (v: int): int = v * 2) == some(246))
+      doAssert(intNone.map(proc (v: int): int = v * 2).isNone)
+
+    block filter:
+      doAssert(some(123).filter(proc (v: int): bool = v == 123) == some(123))
+      doAssert(some(456).filter(proc (v: int): bool = v == 123).isNone)
+      doAssert(intNone.filter(proc (v: int): bool = doAssert false).isNone)
+
+    block flatMap:
+      proc addOneIfNotZero(v: int): Option[int] =
+        if v != 0:
+          result = some(v + 1)
+        else:
+          result = none(int)
+
+      doAssert(some(1).flatMap(addOneIfNotZero) == some(2))
+      doAssert(some(0).flatMap(addOneIfNotZero) == none(int))
+      doAssert(some(1).flatMap(addOneIfNotZero).flatMap(addOneIfNotZero) == some(3))
+
+      proc maybeToString(v: int): Option[string] =
+        if v != 0:
+          result = some($v)
+        else:
+          result = none(string)
+
+      doAssert(some(1).flatMap(maybeToString) == some("1"))
+
+      proc maybeExclaim(v: string): Option[string] =
+        if v != "":
+          result = some v & "!"
+        else:
+          result = none(string)
+
+      doAssert(some(1).flatMap(maybeToString).flatMap(maybeExclaim) == some("1!"))
+      doAssert(some(0).flatMap(maybeToString).flatMap(maybeExclaim) == none(string))
+
+    block SomePointer:
+      var intref: ref int
+      doAssert(option(intref).isNone)
+      intref.new
+      doAssert(option(intref).isSome)
+
+      let tmp = option(intref)
+      doAssert(sizeof(tmp) == sizeof(ptr int))
+
+      var prc = proc (x: int): int = x + 1
+      doAssert(option(prc).isSome)
+      prc = nil
+      doAssert(option(prc).isNone)
+
+    block:
+      doAssert(none[int]().isNone)
+      doAssert(none(int) == none[int]())
+
+    # "$ on typed with .name"
+    block:
+      type Named = object
+        name: string
+
+      let nobody = none(Named)
+      doAssert($nobody == "none(Named)")
+
+    # "$ on type with name()"
+    block:
+      type Person = object
+        myname: string
+
+      let noperson = none(Person)
+      doAssert($noperson == "none(Person)")
+
+    # "Ref type with overloaded `==`"
+    block:
+      let p = some(RefPerson.new())
+      doAssert p.isSome
+
+    block: # test cstring
+      block:
+        let x = some("".cstring)
+        doAssert x.isSome
+        doAssert x.get == ""
+
+      block:
+        let x = some("12345".cstring)
+        doAssert x.isSome
+        doAssert x.get == "12345"
+
+      block:
+        let x = "12345".cstring
+        let y = some(x)
+        doAssert y.isSome
+        doAssert y.get == "12345"
+
+      block:
+        let x = none(cstring)
+        doAssert x.isNone
+        doAssert $x == "none(cstring)"
+
+static: main()
+main()
+
+when not defined(js):
+  block: # bug #22932
+    var it = iterator: int {.closure.} = discard
+    doAssert it.option.isSome # Passes.
+    it = nil
+    doAssert it.option.isNone # Passes.
diff --git a/tests/stdlib/tos.nim b/tests/stdlib/tos.nim
new file mode 100644
index 000000000..611659fdb
--- /dev/null
+++ b/tests/stdlib/tos.nim
@@ -0,0 +1,875 @@
+discard """
+  output: '''
+All:
+__really_obscure_dir_name/are.x
+__really_obscure_dir_name/created
+__really_obscure_dir_name/dirs
+__really_obscure_dir_name/files.q
+__really_obscure_dir_name/some
+__really_obscure_dir_name/test
+__really_obscure_dir_name/testing.r
+__really_obscure_dir_name/these.txt
+Files:
+__really_obscure_dir_name/are.x
+__really_obscure_dir_name/files.q
+__really_obscure_dir_name/testing.r
+__really_obscure_dir_name/these.txt
+Dirs:
+__really_obscure_dir_name/created
+__really_obscure_dir_name/dirs
+__really_obscure_dir_name/some
+__really_obscure_dir_name/test
+Raises
+Raises
+'''
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+"""
+# test os path creation, iteration, and deletion
+
+from stdtest/specialpaths import buildDir
+import std/[syncio, assertions, osproc, os, strutils, pathnorm]
+
+block fileOperations:
+  let files = @["these.txt", "are.x", "testing.r", "files.q"]
+  let dirs = @["some", "created", "test", "dirs"]
+
+  let dname = "__really_obscure_dir_name"
+
+  createDir(dname)
+  doAssert dirExists(dname)
+
+  block: # copyFile, copyFileToDir
+    doAssertRaises(OSError): copyFile(dname/"nonexistent.txt", dname/"nonexistent.txt")
+    let fname = "D20201009T112235"
+    let fname2 = "D20201009T112235.2"
+    let str = "foo1\0foo2\nfoo3\0"
+    let file = dname/fname
+    let file2 = dname/fname2
+    writeFile(file, str)
+    doAssert readFile(file) == str
+    let sub = "sub"
+    doAssertRaises(OSError): copyFile(file, dname/sub/fname2)
+    doAssertRaises(OSError): copyFileToDir(file, dname/sub)
+    doAssertRaises(ValueError): copyFileToDir(file, "")
+    copyFile(file, file2)
+    doAssert fileExists(file2)
+    doAssert readFile(file2) == str
+    createDir(dname/sub)
+    copyFileToDir(file, dname/sub)
+    doAssert fileExists(dname/sub/fname)
+    removeDir(dname/sub)
+    doAssert not dirExists(dname/sub)
+    removeFile(file)
+    removeFile(file2)
+
+  # Test creating files and dirs
+  for dir in dirs:
+    createDir(dname/dir)
+    doAssert dirExists(dname/dir)
+
+  for file in files:
+    let fh = open(dname/file, fmReadWrite)
+    fh.close()
+    doAssert fileExists(dname/file)
+
+  echo "All:"
+
+  template norm(x): untyped =
+    (when defined(windows): x.replace('\\', '/') else: x)
+
+  for path in walkPattern(dname/"*"):
+    echo path.norm
+
+  echo "Files:"
+
+  for path in walkFiles(dname/"*"):
+    echo path.norm
+
+  echo "Dirs:"
+
+  for path in walkDirs(dname/"*"):
+    echo path.norm
+
+  # Test removal of files dirs
+  for dir in dirs:
+    removeDir(dname/dir)
+    doAssert: not dirExists(dname/dir)
+
+  for file in files:
+    removeFile(dname/file)
+    doAssert: not fileExists(dname/file)
+
+  removeDir(dname)
+  doAssert: not dirExists(dname)
+
+  # createDir should create recursive directories
+  createDir(dirs[0] / dirs[1])
+  doAssert dirExists(dirs[0] / dirs[1]) # true
+  removeDir(dirs[0])
+
+  # createDir should properly handle trailing separator
+  createDir(dname / "")
+  doAssert dirExists(dname) # true
+  removeDir(dname)
+
+  # createDir should raise IOError if the path exists
+  # and is not a directory
+  open(dname, fmWrite).close
+  try:
+    createDir(dname)
+  except IOError:
+    echo "Raises"
+  removeFile(dname)
+
+  # removeFile should not remove directory
+  createDir(dname)
+  try:
+    removeFile(dname)
+  except OSError:
+    echo "Raises"
+  removeDir(dname)
+
+  # test copyDir:
+  createDir("a/b")
+  open("a/b/file.txt", fmWrite).close
+  createDir("a/b/c")
+  open("a/b/c/fileC.txt", fmWrite).close
+
+  copyDir("a", "../dest/a")
+  removeDir("a")
+
+  doAssert dirExists("../dest/a/b")
+  doAssert fileExists("../dest/a/b/file.txt")
+
+  doAssert fileExists("../dest/a/b/c/fileC.txt")
+  removeDir("../dest")
+
+  # test copyDir:
+  # if separator at the end of a path
+  createDir("a/b")
+  open("a/file.txt", fmWrite).close
+
+  copyDir("a/", "../dest/a/")
+  removeDir("a")
+
+  doAssert dirExists("../dest/a/b")
+  doAssert fileExists("../dest/a/file.txt")
+  removeDir("../dest")
+
+  # 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:
+    const symlinksAreHandled = not defined(windows)
+    const dname = buildDir/"D20210116T140629"
+    const subDir = dname/"sub"
+    const subDir2 = dname/"sub2"
+    const brokenSymlinkName = "D20210101T191320_BROKEN_SYMLINK"
+    const brokenSymlink = dname/brokenSymlinkName
+    const brokenSymlinkSrc = "D20210101T191320_nonexistent"
+    const brokenSymlinkCopy = brokenSymlink & "_COPY"
+    const brokenSymlinkInSubDir = subDir/brokenSymlinkName
+    const brokenSymlinkInSubDir2 = subDir2/brokenSymlinkName
+
+    createDir(subDir)
+    createSymlink(brokenSymlinkSrc, brokenSymlink)
+
+    # Test copyFile
+    when symlinksAreHandled:
+      doAssertRaises(OSError):
+        copyFile(brokenSymlink, brokenSymlinkCopy)
+      doAssertRaises(OSError):
+        copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkFollow})
+    copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkIgnore})
+    doAssert not fileExists(brokenSymlinkCopy)
+    copyFile(brokenSymlink, brokenSymlinkCopy, {cfSymlinkAsIs})
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
+      removeFile(brokenSymlinkCopy)
+    else:
+      doAssert not fileExists(brokenSymlinkCopy)
+    doAssertRaises(AssertionDefect):
+      copyFile(brokenSymlink, brokenSymlinkCopy,
+               {cfSymlinkAsIs, cfSymlinkFollow})
+
+    # Test copyFileWithPermissions
+    when symlinksAreHandled:
+      doAssertRaises(OSError):
+        copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy)
+      doAssertRaises(OSError):
+        copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                                options = {cfSymlinkFollow})
+    copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                            options = {cfSymlinkIgnore})
+    doAssert not fileExists(brokenSymlinkCopy)
+    copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                            options = {cfSymlinkAsIs})
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
+      removeFile(brokenSymlinkCopy)
+    else:
+      doAssert not fileExists(brokenSymlinkCopy)
+    doAssertRaises(AssertionDefect):
+      copyFileWithPermissions(brokenSymlink, brokenSymlinkCopy,
+                              options = {cfSymlinkAsIs, cfSymlinkFollow})
+
+    # Test copyFileToDir
+    when symlinksAreHandled:
+      doAssertRaises(OSError):
+        copyFileToDir(brokenSymlink, subDir)
+      doAssertRaises(OSError):
+        copyFileToDir(brokenSymlink, subDir, {cfSymlinkFollow})
+    copyFileToDir(brokenSymlink, subDir, {cfSymlinkIgnore})
+    doAssert not fileExists(brokenSymlinkInSubDir)
+    copyFileToDir(brokenSymlink, subDir, {cfSymlinkAsIs})
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkInSubDir) == brokenSymlinkSrc
+      removeFile(brokenSymlinkInSubDir)
+    else:
+      doAssert not fileExists(brokenSymlinkInSubDir)
+
+    createSymlink(brokenSymlinkSrc, brokenSymlinkInSubDir)
+
+    # Test copyDir
+    copyDir(subDir, subDir2)
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
+    else:
+      doAssert not fileExists(brokenSymlinkInSubDir2)
+    removeDir(subDir2)
+
+    # Test copyDirWithPermissions
+    copyDirWithPermissions(subDir, subDir2)
+    when symlinksAreHandled:
+      doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
+    else:
+      doAssert not fileExists(brokenSymlinkInSubDir2)
+    removeDir(subDir2)
+
+    # Test moveFile
+    moveFile(brokenSymlink, brokenSymlinkCopy)
+    when not defined(windows):
+      doAssert expandSymlink(brokenSymlinkCopy) == brokenSymlinkSrc
+    else:
+      doAssert symlinkExists(brokenSymlinkCopy)
+    removeFile(brokenSymlinkCopy)
+
+    # Test moveDir
+    moveDir(subDir, subDir2)
+    when not defined(windows):
+      doAssert expandSymlink(brokenSymlinkInSubDir2) == brokenSymlinkSrc
+    else:
+      doAssert symlinkExists(brokenSymlinkInSubDir2)
+
+    removeDir(dname)
+
+block: # moveFile
+  let tempDir = getTempDir() / "D20210609T151608"
+  createDir(tempDir)
+  defer: removeDir(tempDir)
+
+  writeFile(tempDir / "a.txt", "")
+  moveFile(tempDir / "a.txt", tempDir / "b.txt")
+  doAssert not fileExists(tempDir / "a.txt")
+  doAssert fileExists(tempDir / "b.txt")
+  removeFile(tempDir / "b.txt")
+
+  createDir(tempDir / "moveFile_test")
+  writeFile(tempDir / "moveFile_test/a.txt", "")
+  moveFile(tempDir / "moveFile_test/a.txt", tempDir / "moveFile_test/b.txt")
+  doAssert not fileExists(tempDir / "moveFile_test/a.txt")
+  doAssert fileExists(tempDir / "moveFile_test/b.txt")
+  removeDir(tempDir / "moveFile_test")
+
+  createDir(tempDir / "moveFile_test")
+  writeFile(tempDir / "a.txt", "")
+  moveFile(tempDir / "a.txt", tempDir / "moveFile_test/b.txt")
+  doAssert not fileExists(tempDir / "a.txt")
+  doAssert fileExists(tempDir / "moveFile_test/b.txt")
+  removeDir(tempDir / "moveFile_test")
+
+block: # moveDir
+  let tempDir = getTempDir() / "D20210609T161443"
+  createDir(tempDir)
+  defer: removeDir(tempDir)
+
+  createDir(tempDir / "moveDir_test")
+  moveDir(tempDir / "moveDir_test/", tempDir / "moveDir_test_dest")
+  doAssert not dirExists(tempDir / "moveDir_test")
+  doAssert dirExists(tempDir / "moveDir_test_dest")
+  removeDir(tempDir / "moveDir_test_dest")
+
+  createDir(tempDir / "moveDir_test")
+  writeFile(tempDir / "moveDir_test/a.txt", "")
+  moveDir(tempDir / "moveDir_test", tempDir / "moveDir_test_dest")
+  doAssert not dirExists(tempDir / "moveDir_test")
+  doAssert not fileExists(tempDir / "moveDir_test/a.txt")
+  doAssert dirExists(tempDir / "moveDir_test_dest")
+  doAssert fileExists(tempDir / "moveDir_test_dest/a.txt")
+  removeDir(tempDir / "moveDir_test_dest")
+
+import times
+block modificationTime:
+  # Test get/set modification times
+  # Should support at least microsecond resolution
+  let tm = fromUnix(0) + 100.microseconds
+  writeFile("a", "")
+  setLastModificationTime("a", tm)
+
+  when defined(macosx):
+    doAssert true
+  else:
+    doAssert getLastModificationTime("a") == tm
+  removeFile("a")
+
+block walkDirRec:
+  createDir("walkdir_test/a/b")
+  open("walkdir_test/a/b/file_1", fmWrite).close()
+  open("walkdir_test/a/file_2", fmWrite).close()
+
+  for p in walkDirRec("walkdir_test"):
+    doAssert p.fileExists
+    doAssert p.startsWith("walkdir_test")
+
+  var s: seq[string]
+  for p in walkDirRec("walkdir_test", {pcFile}, {pcDir}, relative = true):
+    s.add(p)
+
+  doAssert s.len == 2
+  doAssert "a" / "b" / "file_1" in s
+  doAssert "a" / "file_2" in s
+
+  removeDir("walkdir_test")
+
+import std/sequtils
+
+block: # walkDir
+  doAssertRaises(OSError):
+    for a in walkDir("nonexistent", checkDir = true): discard
+  doAssertRaises(OSError):
+    for p in walkDirRec("nonexistent", checkDir = true): discard
+
+  when not defined(windows):
+    block walkDirRelative:
+      createDir("walkdir_test")
+      createSymlink(".", "walkdir_test/c")
+      for k, p in walkDir("walkdir_test", true):
+        doAssert k == pcLinkToDir
+      removeDir("walkdir_test")
+
+  when defined(posix):
+    block walkDirSpecial:
+      createDir("walkdir_test")
+      doAssert execShellCmd("mkfifo walkdir_test/fifo") == 0
+      createSymlink("fifo", "walkdir_test/fifo_link")
+      let withSpecialFiles = toSeq(walkDir("walkdir_test", relative = true))
+      doAssert (withSpecialFiles.len == 2 and
+                (pcFile, "fifo") in withSpecialFiles and
+                (pcLinkToFile, "fifo_link") in withSpecialFiles)
+      # now Unix special files are excluded from walkdir output:
+      let skipSpecialFiles = toSeq(walkDir("walkdir_test", relative = true,
+                                           skipSpecial = true))
+      doAssert skipSpecialFiles.len == 0
+      removeDir("walkdir_test")
+
+block normalizedPath:
+  doAssert normalizedPath("") == ""
+  block relative:
+    doAssert normalizedPath(".") == "."
+    doAssert normalizedPath("foo/..") == "."
+    doAssert normalizedPath("foo//../bar/.") == "bar"
+    doAssert normalizedPath("..") == ".."
+    doAssert normalizedPath("../") == ".."
+    doAssert normalizedPath("../..") == unixToNativePath"../.."
+    doAssert normalizedPath("../a/..") == ".."
+    doAssert normalizedPath("../a/../") == ".."
+    doAssert normalizedPath("./") == "."
+
+  block absolute:
+    doAssert normalizedPath("/") == unixToNativePath"/"
+    doAssert normalizedPath("/.") == unixToNativePath"/"
+    doAssert normalizedPath("/..") == unixToNativePath"/.."
+    doAssert normalizedPath("/../") == unixToNativePath"/.."
+    doAssert normalizedPath("/../..") == unixToNativePath"/../.."
+    doAssert normalizedPath("/../../") == unixToNativePath"/../.."
+    doAssert normalizedPath("/../../../") == unixToNativePath"/../../.."
+    doAssert normalizedPath("/a/b/../../foo") == unixToNativePath"/foo"
+    doAssert normalizedPath("/a/b/../../../foo") == unixToNativePath"/../foo"
+    doAssert normalizedPath("/./") == unixToNativePath"/"
+    doAssert normalizedPath("//") == unixToNativePath"/"
+    doAssert normalizedPath("///") == unixToNativePath"/"
+    doAssert normalizedPath("/a//b") == unixToNativePath"/a/b"
+    doAssert normalizedPath("/a///b") == unixToNativePath"/a/b"
+    doAssert normalizedPath("/a/b/c/..") == unixToNativePath"/a/b"
+    doAssert normalizedPath("/a/b/c/../") == unixToNativePath"/a/b"
+
+block isHidden:
+  when defined(posix):
+    doAssert ".foo.txt".isHidden
+    doAssert "bar/.foo.ext".isHidden
+    doAssert not "bar".isHidden
+    doAssert not "foo/".isHidden
+    doAssert ".foo/.".isHidden
+    # Corner cases: `isHidden` is not yet `..` aware
+    doAssert not ".foo/..".isHidden
+
+block absolutePath:
+  doAssertRaises(ValueError): discard absolutePath("a", "b")
+  doAssert absolutePath("a") == getCurrentDir() / "a"
+  doAssert absolutePath("a", "/b") == "/b" / "a"
+  when defined(posix):
+    doAssert absolutePath("a", "/b/") == "/b" / "a"
+    doAssert absolutePath("a", "/b/c") == "/b/c" / "a"
+    doAssert absolutePath("/a", "b/") == "/a"
+
+block splitFile:
+  doAssert splitFile("") == ("", "", "")
+  doAssert splitFile("abc/") == ("abc", "", "")
+  doAssert splitFile("/") == ("/", "", "")
+  doAssert splitFile("./abc") == (".", "abc", "")
+  doAssert splitFile(".txt") == ("", ".txt", "")
+  doAssert splitFile("abc/.txt") == ("abc", ".txt", "")
+  doAssert splitFile("abc") == ("", "abc", "")
+  doAssert splitFile("abc.txt") == ("", "abc", ".txt")
+  doAssert splitFile("/abc.txt") == ("/", "abc", ".txt")
+  doAssert splitFile("/foo/abc.txt") == ("/foo", "abc", ".txt")
+  doAssert splitFile("/foo/abc.txt.gz") == ("/foo", "abc.txt", ".gz")
+  doAssert splitFile(".") == ("", ".", "")
+  doAssert splitFile("abc/.") == ("abc", ".", "")
+  doAssert splitFile("..") == ("", "..", "")
+  doAssert splitFile("a/..") == ("a", "..", "")
+  doAssert splitFile("/foo/abc....txt") == ("/foo", "abc...", ".txt")
+
+# execShellCmd is tested in tosproc
+
+block ospaths:
+  doAssert unixToNativePath("") == ""
+  doAssert unixToNativePath(".") == $CurDir
+  doAssert unixToNativePath("..") == $ParDir
+  doAssert isAbsolute(unixToNativePath("/"))
+  doAssert isAbsolute(unixToNativePath("/", "a"))
+  doAssert isAbsolute(unixToNativePath("/a"))
+  doAssert isAbsolute(unixToNativePath("/a", "a"))
+  doAssert isAbsolute(unixToNativePath("/a/b"))
+  doAssert isAbsolute(unixToNativePath("/a/b", "a"))
+  doAssert unixToNativePath("a/b") == joinPath("a", "b")
+
+  when defined(macos):
+    doAssert unixToNativePath("./") == ":"
+    doAssert unixToNativePath("./abc") == ":abc"
+    doAssert unixToNativePath("../abc") == "::abc"
+    doAssert unixToNativePath("../../abc") == ":::abc"
+    doAssert unixToNativePath("/abc", "a") == "abc"
+    doAssert unixToNativePath("/abc/def", "a") == "abc:def"
+  elif doslikeFileSystem:
+    doAssert unixToNativePath("./") == ".\\"
+    doAssert unixToNativePath("./abc") == ".\\abc"
+    doAssert unixToNativePath("../abc") == "..\\abc"
+    doAssert unixToNativePath("../../abc") == "..\\..\\abc"
+    doAssert unixToNativePath("/abc", "a") == "a:\\abc"
+    doAssert unixToNativePath("/abc/def", "a") == "a:\\abc\\def"
+  else:
+    #Tests for unix
+    doAssert unixToNativePath("./") == "./"
+    doAssert unixToNativePath("./abc") == "./abc"
+    doAssert unixToNativePath("../abc") == "../abc"
+    doAssert unixToNativePath("../../abc") == "../../abc"
+    doAssert unixToNativePath("/abc", "a") == "/abc"
+    doAssert unixToNativePath("/abc/def", "a") == "/abc/def"
+
+  block extractFilenameTest:
+    doAssert extractFilename("") == ""
+    when defined(posix):
+      doAssert extractFilename("foo/bar") == "bar"
+      doAssert extractFilename("foo/bar.txt") == "bar.txt"
+      doAssert extractFilename("foo/") == ""
+      doAssert extractFilename("/") == ""
+    when doslikeFileSystem:
+      doAssert extractFilename(r"foo\bar") == "bar"
+      doAssert extractFilename(r"foo\bar.txt") == "bar.txt"
+      doAssert extractFilename(r"foo\") == ""
+      doAssert extractFilename(r"C:\") == ""
+
+  block lastPathPartTest:
+    doAssert lastPathPart("") == ""
+    when defined(posix):
+      doAssert lastPathPart("foo/bar.txt") == "bar.txt"
+      doAssert lastPathPart("foo/") == "foo"
+      doAssert lastPathPart("/") == ""
+    when doslikeFileSystem:
+      doAssert lastPathPart(r"foo\bar.txt") == "bar.txt"
+      doAssert lastPathPart(r"foo\") == "foo"
+
+  template canon(x): untyped = normalizePath(x, '/')
+  doAssert canon"/foo/../bar" == "/bar"
+  doAssert canon"foo/../bar" == "bar"
+
+  doAssert canon"/f/../bar///" == "/bar"
+  doAssert canon"f/..////bar" == "bar"
+
+  doAssert canon"../bar" == "../bar"
+  doAssert canon"/../bar" == "/../bar"
+
+  doAssert canon("foo/../../bar/") == "../bar"
+  doAssert canon("./bla/blob/") == "bla/blob"
+  doAssert canon(".hiddenFile") == ".hiddenFile"
+  doAssert canon("./bla/../../blob/./zoo.nim") == "../blob/zoo.nim"
+
+  doAssert canon("C:/file/to/this/long") == "C:/file/to/this/long"
+  doAssert canon("") == ""
+  doAssert canon("foobar") == "foobar"
+  doAssert canon("f/////////") == "f"
+
+  doAssert relativePath("/foo/bar//baz.nim", "/foo", '/') == "bar/baz.nim"
+  doAssert normalizePath("./foo//bar/../baz", '/') == "foo/baz"
+
+  doAssert relativePath("/Users/me/bar/z.nim", "/Users/other/bad", '/') == "../../me/bar/z.nim"
+
+  doAssert relativePath("/Users/me/bar/z.nim", "/Users/other", '/') == "../me/bar/z.nim"
+
+  # `//` is a UNC path, `/` is the current working directory's drive, so can't
+  # run this test on Windows.
+  when not doslikeFileSystem:
+    doAssert relativePath("/Users///me/bar//z.nim", "//Users/", '/') == "me/bar/z.nim"
+  doAssert relativePath("/Users/me/bar/z.nim", "/Users/me", '/') == "bar/z.nim"
+  doAssert relativePath("", "/users/moo", '/') == ""
+  doAssert relativePath("foo", "", '/') == "foo"
+  doAssert relativePath("/foo", "/Foo", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
+  doAssert relativePath("/Foo", "/foo", '/') == (when FileSystemCaseSensitive: "../Foo" else: ".")
+  doAssert relativePath("/foo", "/fOO", '/') == (when FileSystemCaseSensitive: "../foo" else: ".")
+  doAssert relativePath("/foO", "/foo", '/') == (when FileSystemCaseSensitive: "../foO" else: ".")
+
+  doAssert relativePath("foo", ".", '/') == "foo"
+  doAssert relativePath(".", ".", '/') == "."
+  doAssert relativePath("..", ".", '/') == ".."
+
+  doAssert relativePath("foo", "foo") == "."
+  doAssert relativePath("", "foo") == ""
+  doAssert relativePath("././/foo", "foo//./") == "."
+
+  doAssert relativePath(getCurrentDir() / "bar", "foo") == "../bar".unixToNativePath
+  doAssert relativePath("bar", getCurrentDir() / "foo") == "../bar".unixToNativePath
+
+  when doslikeFileSystem:
+    doAssert relativePath(r"c:\foo.nim", r"C:\") == r"foo.nim"
+    doAssert relativePath(r"c:\foo\bar\baz.nim", r"c:\foo") == r"bar\baz.nim"
+    doAssert relativePath(r"c:\foo\bar\baz.nim", r"d:\foo") == r"c:\foo\bar\baz.nim"
+    doAssert relativePath(r"\foo\baz.nim", r"\foo") == r"baz.nim"
+    doAssert relativePath(r"\foo\bar\baz.nim", r"\bar") == r"..\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\bar") == r"baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foO\bar") == r"baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\bar\bar") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\foo\car") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\\goo\bar") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"c:\") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"\\foo\bar\baz.nim", r"\foo") == r"\\foo\bar\baz.nim"
+    doAssert relativePath(r"c:\foo.nim", r"\foo") == r"c:\foo.nim"
+
+  doAssert joinPath("usr", "") == unixToNativePath"usr"
+  doAssert joinPath("", "lib") == "lib"
+  doAssert joinPath("", "/lib") == unixToNativePath"/lib"
+  doAssert joinPath("usr/", "/lib") == unixToNativePath"usr/lib"
+  doAssert joinPath("", "") == unixToNativePath"" # issue #13455
+  doAssert joinPath("", "/") == unixToNativePath"/"
+  doAssert joinPath("/", "/") == unixToNativePath"/"
+  doAssert joinPath("/", "") == unixToNativePath"/"
+  doAssert joinPath("/" / "") == unixToNativePath"/" # weird test case...
+  doAssert joinPath("/", "/a/b/c") == unixToNativePath"/a/b/c"
+  doAssert joinPath("foo/", "") == unixToNativePath"foo/"
+  doAssert joinPath("foo/", "abc") == unixToNativePath"foo/abc"
+  doAssert joinPath("foo//./", "abc/.//") == unixToNativePath"foo/abc/"
+  doAssert joinPath("foo", "abc") == unixToNativePath"foo/abc"
+  doAssert joinPath("", "abc") == unixToNativePath"abc"
+
+  doAssert joinPath("zook/.", "abc") == unixToNativePath"zook/abc"
+
+  # controversial: inconsistent with `joinPath("zook/.","abc")`
+  # on linux, `./foo` and `foo` are treated a bit differently for executables
+  # but not `./foo/bar` and `foo/bar`
+  doAssert joinPath(".", "/lib") == unixToNativePath"./lib"
+  doAssert joinPath(".", "abc") == unixToNativePath"./abc"
+
+  # cases related to issue #13455
+  doAssert joinPath("foo", "", "") == "foo"
+  doAssert joinPath("foo", "") == "foo"
+  doAssert joinPath("foo/", "") == unixToNativePath"foo/"
+  doAssert joinPath("foo/", ".") == "foo"
+  doAssert joinPath("foo", "./") == unixToNativePath"foo/"
+  doAssert joinPath("foo", "", "bar/") == unixToNativePath"foo/bar/"
+
+  # issue #13579
+  doAssert joinPath("/foo", "../a") == unixToNativePath"/a"
+  doAssert joinPath("/foo/", "../a") == unixToNativePath"/a"
+  doAssert joinPath("/foo/.", "../a") == unixToNativePath"/a"
+  doAssert joinPath("/foo/.b", "../a") == unixToNativePath"/foo/a"
+  doAssert joinPath("/foo///", "..//a/") == unixToNativePath"/a/"
+  doAssert joinPath("foo/", "../a") == unixToNativePath"a"
+
+  when doslikeFileSystem:
+    doAssert joinPath("C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", "..\\..\\VC\\vcvarsall.bat") == r"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat"
+    doAssert joinPath("C:\\foo", "..\\a") == r"C:\a"
+    doAssert joinPath("C:\\foo\\", "..\\a") == r"C:\a"
+
+block getTempDir:
+  block TMPDIR:
+    # TMPDIR env var is not used if either of these are defined.
+    when not (defined(tempDir) or defined(windows) or defined(android)):
+      if existsEnv("TMPDIR"):
+        let origTmpDir = getEnv("TMPDIR")
+        putEnv("TMPDIR", "/mytmp")
+        doAssert getTempDir() == "/mytmp/"
+        delEnv("TMPDIR")
+        doAssert getTempDir() == "/tmp/"
+        putEnv("TMPDIR", origTmpDir)
+      else:
+        doAssert getTempDir() == "/tmp/"
+
+block: # getCacheDir
+  doAssert getCacheDir().dirExists
+
+block isRelativeTo:
+  doAssert isRelativeTo("/foo", "/")
+  doAssert isRelativeTo("/foo/bar", "/foo")
+  doAssert isRelativeTo("foo/bar", "foo")
+  doAssert isRelativeTo("/foo/bar.nim", "/foo/bar.nim")
+  doAssert isRelativeTo("./foo/", "foo")
+  doAssert isRelativeTo("foo", "./foo/")
+  doAssert isRelativeTo(".", ".")
+  doAssert isRelativeTo("foo/bar", ".")
+  doAssert not isRelativeTo("foo/bar.nims", "foo/bar.nim")
+  doAssert not isRelativeTo("/foo2", "/foo")
+
+block: # quoteShellWindows
+  doAssert quoteShellWindows("aaa") == "aaa"
+  doAssert quoteShellWindows("aaa\"") == "aaa\\\""
+  doAssert quoteShellWindows("") == "\"\""
+
+block: # quoteShellCommand
+  when defined(windows):
+    doAssert quoteShellCommand(["a b c", "d", "e"]) == """"a b c" d e"""
+    doAssert quoteShellCommand(["""ab"c""", r"\", "d"]) == """ab\"c \ d"""
+    doAssert quoteShellCommand(["""ab"c""", """ \""", "d"]) == """ab\"c " \\" d"""
+    doAssert quoteShellCommand(["""a\\\b""", """de fg""", "h"]) == """a\\\b "de fg" h"""
+    doAssert quoteShellCommand(["""a\"b""", "c", "d"]) == """a\\\"b c d"""
+    doAssert quoteShellCommand(["""a\\b c""", "d", "e"]) == """"a\\b c" d e"""
+    doAssert quoteShellCommand(["""a\\b\ c""", "d", "e"]) == """"a\\b\ c" d e"""
+    doAssert quoteShellCommand(["ab", ""]) == """ab """""
+
+block: # quoteShellPosix
+  doAssert quoteShellPosix("aaa") == "aaa"
+  doAssert quoteShellPosix("aaa a") == "'aaa a'"
+  doAssert quoteShellPosix("") == "''"
+  doAssert quoteShellPosix("a'a") == "'a'\"'\"'a'"
+
+block: # quoteShell
+  when defined(posix):
+    doAssert quoteShell("") == "''"
+
+block: # normalizePathEnd
+  # handle edge cases correctly: shouldn't affect whether path is
+  # absolute/relative
+  doAssert "".normalizePathEnd(true) == ""
+  doAssert "".normalizePathEnd(false) == ""
+  doAssert "/".normalizePathEnd(true) == $DirSep
+  doAssert "/".normalizePathEnd(false) == $DirSep
+
+  when defined(posix):
+    doAssert "//".normalizePathEnd(false) == "/"
+    doAssert "foo.bar//".normalizePathEnd == "foo.bar"
+    doAssert "bar//".normalizePathEnd(trailingSep = true) == "bar/"
+  when defined(windows):
+    doAssert r"C:\foo\\".normalizePathEnd == r"C:\foo"
+    doAssert r"C:\foo".normalizePathEnd(trailingSep = true) == r"C:\foo\"
+    # this one is controversial: we could argue for returning `D:\` instead,
+    # but this is simplest.
+    doAssert r"D:\".normalizePathEnd == r"D:"
+    doAssert r"E:/".normalizePathEnd(trailingSep = true) == r"E:\"
+    doAssert "/".normalizePathEnd == r"\"
+
+
+import sugar
+
+block: # normalizeExe
+  doAssert "".dup(normalizeExe) == ""
+  when defined(posix):
+    doAssert "foo".dup(normalizeExe) == "./foo"
+    doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
+  when defined(windows):
+    doAssert "foo".dup(normalizeExe) == "foo"
+
+block: # isAdmin
+  let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure
+  # In Azure on Windows tests run as an admin user
+  if isAzure and defined(windows): doAssert isAdmin()
+  # In Azure on POSIX tests run as a normal user
+  if isAzure and defined(posix): doAssert not isAdmin()
+
+
+import sugar
+
+block: # normalizeExe
+  doAssert "".dup(normalizeExe) == ""
+  when defined(posix):
+    doAssert "foo".dup(normalizeExe) == "./foo"
+    doAssert "foo/../bar".dup(normalizeExe) == "foo/../bar"
+  when defined(windows):
+    doAssert "foo".dup(normalizeExe) == "foo"
+
+block: # isAdmin
+  let isAzure = existsEnv("TF_BUILD") # xxx factor with testament.specs.isAzure
+  # In Azure on Windows tests run as an admin user
+  if isAzure and defined(windows): doAssert isAdmin()
+  # In Azure on POSIX tests run as a normal user
+  if isAzure and defined(posix): doAssert not isAdmin()
+
+when doslikeFileSystem:
+  import std/private/ntpath
+
+  block: # Bug #19103 UNC paths
+
+    # Easiest way of generating a valid, readable and writable UNC path
+    let tempDir = r"\\?\" & getTempDir()
+    doAssert dirExists tempDir
+    createDir tempDir / "test"
+    removeDir tempDir / "test"
+    createDir tempDir / "recursive" / "test"
+    removeDir tempDir / "recursive" / "test"
+
+    let tempDir2 = getTempDir()
+    let (drive, pathNoDrive) = splitDrive(tempDir2)
+    setCurrentDir drive
+    doAssert cmpIgnoreCase(getCurrentDir().splitDrive.drive, drive) == 0
+
+    # Test `\Users` path syntax on Windows by stripping away drive. `\`
+    # resolves to the drive in current working directory. This drive will be
+    # the same as `tempDir2` because of the `setCurrentDir` above.
+    doAssert pathNoDrive[0] == '\\'
+    createDir pathNoDrive / "test"
+    doAssert dirExists pathNoDrive / "test"
+    removeDir pathNoDrive / "test"
+
+    doAssert splitPath("//?/c:") == ("//?/c:", "")
+
+    doAssert relativePath("//?/c:///Users//me", "//?/c:", '/') == "Users/me"
+
+    doAssert parentDir(r"\\?\c:") == r""
+    doAssert parentDir(r"//?/c:/Users") == r"\\?\c:"
+    doAssert parentDir(r"\\localhost\c$") == r""
+    doAssert parentDir(r"\Users") == r"\"
+
+    doAssert tailDir("//?/c:") == ""
+    doAssert tailDir("//?/c:/Users") == "Users"
+    doAssert tailDir(r"\\localhost\c$\Windows\System32") == r"Windows\System32"
+
+    doAssert isRootDir("//?/c:")
+    doAssert isRootDir("//?/UNC/localhost/c$")
+    doAssert not isRootDir(r"\\?\c:\Users")
+
+    doAssert parentDirs(r"C:\Users", fromRoot = true).toSeq == @[r"C:\", r"C:\Users"]
+    doAssert parentDirs(r"C:\Users", fromRoot = false).toSeq == @[r"C:\Users", r"C:"]
+    doAssert parentDirs(r"\\?\c:\Users", fromRoot = true).toSeq ==
+      @[r"\\?\c:\", r"\\?\c:\Users"]
+    doAssert parentDirs(r"\\?\c:\Users", fromRoot = false).toSeq ==
+      @[r"\\?\c:\Users", r"\\?\c:"]
+    doAssert parentDirs(r"//localhost/c$/Users", fromRoot = true).toSeq ==
+      @[r"//localhost/c$/", r"//localhost/c$/Users"]
+    doAssert parentDirs(r"//?/UNC/localhost/c$/Users", fromRoot = false).toSeq ==
+      @[r"//?/UNC/localhost/c$/Users", r"\\?\UNC\localhost\c$"]
+    doAssert parentDirs(r"\Users", fromRoot = true).toSeq == @[r"\", r"\Users"]
+    doAssert parentDirs(r"\Users", fromRoot = false).toSeq == @[r"\Users", r"\"]
+
+    doAssert r"//?/c:" /../ "d/e" == r"\\?\c:\d\e"
+    doAssert r"//?/c:/Users" /../ "d/e" == r"\\?\c:\d\e"
+    doAssert r"\\localhost\c$" /../ "d/e" == r"\\localhost\c$\d\e"
+
+    doAssert splitFile("//?/c:") == ("//?/c:", "", "")
+    doAssert splitFile("//?/c:/Users") == ("//?/c:", "Users", "")
+    doAssert splitFile(r"\\localhost\c$\test.txt") == (r"\\localhost\c$", "test", ".txt")
+
+else:
+  block: # parentDirs
+    doAssert parentDirs("/home", fromRoot=true).toSeq == @["/", "/home"]
+    doAssert parentDirs("/home", fromRoot=false).toSeq == @["/home", "/"]
+    doAssert parentDirs("home", fromRoot=true).toSeq == @["home"]
+    doAssert parentDirs("home", fromRoot=false).toSeq == @["home"]
+
+    doAssert parentDirs("/home/user", fromRoot=true).toSeq == @["/", "/home/", "/home/user"]
+    doAssert parentDirs("/home/user", fromRoot=false).toSeq == @["/home/user", "/home", "/"]
+    doAssert parentDirs("home/user", fromRoot=true).toSeq == @["home/", "home/user"]
+    doAssert parentDirs("home/user", fromRoot=false).toSeq == @["home/user", "home"]
+
+
+# https://github.com/nim-lang/Nim/pull/19643#issuecomment-1235102314
+block:  # isValidFilename
+  # Negative Tests.
+  doAssert not isValidFilename("abcd", maxLen = 2)
+  doAssert not isValidFilename("0123456789", maxLen = 8)
+  doAssert not isValidFilename("con")
+  doAssert not isValidFilename("aux")
+  doAssert not isValidFilename("prn")
+  doAssert not isValidFilename("OwO|UwU")
+  doAssert not isValidFilename(" foo")
+  doAssert not isValidFilename("foo ")
+  doAssert not isValidFilename("foo.")
+  doAssert not isValidFilename("con.txt")
+  doAssert not isValidFilename("aux.bat")
+  doAssert not isValidFilename("prn.exe")
+  doAssert not isValidFilename("nim>.nim")
+  doAssert not isValidFilename(" foo.log")
+  # Positive Tests.
+  doAssert isValidFilename("abcd", maxLen = 42.Positive)
+  doAssert isValidFilename("c0n")
+  doAssert isValidFilename("foo.aux")
+  doAssert isValidFilename("bar.prn")
+  doAssert isValidFilename("OwO_UwU")
+  doAssert isValidFilename("cron")
+  doAssert isValidFilename("ux.bat")
+  doAssert isValidFilename("nim.nim")
+  doAssert isValidFilename("foo.log")
+
+block: # searchExtPos
+  doAssert "foo.nim".searchExtPos == 3
+  doAssert "/foo.nim".searchExtPos == 4
+  doAssert "".searchExtPos == -1
+  doAssert "/".searchExtPos == -1
+  doAssert "a.b/foo".searchExtPos == -1
+  doAssert ".".searchExtPos == -1
+  doAssert "foo.".searchExtPos == 3
+  doAssert "foo..".searchExtPos == 4
+  doAssert "..".searchExtPos == -1
+  doAssert "...".searchExtPos == -1
+  doAssert "./".searchExtPos == -1
+  doAssert "../".searchExtPos == -1
+  doAssert "/.".searchExtPos == -1
+  doAssert "/..".searchExtPos == -1
+  doAssert ".b".searchExtPos == -1
+  doAssert "..b".searchExtPos == -1
+  doAssert "/.b".searchExtPos == -1
+  doAssert "a/.b".searchExtPos == -1
+  doAssert ".a.b".searchExtPos == 2
+  doAssert "a/.b.c".searchExtPos == 4
+  doAssert "a/..b".searchExtPos == -1
+  doAssert "a/b..c".searchExtPos == 4
+
+  when doslikeFileSystem:
+    doAssert "c:a.b".searchExtPos == 3
+    doAssert "c:.a".searchExtPos == -1
+    doAssert r"c:\.a".searchExtPos == -1
+    doAssert "c:..a".searchExtPos == -1
+    doAssert r"c:\..a".searchExtPos == -1
+    doAssert "c:.a.b".searchExtPos == 4
diff --git a/tests/stdlib/tos_unc.nim b/tests/stdlib/tos_unc.nim
new file mode 100644
index 000000000..194deeb42
--- /dev/null
+++ b/tests/stdlib/tos_unc.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  disabled: "posix"
+"""
+
+# bug 10952, UNC paths
+import os
+import std/assertions
+
+doAssert r"\\hostname\foo\bar" / "baz" == r"\\hostname\foo\bar\baz"
+doAssert r"\\?\C:\foo" / "bar" == r"\\?\C:\foo\bar"
diff --git a/tests/stdlib/tosenv.nim b/tests/stdlib/tosenv.nim
new file mode 100644
index 000000000..17e397987
--- /dev/null
+++ b/tests/stdlib/tosenv.nim
@@ -0,0 +1,163 @@
+discard """
+  matrix: "--mm:refc; --mm:arc"
+  joinable: false
+  targets: "c js cpp"
+"""
+
+import std/os
+from std/sequtils import toSeq
+import stdtest/testutils
+
+when defined(nimPreviewSlimSystem):
+  import std/[assertions]
+
+# "LATIN CAPITAL LETTER AE" in UTF-8 (0xc386)
+const unicodeUtf8 = "\xc3\x86"
+
+template main =
+  block: # delEnv, existsEnv, getEnv, envPairs
+    for val in ["val", "", unicodeUtf8]: # ensures empty val works too
+      const key = "NIM_TESTS_TOSENV_KEY"
+      doAssert not existsEnv(key)
+
+      putEnv(key, "tempval")
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == "tempval"
+
+      putEnv(key, val) # change a key that already exists
+      doAssert existsEnv(key)
+      doAssert getEnv(key) == val
+
+      doAssert (key, val) in toSeq(envPairs())
+      delEnv(key)
+      doAssert (key, val) notin toSeq(envPairs())
+      doAssert not existsEnv(key)
+      delEnv(key) # deleting an already deleted env var
+      doAssert not existsEnv(key)
+
+    block:
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "") == ""
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", " ") == " "
+      doAssert getEnv("NIM_TESTS_TOSENV_NONEXISTENT", "defval") == "defval"
+
+    whenVMorJs: discard # xxx improve
+    do:
+      doAssertRaises(OSError, putEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE", "NEW_DUMMY_VALUE"))
+      doAssertRaises(OSError, putEnv("", "NEW_DUMMY_VALUE"))
+      doAssert not existsEnv("")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT=DUMMY_VALUE")
+      doAssert not existsEnv("NIM_TESTS_TOSENV_PUT")
+
+static: main()
+main()
+
+when defined(windows):
+  import std/widestrs
+  proc c_wgetenv(env: WideCString): WideCString {.importc: "_wgetenv", header: "<stdlib.h>".}
+proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
+
+when not defined(js) and not defined(nimscript):
+  when defined(nimPreviewSlimSystem):
+    import std/typedthreads
+  block: # bug #18533
+    var thr: Thread[void]
+    proc threadFunc {.thread.} = putEnv("foo", "fooVal2")
+
+    putEnv("foo", "fooVal1")
+    doAssert getEnv("foo") == "fooVal1"
+    createThread(thr, threadFunc)
+    joinThreads(thr)
+    when defined(windows):
+      doAssert getEnv("foo") == $c_wgetenv("foo".newWideCString)
+    else:
+      doAssert getEnv("foo") == $c_getenv("foo".cstring)
+
+    doAssertRaises(OSError): delEnv("foo=bar")
+
+when defined(windows) and not defined(nimscript):
+  import std/encodings
+
+  proc c_putenv(env: cstring): int32 {.importc: "putenv", header: "<stdlib.h>".}
+  proc c_wputenv(env: WideCString): int32 {.importc: "_wputenv", header: "<stdlib.h>".}
+
+  block: # Bug #20083
+    # These test that `getEnv`, `putEnv` and `existsEnv` handle Unicode
+    # characters correctly. This means that module X in the process calling the
+    # CRT environment variable API will get the correct string. Raw CRT API
+    # calls below represent module X.
+
+    # Getting an env. var. with unicode characters returns the correct UTF-8
+    # encoded string.
+    block:
+      const envName = "twin_envvars1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Putting an env. var. with unicode characters gives the correct UTF-16
+    # encoded string from low-level routine.
+    block:
+      const envName = "twin_envvars2"
+      putEnv(envName, unicodeUtf8)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters is retrieved correctly
+    block:
+      const envName = unicodeUtf8 & "1"
+      doAssert c_wputenv(newWideCString(envName & "=" & unicodeUtf8)) == 0
+      doAssert existsEnv(envName)
+      doAssert getEnv(envName) == unicodeUtf8
+
+    # Env. name containing Unicode characters is set correctly
+    block:
+      const envName = unicodeUtf8 & "2"
+      putEnv(envName, unicodeUtf8)
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == unicodeUtf8
+
+    # Env. name containing Unicode characters and empty value is set correctly
+    block:
+      const envName = unicodeUtf8 & "3"
+      putEnv(envName, "")
+      doAssert existsEnv(envName)
+      doAssert $c_wgetenv(envName.newWideCString) == ""
+
+    # It's hard to test on Windows code pages, because there is no "change
+    # a process' locale" API.
+    if getCurrentEncoding(true) == "windows-1252":
+      const
+        unicodeAnsi = "\xc6" # `unicodeUtf8` in `windows-1252` encoding
+
+      # Test that env. var. ANSI API has correct encoding
+      block:
+        const
+          envName = unicodeUtf8 & "4"
+          envNameAnsi = unicodeAnsi & "4"
+        putEnv(envName, unicodeUtf8)
+        doAssert $c_getenv(envNameAnsi.cstring) == unicodeAnsi
+
+      block:
+        const
+          envName = unicodeUtf8 & "5"
+          envNameAnsi = unicodeAnsi & "5"
+        doAssert c_putenv((envNameAnsi & "=" & unicodeAnsi).cstring) == 0
+        doAssert getEnv(envName) == unicodeUtf8
+
+      # Env. name containing Unicode characters and empty value is set correctly;
+      # and, if env. name. characters cannot be represented in codepage, don't
+      # raise an error.
+      #
+      # `win_setenv.nim` converts UTF-16 to ANSI when setting empty env. var. The
+      # windows-1250 locale has no representation of `abreveUtf8` below, so the
+      # conversion will fail, but this must not be fatal. It is expected that the
+      # routine ignores updating MBCS environment (`environ` global) and carries
+      # on.
+      block:
+        const
+          # "LATIN SMALL LETTER A WITH BREVE" in UTF-8
+          abreveUtf8 = "\xc4\x83"
+          envName = abreveUtf8 & "6"
+        putEnv(envName, "")
+        doAssert existsEnv(envName)
+        doAssert $c_wgetenv(envName.newWideCString) == ""
+        doAssert getEnv(envName) == ""
diff --git a/tests/stdlib/toserrors.nim b/tests/stdlib/toserrors.nim
new file mode 100644
index 000000000..e907dfe63
--- /dev/null
+++ b/tests/stdlib/toserrors.nim
@@ -0,0 +1,9 @@
+discard """
+  action: compile
+"""
+
+import std/oserrors
+
+let x1 = osLastError()
+raiseOSError(x1)
+echo osErrorMsg(x1)
diff --git a/tests/stdlib/tosproc.nim b/tests/stdlib/tosproc.nim
new file mode 100644
index 000000000..da4f6252d
--- /dev/null
+++ b/tests/stdlib/tosproc.nim
@@ -0,0 +1,316 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+joinable: false
+"""
+
+#[
+joinable: false
+because it'd need cleanup up stdout
+
+see also: tests/osproc/*.nim; consider merging those into a single test here
+(easier to factor and test more things as a single self contained test)
+]#
+import std/[assertions, syncio]
+
+when defined(case_testfile): # compiled test file for child process
+  from posix import exitnow
+  proc c_exit2(code: cint): void {.importc: "_exit", header: "<unistd.h>".}
+  import os
+  var a = 0
+  proc fun(b = 0) =
+    a.inc
+    if a mod 10000000 == 0: # prevents optimizing it away
+      echo a
+    fun(b+1)
+
+  proc main() =
+    let args = commandLineParams()
+    echo (msg: "child binary", pid: getCurrentProcessId())
+    let arg = args[0]
+    echo (arg: arg)
+    case arg
+    of "exit_0":
+      if true: quit(0)
+    of "exit_1":
+      if true: quit(1)
+    of "exit_2":
+      if true: quit(2)
+    of "exit_42":
+      if true: quit(42)
+    of "exitnow_139":
+      if true: exitnow(139)
+    of "c_exit2_139":
+      if true: c_exit2(139)
+    of "quit_139":
+      # `exitStatusLikeShell` doesn't distinguish between a process that
+      # exit(139) and a process that gets killed with `SIGSEGV` because
+      # 139 = 11 + 128 = SIGSEGV + 128.
+      # However, as #10249 shows, this leads to bad debugging experience
+      # when a child process dies with SIGSEGV, leaving no trace of why it
+      # failed. The shell (and lldb debugger) solves that by inserting a
+      # helpful msg: `segmentation fault` when it detects a signal killed
+      # the child.
+      # todo: expose an API that will show more diagnostic, returning
+      # (exitCode, signal) instead of just `shellExitCode`.
+      if true: quit(139)
+    of "exit_recursion": # stack overflow by infinite recursion
+      fun()
+      echo a
+    of "exit_array": # bad array access
+      echo args[1]
+  main()
+
+elif defined(case_testfile2):
+  import strutils
+  let x = stdin.readLine()
+  echo x.parseInt + 5
+
+elif defined(case_testfile3):
+  echo "start ta_out"
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+
+  stderr.writeLine("to stderr")
+  stderr.flushFile()
+  stderr.writeLine("to stderr")
+  stderr.flushFile()
+
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+  stdout.writeLine("to stdout")
+  stdout.flushFile()
+  echo "end ta_out"
+
+elif defined(case_testfile4):
+  import system # we could remove that
+  quit(QuitFailure)
+
+else: # main driver
+  import stdtest/[specialpaths, unittest_light]
+  import os, osproc, strutils
+  const nim = getCurrentCompilerExe()
+  const sourcePath = currentSourcePath()
+  let dir = getCurrentDir() / "tests" / "osproc"
+
+  template deferring(cleanup, body) =
+    try: body
+    finally: cleanup
+
+  # we're testing `execShellCmd` so don't rely on it to compile test file
+  # note: this should be exported in posix.nim
+  proc c_system(cmd: cstring): cint {.importc: "system", header: "<stdlib.h>".}
+
+  proc compileNimProg(opt: string, name: string): string =
+    result = buildDir / name.addFileExt(ExeExt)
+    let cmd = "$# c -o:$# --hints:off $# $#" % [nim.quoteShell, result.quoteShell, opt, sourcePath.quoteShell]
+    doAssert c_system(cmd) == 0, $cmd
+    doAssert result.fileExists
+
+  block execShellCmdTest:
+    let output = compileNimProg("-d:release -d:case_testfile", "D20190111T024543")
+
+    ## use it
+    template runTest(arg: string, expected: int) =
+      echo (arg2: arg, expected2: expected)
+      assertEquals execShellCmd(output & " " & arg), expected
+
+    runTest("exit_0", 0)
+    runTest("exitnow_139", 139)
+    runTest("c_exit2_139", 139)
+    when defined(posix):
+      runTest("quit_139", 127) # The quit value gets saturated to 127
+    else:
+      runTest("quit_139", 139)
+
+  block execCmdTest:
+    let output = compileNimProg("-d:release -d:case_testfile", "D20220705T221100")
+    doAssert execCmd(output & " exit_0") == 0
+    doAssert execCmd(output & " exit_1") == 1
+    doAssert execCmd(output & " exit_2") == 2
+    doAssert execCmd(output & " exit_42") == 42
+
+  import std/streams
+
+  block execProcessTest:
+    let dir = sourcePath.parentDir
+    let (_, err) = execCmdEx(nim & " c " & quoteShell(dir / "osproctest.nim"))
+    doAssert err == 0
+    let exePath = dir / addFileExt("osproctest", ExeExt)
+    let outStr1 = execProcess(exePath, workingDir = dir, args = ["foo",
+        "b A r"], options = {})
+    doAssert outStr1 == dir & "\nfoo\nb A r\n"
+
+    const testDir = "t e st"
+    createDir(testDir)
+    doAssert dirExists(testDir)
+    let outStr2 = execProcess(exePath, workingDir = testDir, args = ["x yz"],
+        options = {})
+    doAssert outStr2 == absolutePath(testDir) & "\nx yz\n"
+
+    removeDir(testDir)
+
+    # test for PipeOutStream
+    var
+      p = startProcess(exePath, args = ["abcdefghi", "foo", "bar", "0123456"])
+      outStrm = p.peekableOutputStream
+
+    var tmp: string
+    doAssert outStrm.readLine(tmp)
+    doAssert outStrm.readChar == 'a'
+    doAssert outStrm.peekChar == 'b'
+    doAssert outStrm.readChar == 'b'
+    doAssert outStrm.readChar == 'c'
+    doAssert outStrm.peekChar == 'd'
+    doAssert outStrm.peekChar == 'd'
+    doAssert outStrm.readChar == 'd'
+    doAssert outStrm.readStr(2) == "ef"
+    doAssert outStrm.peekStr(2) == "gh"
+    doAssert outStrm.peekStr(2) == "gh"
+    doAssert outStrm.readStr(1) == "g"
+    doAssert outStrm.readStr(3) == "hi\n"
+
+    doAssert outStrm.readLine == "foo"
+    doAssert outStrm.readChar == 'b'
+    doAssert outStrm.peekChar == 'a'
+    doAssert outStrm.readLine == "ar"
+
+    tmp.setLen(4)
+    tmp[0] = 'n'
+    doAssert outStrm.readDataStr(tmp, 1..3) == 3
+    doAssert tmp == "n012"
+    doAssert outStrm.peekStr(3) == "345"
+    doAssert outStrm.readDataStr(tmp, 1..2) == 2
+    doAssert tmp == "n342"
+    doAssert outStrm.peekStr(2) == "56"
+    doAssert outStrm.readDataStr(tmp, 0..3) == 3
+    doAssert tmp == "56\n2"
+    p.close
+
+    p = startProcess(exePath, args = ["123"])
+    outStrm = p.peekableOutputStream
+    let c = outStrm.peekChar
+    doAssert outStrm.readLine(tmp)
+    doAssert tmp[0] == c
+    tmp.setLen(7)
+    doAssert outStrm.peekData(addr tmp[0], 7) == 4
+    doAssert tmp[0..3] == "123\n"
+    doAssert outStrm.peekData(addr tmp[0], 7) == 4
+    doAssert tmp[0..3] == "123\n"
+    doAssert outStrm.readData(addr tmp[0], 7) == 4
+    doAssert tmp[0..3] == "123\n"
+    p.close
+
+    try:
+      removeFile(exePath)
+    except OSError:
+      discard
+
+  block: # test for startProcess (more tests needed)
+    # bugfix: windows stdin.close was a noop and led to blocking reads
+    proc startProcessTest(command: string, options: set[ProcessOption] = {
+                    poStdErrToStdOut, poUsePath}, input = ""): tuple[
+                    output: string,
+                    exitCode: int] {.tags:
+                    [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
+      var p = startProcess(command, options = options + {poEvalCommand})
+      var outp = outputStream(p)
+      if input.len > 0: inputStream(p).write(input)
+      close inputStream(p)
+      result = ("", -1)
+      var line = newStringOfCap(120)
+      while true:
+        if outp.readLine(line):
+          result[0].add(line)
+          result[0].add("\n")
+        else:
+          result[1] = peekExitCode(p)
+          if result[1] != -1: break
+      close(p)
+
+    var result = startProcessTest("nim r --hints:off -", options = {}, input = "echo 3*4")
+    doAssert result == ("12\n", 0)
+
+  block: # startProcess stdin (replaces old test `tstdin` + `ta_in`)
+    let output = compileNimProg("-d:case_testfile2", "D20200626T215919")
+    var p = startProcess(output, dir) # dir not needed though
+    p.inputStream.write("5\n")
+    p.inputStream.flush()
+    var line = ""
+    var s: seq[string]
+    while p.outputStream.readLine(line):
+      s.add line
+    doAssert s == @["10"]
+
+  block:
+    let output = compileNimProg("-d:case_testfile3", "D20200626T221233")
+    var x = newStringOfCap(120)
+    block: # startProcess stdout poStdErrToStdOut (replaces old test `tstdout` + `ta_out`)
+      var p = startProcess(output, dir, options={poStdErrToStdOut})
+      deferring: p.close()
+      do:
+        var sout: seq[string]
+        while p.outputStream.readLine(x): sout.add x
+        doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"]
+    block: # startProcess stderr (replaces old test `tstderr` + `ta_out`)
+      var p = startProcess(output, dir, options={})
+      deferring: p.close()
+      do:
+        var serr, sout: seq[string]
+        while p.errorStream.readLine(x): serr.add x
+        while p.outputStream.readLine(x): sout.add x
+        doAssert serr == @["to stderr", "to stderr"]
+        doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stdout", "to stdout", "end ta_out"]
+
+  block: # startProcess exit code (replaces old test `texitcode` + `tafalse`)
+    let output = compileNimProg("-d:case_testfile4", "D20200626T224758")
+    var p = startProcess(output, dir)
+    doAssert waitForExit(p) == QuitFailure
+    p = startProcess(output, dir)
+    var running = true
+    while running:
+      # xxx: avoid busyloop?
+      running = running(p)
+    doAssert waitForExit(p) == QuitFailure
+
+    # make sure that first call to running() after process exit returns false
+    p = startProcess(output, dir)
+    for j in 0..<30: # refs #13449
+      os.sleep(50)
+      if not running(p): break
+    doAssert not running(p)
+    doAssert waitForExit(p) == QuitFailure # avoid zombies
+
+  import std/strtabs
+  block execProcessTest:
+    var result = execCmdEx("nim r --hints:off -", options = {}, input = "echo 3*4")
+    stripLineEnd(result[0])
+    doAssert result == ("12", 0)
+    when not defined(windows):
+      doAssert execCmdEx("ls --nonexistent").exitCode != 0
+    when false:
+      # bug: on windows, this raises; on posix, passes
+      doAssert execCmdEx("nonexistent").exitCode != 0
+    when defined(posix):
+      doAssert execCmdEx("echo $FO", env = newStringTable({"FO": "B"})) == ("B\n", 0)
+      doAssert execCmdEx("echo $PWD", workingDir = "/") == ("/\n", 0)
+
+  block: # bug #17749
+    let output = compileNimProg("-d:case_testfile4", "D20210417T011153")
+    var p = startProcess(output, dir)
+    let inp = p.inputStream
+    var count = 0
+    when defined(windows):
+      # xxx we should make osproc.hsWriteData raise IOError on windows, consistent
+      # with posix; we could also (in addition) make IOError a subclass of OSError.
+      type SIGPIPEError = OSError
+    else:
+      type SIGPIPEError = IOError
+    doAssertRaises(SIGPIPEError):
+      for i in 0..<100000:
+        count.inc
+        inp.writeLine "ok" # was giving SIGPIPE and crashing
+    doAssert count >= 100
+    doAssert waitForExit(p) == QuitFailure
+    close(p) # xxx isn't that missing in other places?
diff --git a/tests/stdlib/tosprocterminate.nim b/tests/stdlib/tosprocterminate.nim
new file mode 100644
index 000000000..93b0317f7
--- /dev/null
+++ b/tests/stdlib/tosprocterminate.nim
@@ -0,0 +1,44 @@
+discard """
+  cmd: "nim $target $options -r $file"
+  targets: "c cpp"
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import os, osproc, times, std / monotimes
+import std/assertions
+
+when defined(windows):
+  const ProgramWhichDoesNotEnd = "notepad"
+elif defined(openbsd):
+  const ProgramWhichDoesNotEnd = "/bin/cat"
+else:
+  const ProgramWhichDoesNotEnd = "/bin/sh"
+
+echo("starting " & ProgramWhichDoesNotEnd)
+var process = startProcess(ProgramWhichDoesNotEnd)
+sleep(500)
+echo("stopping process")
+process.terminate()
+var TimeToWait = 5000
+while process.running() and TimeToWait > 0:
+  sleep(100)
+  TimeToWait = TimeToWait - 100
+
+doAssert not process.running()
+echo("stopped process")
+
+process.close()
+
+echo("starting " & ProgramWhichDoesNotEnd)
+process = startProcess(ProgramWhichDoesNotEnd)
+echo("process should be stopped after 2s")
+
+let start = getMonoTime()
+discard process.waitForExit(2000)
+let took = getMonoTime() - start
+
+doAssert not process.running()
+# some additional time to account for overhead
+doAssert took < initDuration(seconds = 3)
+
+echo("stopped process after ", took)
diff --git a/tests/stdlib/tpackedsets.nim b/tests/stdlib/tpackedsets.nim
new file mode 100644
index 000000000..f519c08a7
--- /dev/null
+++ b/tests/stdlib/tpackedsets.nim
@@ -0,0 +1,265 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/packedsets
+import std/sets
+
+import sequtils
+import algorithm
+
+import std/assertions
+
+block basicIntSetTests:
+  var y = initPackedSet[int]()
+  y.incl(1)
+  y.incl(2)
+  y.incl(7)
+  y.incl(1056)
+
+  y.incl(1044)
+  y.excl(1044)
+
+  doAssert y == [1, 2, 7, 1056].toPackedSet
+  doAssert toSeq(y.items) == [1, 2, 7, 1056]
+
+  doAssert y.containsOrIncl(888) == false
+  doAssert 888 in y
+  doAssert y.containsOrIncl(888) == true
+
+  doAssert y.missingOrExcl(888) == false
+  doAssert 888 notin y
+  doAssert y.missingOrExcl(888) == true
+
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+type Id = distinct int
+proc `$`(x: Id): string {.borrow.}
+proc cmp(a: Id, b: Id): int {.borrow.}
+proc `==`(a: Id, b: Id): bool {.borrow.}
+proc `<`(a: Id, b: Id): bool {.borrow.}
+
+block genericTests: 
+  # we use HashSet as groundtruth, it's well tested elsewhere
+  template testDel(A: typedesc, t: typed, t0: typed) =
+
+    block:
+      template checkEquals() =
+        doAssert t.len == t0.len
+        for k in t0:
+          doAssert k in t
+        for k in t:
+          doAssert k in t0
+
+        doAssert sortedItems(t) == sortedItems(t0)
+
+      template incl2(i) =
+        t.incl i
+        t0.incl i
+
+      template excl2(i) =
+        t.excl i
+        t0.excl i
+
+      var expected: seq[A]
+      let n = 100
+      let n2 = n*2
+      for i in 0..<n:
+        incl2(A(i))
+      checkEquals()
+      for i in 0..<n:
+        if i mod 3 == 0:
+          if i < n div 2:
+            excl2(A(i))
+          else:
+            t0.excl A(i)
+            doAssert A(i) in t
+            doAssert not t.missingOrExcl A(i)
+
+      checkEquals()
+      for i in n..<n2:
+        incl2(A(i))
+      checkEquals()
+      for i in 0..<n2:
+        if i mod 7 == 0:
+          excl2(A(i))
+      checkEquals()
+
+      # notin check
+      for i in 0..<t.len:
+        if i mod 7 == 0:
+          doAssert A(i) notin t0
+          doAssert A(i) notin t
+          # issue #13505
+          doAssert t.missingOrExcl(A(i))
+
+  var t: PackedSet[int]
+  var t0: HashSet[int]
+  testDel(int, t, t0)
+
+  var distT: PackedSet[Id]
+  var distT0: HashSet[Id]
+  testDel(Id, distT, distT0)
+
+  doAssert union(distT, initPackedSet[Id]()) == distT
+
+  var charT: PackedSet[char]
+  var charT0: HashSet[char]
+  testDel(char, charT, charT0)
+
+
+block typeSafetyTest:
+  # mixing sets of different types shouldn't compile
+  doAssert not compiles( union(initPackedSet[Id](), initPackedSet[int]()) )
+  doAssert     compiles( union(initPackedSet[Id](), initPackedSet[Id]()))
+
+  var ids: PackedSet[Id]
+  doAssert not compiles( ids.incl(3) )
+  doAssert     compiles( ids.incl(Id(3)) )
+
+  type NonOrdinal = string
+  doAssert not compiles( initPackedSet[NonOrdinal]() )
+
+type EnumABCD = enum A, B, C, D
+
+block enumTest:
+  var letterSet = initPackedSet[EnumABCD]()
+
+  for x in [A, C]:
+    letterSet.incl(x)
+
+  doAssert A in letterSet
+  doAssert B notin letterSet
+  doAssert C in letterSet
+  doAssert D notin letterSet
+
+type Foo = distinct int16
+proc `$`(a: Foo): string {.borrow.} # `echo a` below won't work without `$` defined, as expected
+
+block printTest:
+  var a = initPackedSet[EnumABCD]()
+  a.incl A
+  a.incl C 
+  doAssert $a == "{A, C}"
+
+import intsets
+
+block legacyMainModuleTests:
+  template genericTests(A: typedesc[Ordinal], x: typed) =
+    block:
+      proc typSeq(s: seq[int]): seq[A] = s.map(proc (i: int): A = A(i))
+      x.incl(A(1))
+      x.incl(A(2))
+      x.incl(A(7))
+      x.incl(A(1056))
+
+      x.incl(A(1044))
+      x.excl(A(1044))
+
+      doAssert x == typSeq(@[1, 2, 7, 1056]).toPackedSet
+
+      doAssert x.containsOrIncl(A(888)) == false
+      doAssert A(888) in x
+      doAssert x.containsOrIncl(A(888)) == true
+
+      doAssert x.missingOrExcl(A(888)) == false
+      doAssert A(888) notin x
+      doAssert x.missingOrExcl(A(888)) == true
+
+      var xs = toSeq(items(x))
+      xs.sort(cmp[A])
+      doAssert xs == typSeq(@[1, 2, 7, 1056])
+
+      var y: PackedSet[A]
+      assign(y, x)
+      var ys = toSeq(items(y))
+      ys.sort(cmp[A])
+      doAssert ys == typSeq(@[1, 2, 7, 1056])
+
+      doAssert x == y
+
+      var z: PackedSet[A]
+      for i in 0..1000:
+        incl z, A(i)
+        doAssert z.len() == i+1
+      for i in 0..1000:
+        doAssert z.contains(A(i))
+
+      var w = initPackedSet[A]()
+      w.incl(A(1))
+      w.incl(A(4))
+      w.incl(A(50))
+      w.incl(A(1001))
+      w.incl(A(1056))
+
+      var xuw = x.union(w)
+      var xuws = toSeq(items(xuw))
+      xuws.sort(cmp)
+      doAssert xuws == typSeq(@[1, 2, 4, 7, 50, 1001, 1056])
+
+      var xiw = x.intersection(w)
+      var xiws = toSeq(items(xiw))
+      xiws.sort(cmp)
+      doAssert xiws == @[A(1), A(1056)]
+
+      var xdw = x.difference(w)
+      var xdws = toSeq(items(xdw))
+      xdws.sort(cmp[A])
+      doAssert xdws == @[A(2), A(7)]
+
+      var xsw = x.symmetricDifference(w)
+      var xsws = toSeq(items(xsw))
+      xsws.sort(cmp[A])
+      doAssert xsws == typSeq(@[2, 4, 7, 50, 1001])
+
+      x.incl(w)
+      xs = toSeq(items(x))
+      xs.sort(cmp[A])
+      doAssert xs == typSeq(@[1, 2, 4, 7, 50, 1001, 1056])
+
+      doAssert w <= x
+
+      doAssert w < x
+
+      doAssert(not disjoint(w, x))
+
+      var u = initPackedSet[A]()
+      u.incl(A(3))
+      u.incl(A(5))
+      u.incl(A(500))
+      doAssert disjoint(u, x)
+
+      var v = initPackedSet[A]()
+      v.incl(A(2))
+      v.incl(A(50))
+
+      x.excl(v)
+      xs = toSeq(items(x))
+      xs.sort(cmp[A])
+      doAssert xs == typSeq(@[1, 4, 7, 1001, 1056])
+
+      proc bug12366 =
+        var
+          x = initPackedSet[A]()
+          y = initPackedSet[A]()
+          n = 3584
+
+        for i in 0..n:
+          x.incl(A(i))
+          y.incl(A(i))
+
+        let z = symmetricDifference(x, y)
+        doAssert z.len == 0
+        doAssert $z == "{}"
+
+      bug12366()
+
+  var legacyInit = initIntSet()
+  genericTests(int, legacyInit)
+
+  var intGenericInit = initPackedSet[int]()
+  genericTests(int, intGenericInit)
+
+  var intDistinct = initPackedSet[Id]()
+  genericTests(Id, intDistinct)
diff --git a/tests/stdlib/tparsecfg.nim b/tests/stdlib/tparsecfg.nim
new file mode 100644
index 000000000..2600d6f66
--- /dev/null
+++ b/tests/stdlib/tparsecfg.nim
@@ -0,0 +1,132 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import parsecfg, streams, sequtils
+import std/assertions
+
+when not defined(js):
+  from stdtest/specialpaths import buildDir
+  import os
+  # bug #6046
+  block:
+    var config = newConfig()
+    config.setSectionKey("foo", "bar", "-1")
+    config.setSectionKey("foo", "foo", "abc")
+
+    const file = buildDir / "tparsecfg.ini"
+    config.writeConfig(file)
+
+    # file now contains
+    # [foo]
+    # bar=-1
+    # foo=abc
+
+    var config2 = loadConfig(file)
+    let bar = config2.getSectionValue("foo", "bar")
+    let foo = config2.getSectionValue("foo", "foo")
+    doAssert(bar == "-1")
+    doAssert(foo == "abc")
+
+## Creating a configuration file.
+var dict1 = newConfig()
+dict1.setSectionKey("", "charset", "utf-8")
+dict1.setSectionKey("Package", "name", "hello")
+dict1.setSectionKey("Package", "--threads", "on")
+dict1.setSectionKey("Author", "name", "lihf8515")
+dict1.setSectionKey("Author", "qq", "10214028")
+dict1.setSectionKey("Author", "email", "lihaifeng@wxm.com")
+var ss = newStringStream()
+dict1.writeConfig(ss)
+
+## Reading a configuration file.
+let dict2 = loadConfig(newStringStream(ss.data))
+doAssert dict2.getSectionValue("", "charset") == "utf-8"
+doAssert dict2.getSectionValue("Package", "--threads") == "on"
+doAssert dict2.getSectionValue("Package", "name") == "hello"
+doAssert dict2.getSectionValue("Author", "name") == "lihf8515"
+doAssert dict2.getSectionValue("Author", "qq") == "10214028"
+doAssert dict2.getSectionValue("Author", "email") == "lihaifeng@wxm.com"
+doAssert toSeq(dict2.sections) == @["", "Package", "Author"]
+
+## Modifying a configuration file.
+var dict3 = loadConfig(newStringStream(ss.data))
+dict3.setSectionKey("Author", "name", "lhf")
+doAssert $dict3 == """charset=utf-8
+[Package]
+name=hello
+--threads:on
+[Author]
+name=lhf
+qq=10214028
+email="lihaifeng@wxm.com"
+"""
+
+## Deleting a section key in a configuration file.
+var dict4 = loadConfig(newStringStream(ss.data))
+dict4.delSectionKey("Author", "email")
+doAssert $dict4 == """charset=utf-8
+[Package]
+name=hello
+--threads:on
+[Author]
+name=lihf8515
+qq=10214028
+"""
+
+block:
+  var dict = loadConfig(newStringStream("""[Simple Values]
+  key=value
+  spaces in keys=allowed
+  spaces in values=allowed as well
+  spaces around the delimiter = obviously
+  you can also use : to delimit keys from values
+  [All Values Are Strings]
+  values like this: 19990429
+  or this: 3.14159265359
+  are they treated as numbers : no
+  integers floats and booleans are held as: strings
+  can use the API to get converted values directly: true
+  [No Values]
+  key_without_value
+  # empty string value is not allowed =
+  [ Seletion A   ]
+  space around section name will be ignored
+  [You can use comments]
+  # like this
+  ; or this
+  # By default only in an empty line.
+  # Inline comments can be harmful because they prevent users
+  # from using the delimiting characters as parts of values.
+  # That being said, this can be customized.
+      [Sections Can Be Indented]
+          can_values_be_as_well = True
+          does_that_mean_anything_special = False
+          purpose = formatting for readability
+          # Did I mention we can indent comments, too?
+  """)
+  )
+
+  let section1 = "Simple Values"
+  doAssert dict.getSectionValue(section1, "key") == "value"
+  doAssert dict.getSectionValue(section1, "spaces in keys") == "allowed"
+  doAssert dict.getSectionValue(section1, "spaces in values") == "allowed as well"
+  doAssert dict.getSectionValue(section1, "spaces around the delimiter") == "obviously"
+  doAssert dict.getSectionValue(section1, "you can also use") == "to delimit keys from values"
+
+  let section2 = "All Values Are Strings"
+  doAssert dict.getSectionValue(section2, "values like this") == "19990429"
+  doAssert dict.getSectionValue(section2, "or this") == "3.14159265359"
+  doAssert dict.getSectionValue(section2, "are they treated as numbers") == "no"
+  doAssert dict.getSectionValue(section2, "integers floats and booleans are held as") == "strings"
+  doAssert dict.getSectionValue(section2, "can use the API to get converted values directly") == "true"
+
+  let section3 = "Seletion A"
+  doAssert dict.getSectionValue(section3, 
+    "space around section name will be ignored", "not an empty value") == ""
+
+  let section4 = "Sections Can Be Indented"
+  doAssert dict.getSectionValue(section4, "can_values_be_as_well") == "True"
+  doAssert dict.getSectionValue(section4, "does_that_mean_anything_special") == "False"
+  doAssert dict.getSectionValue(section4, "purpose") == "formatting for readability"
diff --git a/tests/stdlib/tparsecsv.nim b/tests/stdlib/tparsecsv.nim
new file mode 100644
index 000000000..5a1e41bce
--- /dev/null
+++ b/tests/stdlib/tparsecsv.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+include parsecsv
+import strutils, os
+import std/assertions
+
+block: # Tests for reading the header row
+  let content = "\nOne,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
+  writeFile("temp.csv", content)
+
+  var p: CsvParser
+  p.open("temp.csv")
+  p.readHeaderRow()
+  while p.readRow():
+    let zeros = repeat('0', p.currRow-2)
+    doAssert p.rowEntry("One") == "1" & zeros
+    doAssert p.rowEntry("Two") == "2" & zeros
+    doAssert p.rowEntry("Three") == "3" & zeros
+    doAssert p.rowEntry("Four") == "4" & zeros
+  p.close()
+
+  when not defined(testing):
+    var parser: CsvParser
+    parser.open("temp.csv")
+    parser.readHeaderRow()
+    while parser.readRow():
+      echo "new row: "
+      for col in items(parser.headers):
+        echo "##", col, ":", parser.rowEntry(col), "##"
+    parser.close()
+    removeFile("temp.csv")
+
+  # Tidy up
+  removeFile("temp.csv")
diff --git a/tests/stdlib/tparseipv6.nim b/tests/stdlib/tparseipv6.nim
new file mode 100644
index 000000000..31ec4ecfb
--- /dev/null
+++ b/tests/stdlib/tparseipv6.nim
@@ -0,0 +1,226 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: "all ok"
+"""
+
+import net
+
+const
+  positives = [
+    "::f:8:a8f:218.17.235.229",
+    "::b:228.19.241.2",
+    "::8:c:a:f:8.35.8.96",
+    "::3:e:a:bc:4.19.2.9",
+    "::2:212.242.248.19",
+    "::df:a5f:3.250.208.9",
+    "::8:c:5:e63:250.208.249.0",
+    "::b:f:181.12.9.98",
+    "::a:f8:77.8.243.232",
+    "::a:b:85:e4d9:252.9.229.56",
+    "941:c:8a:c:e::917",
+    "e8:7a:e:ad:88a:8:203.235.225.46",
+    "139c:9e::f8:254.8.21.249",
+    "b38:f0:e::f9:89.6.12.18",
+    "ef::8",
+    "5::ab",
+    "a::8:255.247.96.253",
+    "b:c0::c:254.248.95.254",
+    "::8c:2:99.251.24.3",
+    "98::c:247.240.249.57",
+    "9::9",
+    "628::f1ed:f",
+    "c::cca8",
+    "2::3:c",
+    "fde::8fcc:92:e",
+    "f::3",
+    "e85::7",
+    "8::b:f6",
+    "0::6:8ca",
+    "c8::6e:be8",
+    "87::e",
+    "6:9::a7:9",
+    "c::5",
+    "49::1:62",
+    "df:c0::f:9",
+    "a09a:8::21:887a",
+    "2:f::c",
+    "8bf5:5::2a6e:f8f",
+    "a:9e::bc:a",
+    "f:60::c:fd",
+    "59::52f:0:fa7",
+    "8268:6cf::f:9",
+    "c:abb::f",
+    "a:ff8d::9:7",
+    "05:c87::9c:9a",
+    "e:f::c:9a:1",
+    "ff6:8::962:e",
+    "9::bd",
+    "68:ec::6",
+    "3b8:f::94:3e9:9952",
+    "49b4:ae::899:b4",
+    "cb9:8e8:af::f4",
+    "8::10:9ae6:f9",
+    "b9::2:57",
+    "ff:fba9::d",
+    "4::a:8",
+    "caa:c:85a::2:3",
+    "5::a5:9",
+    "c:ad::a",
+    "9a:f:f65::b",
+    "f:df::9:0",
+    "c:b9::8de",
+    "d:f::a",
+    "ab88:d4:0::fc:8d",
+    "8f:ee2::3",
+    "f:f8::bf2:8c8",
+    "8::efc",
+    "e:5a::b",
+    "c:48::94",
+    "a:b:5::8",
+    "f:88f::f0a6",
+    "9:f:e::3",
+    "b::fedd",
+    "7b:f::c",
+    "edf4:7d::88",
+    "89::d",
+    "c0:a:62::ac",
+    "7:f::b",
+    "8::a2",
+    "0f::1",
+    "::",
+    "b:8::",
+    "44:a::",
+    "ef8f::",
+    "b:4:d::",
+    "a::",
+    "5a:8::",
+    "ddaf:ecbf::",
+    "f:bb:a1::",
+    "f8:f::",
+    "::e:38:ab:f8",
+    "::cd:c",
+    "::aa3:eb",
+    "::bf:9f9",
+    "::7ef:bf8a",
+    "::9",
+    "::a:9af",
+    "::315",
+    "::a:a",
+    "::aed3:a",
+    "f0eb:0:e8:b:c:a:254.98.233.17",
+    "bfa:7fc:c66d:15:e9a:ded:254.119.9.9",
+    "d:ffa8:9:a:879:3:202.39.8.245",
+    "8e:2:8:fa8a:f1d1:1aa8:252.254.245.81",
+    "5:d4:a:e9:8:8:6.38.98.253",
+    "9c5:4:a5c:f:a6:8c9d:5.250.8.2",
+    "d19a:2:f808:be:f:c:98.86.197.249",
+    "8:26ac:8:8:cb:f:242.0.254.85",
+    "38:e:1:0b88:f:0:8.89.248.92",
+    "e7:ff96:a:f:f:b:253.91.52.195",
+    "d:8:2:5:894:5:254.0.240.199",
+    "2:98:9:8aa:9c8f:fa:252.98.248.17",
+    "e9:d4f:890:ccbe:5:8:88.200.228.216",
+    "3:3:9:5:6a:df5:255.251.8.12",
+    "0280:3:8:8:4:9:255.0.251.249",
+    "8:af7:db:aa:0:9:238.248.250.255",
+    "ff:ee:9a:9252:a:289:59.83.18.255",
+    "9f6:5:fc9:b:a89:a:142.1.250.254",
+    "e:981a:da:bf94:9:f8:254.242.18.95",
+    "3c:1:4:f2:89:f:8.91.255.14",
+    "e::9a2:c:9.50.80.8",
+    "9::4a:07:fb:211.241.254.228",
+    "9be::2:e:215.189.48.188",
+    "f::f:d:69.148.99.168",
+    "f::a:97.18.240.47",
+    "c::a98e:1:251.253.252.254",
+    "668::82:214.87.208.9",
+    "9c0::cf0:ecb:253.208.238.255",
+    "a::0:f1:210.240.238.49",
+    "8::a:1:251.238.34.9",
+    "81:dfe::b8:8.255.249.248",
+    "d3::7:b:9:83.189.8.244",
+    "8::9:8:8:0.7.11.252",
+    "2:8::c:a8:250.221.9.249",
+    "2::f:99.8.249.247",
+    "c:22f5::5:2c:243.15.79.89",
+    "e:8e::da:251.243.255.2",
+    "f15f:9::a:255.70.247.218",
+    "f:b::9f38:31.220.94.22",
+    "9::9a48:3.98.249.119",
+    "d:d:9b87::2d:a:249.253.38.8",
+    "d86d:99b::a9b:5:242.236.8.244",
+    "eb:3::f:9cf:1.253.1.228",
+    "b::ba2:255.247.114.64",
+    "2f:ec:bcb::9:219.254.250.94",
+    "da8a:f6::a:e0:19.251.241.251",
+    "5e:c1::a:21.250.8.254",
+    "c:9::8c9b:248.219.212.252",
+    "2:a::8d4a:216.255.198.223",
+    "1f::66:255.30.8.150",
+    "bc2b:8f::2ff9:6.245.99.230",
+    "a:8::a8:9.251.246.255",
+    "f:7:7::98:6.14.1.208",
+    "e:2::9:218.249.255.254",
+    "79:f::6:250.255.98.246",
+    "47:9:fb9f::9:38.136.17.251",
+    "ed::a:247.9.23.239",
+    "6f::f1:88.254.119.9",
+    "a::d:218.199.236.0",
+    "fc88::9:203.196.4.95",
+    "::8.48.255.85",
+    "::253.7.255.36",
+    "9:d::253.7.178.229",
+    "::250.84.158.253",
+    "::8.55.204.248",
+    "2d:c::253.18.18.252",
+    "df9:88ca::248.255.108.17",
+    "8e9b::250.206.0.82",
+    "::209.8.254.209",
+    "::247.88.8.8",
+    "::cb:f:ba41:250.208.19.249",
+    "::fe:0e8:243.240.229.5",
+    "::c:223.251.5.226",
+    "::8:8.3.8.250",
+    "::f:8.88.11.255",
+    "::fda:48:aa:5.189.7.2",
+    "::8:c3f:f:240.6.212.255",
+    "::f:0aa:244.123.99.16",
+    "::c9b5:c:34.8.90.196",
+    "::98:c9:254.14.241.81"
+  ]
+  negatives = ["foo.bar",
+    "::::::::::::",
+    "yet another failure",
+    "de:6:c:ab5:6a::9:252.6.6.249",
+    "f9:5f7:fa38:9:b::b6:9.255.248.252",
+    "97:c:5b:81:8a::f5dd:144.252.250.9",
+    "9:8:cd:8:a9::f:247.255.9.255",
+    "18:1:8c:2:3::9:8.254.252.139",
+    "e:c298:3:e:a::bb12:254.246.5.250",
+    "e:e:c:8e:fd::8:253.8.49.231",
+    "9:97f:f:e929:8a::c9:0.8.252.10",
+    "0df:b24:7:89:c::2b:16.249.240.92",
+    "b:8f5f:485:c:9a::84c:178.7.249.34",
+    "::3:e:a:bc:091.19.2.9",
+    "::a:f8:77.08.243.232",
+    "::8c:2:99.251.029.3",
+    "::8:c:a:f:8.35.8.096",
+    "d:ffa8:9:a:879:3:0202.39.8.245",
+    "139c:9e::f8:254.07.21.249",
+    "f0eb:0:e8:b:c:a:254.233.043.17",
+    "::a:b:85:e4d9:252.9.229.056",
+  ]
+
+proc ok(pos: openArray[string]) =
+  for p in pos:
+    if not isIpAddress(p):
+      echo "failure ", p
+
+proc notok(neg: openArray[string]) =
+  for n in neg:
+    if isIpAddress(n):
+      echo "failure ", n
+
+ok(positives)
+notok(negatives)
+echo "all ok"
diff --git a/tests/stdlib/tparsesql.nim b/tests/stdlib/tparsesql.nim
new file mode 100644
index 000000000..cd582551d
--- /dev/null
+++ b/tests/stdlib/tparsesql.nim
@@ -0,0 +1,245 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+import parsesql
+import std/assertions
+
+doAssert treeRepr(parseSql("INSERT INTO STATS VALUES (10, 5.5); ")
+) == """
+
+nkStmtList
+  nkInsert
+    nkIdent STATS
+    nkNone
+    nkValueList
+      nkIntegerLit 10
+      nkNumericLit 5.5"""
+
+doAssert $parseSql("SELECT foo FROM table;") == "select foo from table;"
+doAssert $parseSql("""
+SELECT
+  CustomerName,
+  ContactName,
+  Address,
+  City,
+  PostalCode,
+  Country,
+  CustomerName,
+  ContactName,
+  Address,
+  City,
+  PostalCode,
+  Country
+FROM table;""") == "select CustomerName, ContactName, Address, City, PostalCode, Country, CustomerName, ContactName, Address, City, PostalCode, Country from table;"
+
+doAssert $parseSql("SELECT foo FROM table limit 10") == "select foo from table limit 10;"
+doAssert $parseSql("SELECT foo, bar, baz FROM table limit 10") == "select foo, bar, baz from table limit 10;"
+doAssert $parseSql("SELECT foo AS bar FROM table") == "select foo as bar from table;"
+doAssert $parseSql("SELECT foo AS foo_prime, bar AS bar_prime, baz AS baz_prime FROM table") == "select foo as foo_prime, bar as bar_prime, baz as baz_prime from table;"
+doAssert $parseSql("SELECT * FROM table") == "select * from table;"
+doAssert $parseSql("SELECT count(*) FROM table") == "select count(*) from table;"
+doAssert $parseSql("SELECT count(*) as 'Total' FROM table") == "select count(*) as 'Total' from table;"
+doAssert $parseSql("SELECT count(*) as 'Total', sum(a) as 'Aggr' FROM table") == "select count(*) as 'Total', sum(a) as 'Aggr' from table;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+WHERE a = b and c = d
+""") == "select * from table where a = b and c = d;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+WHERE not b
+""") == "select * from table where not b;"
+
+doAssert $parseSql("""
+SELECT
+  *
+FROM
+  table
+WHERE
+  a and not b
+""") == "select * from table where a and not b;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+ORDER BY 1
+""") == "select * from table order by 1;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+GROUP BY 1
+ORDER BY 1
+""") == "select * from table group by 1 order by 1;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+ORDER BY 1
+LIMIT 100
+""") == "select * from table order by 1 limit 100;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+WHERE a = b and c = d or n is null and not b + 1 = 3
+""") == "select * from table where a = b and c = d or n is null and not b + 1 = 3;"
+
+doAssert $parseSql("""
+SELECT * FROM table
+WHERE (a = b and c = d) or (n is null and not b + 1 = 3)
+""") == "select * from table where(a = b and c = d) or (n is null and not b + 1 = 3);"
+
+doAssert $parseSql("""
+SELECT * FROM table
+HAVING a = b and c = d
+""") == "select * from table having a = b and c = d;"
+
+doAssert $parseSql("""
+SELECT a, b FROM table
+GROUP BY a
+""") == "select a, b from table group by a;"
+
+doAssert $parseSql("""
+SELECT a, b FROM table
+GROUP BY 1, 2
+""") == "select a, b from table group by 1, 2;"
+
+doAssert $parseSql("SELECT t.a FROM t as t") == "select t.a from t as t;"
+
+doAssert $parseSql("""
+SELECT a, b FROM (
+  SELECT * FROM t
+)
+""") == "select a, b from(select * from t);"
+
+doAssert $parseSql("""
+SELECT a, b FROM (
+  SELECT * FROM t
+) as foo
+""") == "select a, b from(select * from t) as foo;"
+
+doAssert $parseSql("""
+SELECT a, b FROM (
+  SELECT * FROM (
+    SELECT * FROM (
+      SELECT * FROM (
+        SELECT * FROM innerTable as inner1
+      ) as inner2
+    ) as inner3
+  ) as inner4
+) as inner5
+""") == "select a, b from(select * from(select * from(select * from(select * from innerTable as inner1) as inner2) as inner3) as inner4) as inner5;"
+
+doAssert $parseSql("""
+SELECT a, b FROM
+  (SELECT * FROM a),
+  (SELECT * FROM b),
+  (SELECT * FROM c)
+""") == "select a, b from(select * from a),(select * from b),(select * from c);"
+
+doAssert $parseSql("""
+SELECT * FROM Products
+WHERE Price BETWEEN 10 AND 20;
+""") == "select * from Products where Price between 10 and 20;"
+
+doAssert $parseSql("""
+SELECT id FROM a
+JOIN b
+ON a.id == b.id
+""") == "select id from a join b on a.id == b.id;"
+
+doAssert $parseSql("""
+SELECT id FROM a
+JOIN (SELECT id from c) as b
+ON a.id == b.id
+""") == "select id from a join(select id from c) as b on a.id == b.id;"
+
+doAssert $parseSql("""
+SELECT id FROM a
+INNER JOIN b
+ON a.id == b.id
+""") == "select id from a inner join b on a.id == b.id;"
+
+doAssert $parseSql("""
+SELECT id FROM a
+OUTER JOIN b
+ON a.id == b.id
+""") == "select id from a outer join b on a.id == b.id;"
+
+doAssert $parseSql("""
+SELECT id FROM a
+CROSS JOIN b
+ON a.id == b.id
+""") == "select id from a cross join b on a.id == b.id;"
+
+doAssert $parseSql("""
+CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
+CREATE TABLE holidays (
+  num_weeks int,
+  happiness happiness
+);
+CREATE INDEX table1_attr1 ON table1(attr1);
+SELECT * FROM myTab WHERE col1 = 'happy';
+""") == "create type happiness as enum ('happy' , 'very happy' , 'ecstatic' ); create table holidays(num_weeks  int , happiness  happiness );; create index table1_attr1 on table1(attr1 );; select * from myTab where col1 = 'happy';"
+
+doAssert $parseSql("""
+INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
+VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');
+""") == "insert into Customers (CustomerName , ContactName , Address , City , PostalCode , Country ) values ('Cardinal' , 'Tom B. Erichsen' , 'Skagen 21' , 'Stavanger' , '4006' , 'Norway' );"
+
+doAssert $parseSql("""
+INSERT INTO TableName DEFAULT VALUES
+""") == "insert into TableName default values;"
+
+doAssert $parseSql("""
+UPDATE Customers
+SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
+WHERE CustomerID = 1;
+""") == "update Customers set ContactName  = 'Alfred Schmidt' , City  = 'Frankfurt' where CustomerID = 1;"
+
+doAssert treeRepr(parseSql("""UPDATE Customers
+                              SET ContactName = 'Alice', City= 'Frankfurt';""")
+) == """
+
+nkStmtList
+  nkUpdate
+    nkIdent Customers
+    nkAsgn
+      nkIdent ContactName
+      nkStringLit Alice
+    nkAsgn
+      nkIdent City
+      nkStringLit Frankfurt
+    nkNone"""
+
+doAssert $parseSql("DELETE FROM table_name;") == "delete from table_name;"
+
+doAssert treeRepr(parseSql("DELETE FROM table_name;")
+) == """
+
+nkStmtList
+  nkDelete
+    nkIdent table_name
+    nkNone"""
+
+doAssert $parseSql("DELETE * FROM table_name;") == "delete from table_name;"
+
+doAssert $parseSql("""
+--Select all:
+SELECT * FROM Customers;
+""") == "select * from Customers;"
+
+doAssert $parseSql("""
+SELECT * FROM Customers WHERE (CustomerName LIKE 'L%'
+OR CustomerName LIKE 'R%' /*OR CustomerName LIKE 'S%'
+OR CustomerName LIKE 'T%'*/ OR CustomerName LIKE 'W%')
+AND Country='USA'
+ORDER BY CustomerName;
+""") == "select * from Customers where(CustomerName like 'L%' or CustomerName like 'R%' or CustomerName like 'W%') and Country = 'USA' order by CustomerName;"
+
+# parse quoted keywords as identifires
+doAssert $parseSql("""
+SELECT `SELECT`, `FROM` as `GROUP` FROM `WHERE`;
+""") == """select "SELECT", "FROM" as "GROUP" from "WHERE";"""
+doAssert $parseSql("""
+SELECT "SELECT", "FROM" as "GROUP" FROM "WHERE";
+""") == """select "SELECT", "FROM" as "GROUP" from "WHERE";"""
diff --git a/tests/stdlib/tparseuints.nim b/tests/stdlib/tparseuints.nim
new file mode 100644
index 000000000..9c71a27d6
--- /dev/null
+++ b/tests/stdlib/tparseuints.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import unittest, strutils
+
+block: # parseutils
+  check: parseBiggestUInt("0") == 0'u64
+  check: parseBiggestUInt("18446744073709551615") == 0xFFFF_FFFF_FFFF_FFFF'u64
+  expect(ValueError):
+    discard parseBiggestUInt("18446744073709551616")
diff --git a/tests/stdlib/tparseutils.nim b/tests/stdlib/tparseutils.nim
new file mode 100644
index 000000000..b69900864
--- /dev/null
+++ b/tests/stdlib/tparseutils.nim
@@ -0,0 +1,112 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp"
+"""
+
+import std/[parseutils, sequtils, sugar, formatfloat]
+import std/assertions
+
+proc test() =
+  let input = "$test{}  $this is ${an{  example}}  "
+  let expected = @[(ikVar, "test"), (ikStr, "{}  "), (ikVar, "this"),
+                    (ikStr, " is "), (ikExpr, "an{  example}"), (ikStr, "  ")]
+  doAssert toSeq(interpolatedFragments(input)) == expected
+
+  var value = 0
+  discard parseHex("0x38", value)
+  doAssert value == 56
+
+  value = -1
+  doAssert(parseSaturatedNatural("848", value) == 3)
+  doAssert value == 848
+
+  value = -1
+  discard parseSaturatedNatural("84899999999999999999324234243143142342135435342532453", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("9223372036854775808", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("9223372036854775807", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("18446744073709551616", value)
+  doAssert value == high(int)
+
+  value = -1
+  discard parseSaturatedNatural("18446744073709551615", value)
+  doAssert value == high(int)
+
+  value = -1
+  doAssert(parseSaturatedNatural("1_000_000", value) == 9)
+  doAssert value == 1_000_000
+
+  var i64Value: int64
+  discard parseBiggestInt("9223372036854775807", i64Value)
+  doAssert i64Value == 9223372036854775807
+
+  block:
+    var f: float
+    let res = collect:
+      for x in ["9.123456789012345+","11.123456789012345+","9.123456789012345-","8.123456789012345+","9.12345678901234-","9.123456789012345"]:
+        (parseFloat(x, f, 0), $f)
+    doAssert res == @[(17, "9.123456789012344"), (18, "11.123456789012344"),
+                      (17, "9.123456789012344"), (17, "8.123456789012344"),
+                      (16, "9.12345678901234"), (17, "9.123456789012344")]
+
+test()
+static: test()
+
+block:  # With this included, static: test() crashes the compiler (from a
+        # VM problem with parseSize calling parseFloat).
+  var sz: int64
+  template checkParseSize(s, expectLen, expectVal) =
+    if (let got = parseSize(s, sz); got != expectLen):
+      raise newException(IOError, "got len " & $got & " != " & $expectLen)
+    if sz != expectVal:
+      raise newException(IOError, "got sz " & $sz & " != " & $expectVal)
+  #              STRING    LEN SZ
+  # Good, complete parses
+  checkParseSize "1  b"   , 4, 1
+  checkParseSize "1  B"   , 4, 1
+  checkParseSize "1k"     , 2, 1000
+  checkParseSize "1 kib"  , 5, 1024
+  checkParseSize "1 ki"   , 4, 1024
+  checkParseSize "1mi"    , 3, 1048576
+  checkParseSize "1 mi"   , 4, 1048576
+  checkParseSize "1 mib"  , 5, 1048576
+  checkParseSize "1 Mib"  , 5, 1048576
+  checkParseSize "1 MiB"  , 5, 1048576
+  checkParseSize "1.23GiB", 7, 1320702444 # 1320702443.52 rounded
+  checkParseSize "0.001k" , 6, 1
+  checkParseSize "0.0004k", 7, 0
+  checkParseSize "0.0006k", 7, 1
+  # Incomplete parses
+  checkParseSize "1  "    , 1, 1          # Trailing white IGNORED
+  checkParseSize "1  B "  , 4, 1          # Trailing white IGNORED
+  checkParseSize "1  B/s" , 4, 1          # Trailing junk IGNORED
+  checkParseSize "1 kX"   , 3, 1000
+  checkParseSize "1 kiX"  , 4, 1024
+  checkParseSize "1j"     , 1, 1          # Unknown prefix IGNORED
+  checkParseSize "1 jib"  , 2, 1          # Unknown prefix post space
+  checkParseSize "1  ji"  , 3, 1
+  # Bad parses; `sz` should stay last good|incomplete value
+  checkParseSize "-1b"    , 0, 1          # Negative numbers
+  checkParseSize "abc"    , 0, 1          # Non-numeric
+  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/tparsopt.nim b/tests/stdlib/tparsopt.nim
new file mode 100644
index 000000000..f3a9a9798
--- /dev/null
+++ b/tests/stdlib/tparsopt.nim
@@ -0,0 +1,35 @@
+discard """
+disabled: true
+"""
+
+# this file has a type in the name, and it does not really test
+# parseopt module, because tester has no support to set arguments. Test the
+# new parseopt module. Therefore it is disabled.
+
+import
+  parseopt
+
+import std/[assertions, syncio]
+
+proc writeHelp() =
+  writeLine(stdout, "Usage: tparsopt [options] filename [options]")
+
+proc writeVersion() =
+  writeLine(stdout, "Version: 1.0.0")
+
+var
+  filename = ""
+for kind, key, val in getopt():
+  case kind
+  of cmdArgument:
+    filename = key
+  of cmdLongOption, cmdShortOption:
+    case key
+    of "help", "h": writeHelp()
+    of "version", "v": writeVersion()
+    else:
+      writeLine(stdout, "Unknown command line option: ", key, ": ", val)
+  of cmdEnd: doAssert(false) # cannot happen
+if filename == "":
+  # no filename has been given, so we show the help:
+  writeHelp()
diff --git a/tests/stdlib/tpathnorm.nim b/tests/stdlib/tpathnorm.nim
new file mode 100644
index 000000000..3dd287a77
--- /dev/null
+++ b/tests/stdlib/tpathnorm.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/os
+import std/assertions
+
+when doslikeFileSystem:
+  import std/pathnorm
+
+  template initVars =
+    var state {.inject.} = 0
+    var result {.inject.}: string
+
+  block: # / -> /
+    initVars
+    addNormalizePath("//?/c:/./foo//bar/../baz", result, state, '/')
+    doAssert result == "//?/c:/foo/baz"
+    addNormalizePath("me", result, state, '/')
+    doAssert result == "//?/c:/foo/baz/me"
+
+  block: # / -> \
+    initVars
+    addNormalizePath(r"//?/c:/./foo//bar/../baz", result, state, '\\')
+    doAssert result == r"\\?\c:\foo\baz"
+    addNormalizePath("me", result, state, '\\')
+    doAssert result == r"\\?\c:\foo\baz\me"
+
+  block: # Append path component to UNC drive
+    initVars
+    addNormalizePath(r"//?/c:", result, state, '\\')
+    doAssert result == r"\\?\c:"
+    addNormalizePath("Users", result, state, '\\')
+    doAssert result == r"\\?\c:\Users"
+    addNormalizePath("me", result, state, '\\')
+    doAssert result == r"\\?\c:\Users\me"
diff --git a/tests/stdlib/tpaths.nim b/tests/stdlib/tpaths.nim
new file mode 100644
index 000000000..edb56209a
--- /dev/null
+++ b/tests/stdlib/tpaths.nim
@@ -0,0 +1,238 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/paths
+import std/assertions
+import pathnorm
+from std/private/ospaths2 {.all.} import joinPathImpl
+import std/[sugar, sets]
+
+
+proc normalizePath*(path: Path; dirSep = DirSep): Path =
+  result = Path(pathnorm.normalizePath(path.string, dirSep))
+
+func joinPath*(parts: varargs[Path]): Path =
+  var estimatedLen = 0
+  var state = 0
+  for p in parts: estimatedLen += p.string.len
+  var res = newStringOfCap(estimatedLen)
+  for i in 0..high(parts):
+    joinPathImpl(res, state, parts[i].string)
+  result = Path(res)
+
+
+func joinPath(head, tail: Path): Path {.inline.} =
+  head / tail
+
+block absolutePath:
+  doAssertRaises(ValueError): discard absolutePath(Path"a", Path"b")
+  doAssert absolutePath(Path"a") == getCurrentDir() / Path"a"
+  doAssert absolutePath(Path"a", Path"/b") == Path"/b" / Path"a"
+  when defined(posix):
+    doAssert absolutePath(Path"a", Path"/b/") == Path"/b" / Path"a"
+    doAssert absolutePath(Path"a", Path"/b/c") == Path"/b/c" / Path"a"
+    doAssert absolutePath(Path"/a", Path"b/") == Path"/a"
+
+block splitFile:
+  doAssert splitFile(Path"") == (Path"", Path"", "")
+  doAssert splitFile(Path"abc/") == (Path"abc", Path"", "")
+  doAssert splitFile(Path"/") == (Path"/", Path"", "")
+  doAssert splitFile(Path"./abc") == (Path".", Path"abc", "")
+  doAssert splitFile(Path".txt") == (Path"", Path".txt", "")
+  doAssert splitFile(Path"abc/.txt") == (Path"abc", Path".txt", "")
+  doAssert splitFile(Path"abc") == (Path"", Path"abc", "")
+  doAssert splitFile(Path"abc.txt") == (Path"", Path"abc", ".txt")
+  doAssert splitFile(Path"/abc.txt") == (Path"/", Path"abc", ".txt")
+  doAssert splitFile(Path"/foo/abc.txt") == (Path"/foo", Path"abc", ".txt")
+  doAssert splitFile(Path"/foo/abc.txt.gz") == (Path"/foo", Path"abc.txt", ".gz")
+  doAssert splitFile(Path".") == (Path"", Path".", "")
+  doAssert splitFile(Path"abc/.") == (Path"abc", Path".", "")
+  doAssert splitFile(Path"..") == (Path"", Path"..", "")
+  doAssert splitFile(Path"a/..") == (Path"a", Path"..", "")
+  doAssert splitFile(Path"/foo/abc....txt") == (Path"/foo", Path"abc...", ".txt")
+
+# execShellCmd is tested in tosproc
+
+block ospaths:
+  doAssert unixToNativePath(Path"") == Path""
+  doAssert unixToNativePath(Path".") == Path($CurDir)
+  doAssert unixToNativePath(Path"..") == Path($ParDir)
+  doAssert isAbsolute(unixToNativePath(Path"/"))
+  doAssert isAbsolute(unixToNativePath(Path"/", Path"a"))
+  doAssert isAbsolute(unixToNativePath(Path"/a"))
+  doAssert isAbsolute(unixToNativePath(Path"/a", Path"a"))
+  doAssert isAbsolute(unixToNativePath(Path"/a/b"))
+  doAssert isAbsolute(unixToNativePath(Path"/a/b", Path"a"))
+  doAssert unixToNativePath(Path"a/b") == joinPath(Path"a", Path"b")
+
+  when defined(macos):
+    doAssert unixToNativePath(Path"./") == Path":"
+    doAssert unixToNativePath(Path"./abc") == Path":abc"
+    doAssert unixToNativePath(Path"../abc") == Path"::abc"
+    doAssert unixToNativePath(Path"../../abc") == Path":::abc"
+    doAssert unixToNativePath(Path"/abc", Path"a") == Path"abc"
+    doAssert unixToNativePath(Path"/abc/def", Path"a") == Path"abc:def"
+  elif doslikeFileSystem:
+    doAssert unixToNativePath(Path"./") == Path(".\\")
+    doAssert unixToNativePath(Path"./abc") == Path(".\\abc")
+    doAssert unixToNativePath(Path"../abc") == Path("..\\abc")
+    doAssert unixToNativePath(Path"../../abc") == Path("..\\..\\abc")
+    doAssert unixToNativePath(Path"/abc", Path"a") == Path("a:\\abc")
+    doAssert unixToNativePath(Path"/abc/def", Path"a") == Path("a:\\abc\\def")
+  else:
+    #Tests for unix
+    doAssert unixToNativePath(Path"./") == Path"./"
+    doAssert unixToNativePath(Path"./abc") == Path"./abc"
+    doAssert unixToNativePath(Path"../abc") == Path"../abc"
+    doAssert unixToNativePath(Path"../../abc") == Path"../../abc"
+    doAssert unixToNativePath(Path"/abc", Path"a") == Path"/abc"
+    doAssert unixToNativePath(Path"/abc/def", Path"a") == Path"/abc/def"
+
+  block extractFilenameTest:
+    doAssert extractFilename(Path"") == Path""
+    when defined(posix):
+      doAssert extractFilename(Path"foo/bar") == Path"bar"
+      doAssert extractFilename(Path"foo/bar.txt") == Path"bar.txt"
+      doAssert extractFilename(Path"foo/") == Path""
+      doAssert extractFilename(Path"/") == Path""
+    when doslikeFileSystem:
+      doAssert extractFilename(Path(r"foo\bar")) == Path"bar"
+      doAssert extractFilename(Path(r"foo\bar.txt")) == Path"bar.txt"
+      doAssert extractFilename(Path(r"foo\")) == Path""
+      doAssert extractFilename(Path(r"C:\")) == Path""
+
+  block lastPathPartTest:
+    doAssert lastPathPart(Path"") == Path""
+    when defined(posix):
+      doAssert lastPathPart(Path"foo/bar.txt") == Path"bar.txt"
+      doAssert lastPathPart(Path"foo/") == Path"foo"
+      doAssert lastPathPart(Path"/") == Path""
+    when doslikeFileSystem:
+      doAssert lastPathPart(Path(r"foo\bar.txt")) == Path"bar.txt"
+      doAssert lastPathPart(Path(r"foo\")) == Path"foo"
+
+  template canon(x): Path = normalizePath(Path(x), '/')
+  doAssert canon"/foo/../bar" == Path"/bar"
+  doAssert canon"foo/../bar" == Path"bar"
+
+  doAssert canon"/f/../bar///" == Path"/bar"
+  doAssert canon"f/..////bar" == Path"bar"
+
+  doAssert canon"../bar" == Path"../bar"
+  doAssert canon"/../bar" == Path"/../bar"
+
+  doAssert canon("foo/../../bar/") == Path"../bar"
+  doAssert canon("./bla/blob/") == Path"bla/blob"
+  doAssert canon(".hiddenFile") == Path".hiddenFile"
+  doAssert canon("./bla/../../blob/./zoo.nim") == Path"../blob/zoo.nim"
+
+  doAssert canon("C:/file/to/this/long") == Path"C:/file/to/this/long"
+  doAssert canon("") == Path""
+  doAssert canon("foobar") == Path"foobar"
+  doAssert canon("f/////////") == Path"f"
+
+  doAssert relativePath(Path"/foo/bar//baz.nim", Path"/foo", '/') == Path"bar/baz.nim"
+  doAssert normalizePath(Path"./foo//bar/../baz", '/') == Path"foo/baz"
+
+  doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/other/bad", '/') == Path"../../me/bar/z.nim"
+
+  doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/other", '/') == Path"../me/bar/z.nim"
+
+  # `//` is a UNC path, `/` is the current working directory's drive, so can't
+  # run this test on Windows.
+  when not doslikeFileSystem:
+    doAssert relativePath(Path"/Users///me/bar//z.nim", Path"//Users/", '/') == Path"me/bar/z.nim"
+  doAssert relativePath(Path"/Users/me/bar/z.nim", Path"/Users/me", '/') == Path"bar/z.nim"
+  doAssert relativePath(Path"", Path"/users/moo", '/') == Path""
+  doAssert relativePath(Path"foo", Path"", '/') == Path"foo"
+  doAssert relativePath(Path"/foo", Path"/Foo", '/') == (when FileSystemCaseSensitive: Path"../foo" else: Path".")
+  doAssert relativePath(Path"/Foo", Path"/foo", '/') == (when FileSystemCaseSensitive: Path"../Foo" else: Path".")
+  doAssert relativePath(Path"/foo", Path"/fOO", '/') == (when FileSystemCaseSensitive: Path"../foo" else: Path".")
+  doAssert relativePath(Path"/foO", Path"/foo", '/') == (when FileSystemCaseSensitive: Path"../foO" else: Path".")
+
+  doAssert relativePath(Path"foo", Path".", '/') == Path"foo"
+  doAssert relativePath(Path".", Path".", '/') == Path"."
+  doAssert relativePath(Path"..", Path".", '/') == Path".."
+
+  doAssert relativePath(Path"foo", Path"foo") == Path"."
+  doAssert relativePath(Path"", Path"foo") == Path""
+  doAssert relativePath(Path"././/foo", Path"foo//./") == Path"."
+
+  doAssert relativePath(getCurrentDir() / Path"bar", Path"foo") == Path"../bar".unixToNativePath
+  doAssert relativePath(Path"bar", getCurrentDir() / Path"foo") == Path"../bar".unixToNativePath
+
+  when doslikeFileSystem:
+    doAssert relativePath(r"c:\foo.nim".Path, r"C:\".Path) == r"foo.nim".Path
+    doAssert relativePath(r"c:\foo\bar\baz.nim".Path, r"c:\foo".Path) == r"bar\baz.nim".Path
+    doAssert relativePath(r"c:\foo\bar\baz.nim".Path, r"d:\foo".Path) == r"c:\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\foo\baz.nim".Path, r"\foo".Path) == r"baz.nim".Path
+    doAssert relativePath(r"\foo\bar\baz.nim".Path, r"\bar".Path) == r"..\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foo\bar".Path) == r"baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foO\bar".Path) == r"baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\bar\bar".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\foo\car".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\\goo\bar".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"c:\".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"\\foo\bar\baz.nim".Path, r"\foo".Path) == r"\\foo\bar\baz.nim".Path
+    doAssert relativePath(r"c:\foo.nim".Path, r"\foo".Path) == r"c:\foo.nim".Path
+
+  doAssert joinPath(Path"usr", Path"") == unixToNativePath(Path"usr")
+  doAssert joinPath(Path"usr", Path"") == (Path"usr").dup(add Path"")
+  doAssert joinPath(Path"", Path"lib") == Path"lib"
+  doAssert joinPath(Path"", Path"lib") == Path"".dup(add Path"lib")
+  doAssert joinPath(Path"", Path"/lib") == unixToNativePath(Path"/lib")
+  doAssert joinPath(Path"", Path"/lib") == unixToNativePath(Path"/lib")
+  doAssert joinPath(Path"usr/", Path"/lib") == Path"usr/".dup(add Path"/lib")
+  doAssert joinPath(Path"", Path"") == unixToNativePath(Path"") # issue #13455
+  doAssert joinPath(Path"", Path"") == Path"".dup(add Path"")
+  doAssert joinPath(Path"", Path"/") == unixToNativePath(Path"/")
+  doAssert joinPath(Path"", Path"/") == Path"".dup(add Path"/")
+  doAssert joinPath(Path"/", Path"/") == unixToNativePath(Path"/")
+  doAssert joinPath(Path"/", Path"/") == Path"/".dup(add Path"/")
+  doAssert joinPath(Path"/", Path"") == unixToNativePath(Path"/")
+  doAssert joinPath(Path"/" / Path"") == unixToNativePath(Path"/") # weird test case...
+  doAssert joinPath(Path"/", Path"/a/b/c") == unixToNativePath(Path"/a/b/c")
+  doAssert joinPath(Path"foo/", Path"") == unixToNativePath(Path"foo/")
+  doAssert joinPath(Path"foo/", Path"abc") == unixToNativePath(Path"foo/abc")
+  doAssert joinPath(Path"foo//./", Path"abc/.//") == unixToNativePath(Path"foo/abc/")
+  doAssert Path"foo//./".dup(add Path"abc/.//") == unixToNativePath(Path"foo/abc/")
+  doAssert joinPath(Path"foo", Path"abc") == unixToNativePath(Path"foo/abc")
+  doAssert Path"foo".dup(add Path"abc") == unixToNativePath(Path"foo/abc")
+  doAssert joinPath(Path"", Path"abc") == unixToNativePath(Path"abc")
+
+  doAssert joinPath(Path"zook/.", Path"abc") == unixToNativePath(Path"zook/abc")
+
+  # controversial: inconsistent with `joinPath("zook/.","abc")`
+  # on linux, `./foo` and `foo` are treated a bit differently for executables
+  # but not `./foo/bar` and `foo/bar`
+  doAssert joinPath(Path".", Path"/lib") == unixToNativePath(Path"./lib")
+  doAssert joinPath(Path".", Path"abc") == unixToNativePath(Path"./abc")
+
+  # cases related to issue #13455
+  doAssert joinPath(Path"foo", Path"", Path"") == Path"foo"
+  doAssert joinPath(Path"foo", Path"") == Path"foo"
+  doAssert joinPath(Path"foo/", Path"") == unixToNativePath(Path"foo/")
+  doAssert joinPath(Path"foo/", Path".") == Path"foo"
+  doAssert joinPath(Path"foo", Path"./") == unixToNativePath(Path"foo/")
+  doAssert joinPath(Path"foo", Path"", Path"bar/") == unixToNativePath(Path"foo/bar/")
+
+  # issue #13579
+  doAssert joinPath(Path"/foo", Path"../a") == unixToNativePath(Path"/a")
+  doAssert joinPath(Path"/foo/", Path"../a") == unixToNativePath(Path"/a")
+  doAssert joinPath(Path"/foo/.", Path"../a") == unixToNativePath(Path"/a")
+  doAssert joinPath(Path"/foo/.b", Path"../a") == unixToNativePath(Path"/foo/a")
+  doAssert joinPath(Path"/foo///", Path"..//a/") == unixToNativePath(Path"/a/")
+  doAssert joinPath(Path"foo/", Path"../a") == unixToNativePath(Path"a")
+
+  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
+
+
+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/tpegs.nim b/tests/stdlib/tpegs.nim
new file mode 100644
index 000000000..da3fc14b7
--- /dev/null
+++ b/tests/stdlib/tpegs.nim
@@ -0,0 +1,344 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+  output: '''
+PEG AST traversal output
+------------------------
+pkNonTerminal: Sum @(2, 3)
+  pkSequence: (Product (('+' / '-') Product)*)
+    pkNonTerminal: Product @(3, 7)
+      pkSequence: (Value (('*' / '/') Value)*)
+        pkNonTerminal: Value @(4, 5)
+          pkOrderedChoice: (([0-9] [0-9]*) / ('(' Expr ')'))
+            pkSequence: ([0-9] [0-9]*)
+              pkCharChoice: [0-9]
+              pkGreedyRepSet: [0-9]*
+            pkSequence: ('(' Expr ')')
+              pkChar: '('
+              pkNonTerminal: Expr @(1, 4)
+                pkNonTerminal: Sum @(2, 3)
+              pkChar: ')'
+        pkGreedyRep: (('*' / '/') Value)*
+          pkSequence: (('*' / '/') Value)
+            pkOrderedChoice: ('*' / '/')
+              pkChar: '*'
+              pkChar: '/'
+            pkNonTerminal: Value @(4, 5)
+    pkGreedyRep: (('+' / '-') Product)*
+      pkSequence: (('+' / '-') Product)
+        pkOrderedChoice: ('+' / '-')
+          pkChar: '+'
+          pkChar: '-'
+        pkNonTerminal: Product @(3, 7)
+
+Event parser output
+-------------------
+@[5.0]
++
+@[5.0, 3.0]
+@[8.0]
+
+/
+@[8.0, 2.0]
+@[4.0]
+
+-
+@[4.0, 7.0]
+-*
+@[4.0, 7.0, 22.0]
+@[4.0, 154.0]
+-
+@[-150.0]
+'''
+"""
+
+when defined(nimHasEffectsOf):
+  {.experimental: "strictEffects".}
+
+import std/[strutils, streams, pegs, assertions]
+
+const
+  indent = "  "
+
+let
+  pegAst = """
+Expr    <- Sum
+Sum     <- Product (('+' / '-')Product)*
+Product <- Value (('*' / '/')Value)*
+Value   <- [0-9]+ / '(' Expr ')'
+  """.peg
+  txt = "(5+3)/2-7*22"
+
+block:
+  var
+    outp = newStringStream()
+    processed: seq[string] = @[]
+
+  proc prt(outp: Stream, kind: PegKind, s: string; level: int = 0) =
+    outp.writeLine indent.repeat(level) & "$1: $2" % [$kind, s]
+
+  proc recLoop(p: Peg, level: int = 0) =
+    case p.kind
+    of pkEmpty..pkWhitespace:
+      discard
+    of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle:
+      outp.prt(p.kind, $p, level)
+    of pkChar, pkGreedyRepChar:
+      outp.prt(p.kind, $p, level)
+    of pkCharChoice, pkGreedyRepSet:
+      outp.prt(p.kind, $p, level)
+    of pkNonTerminal:
+      outp.prt(p.kind,
+        "$1 @($3, $4)" % [p.nt.name, $p.nt.rule.kind, $p.nt.line, $p.nt.col], level)
+      if not(p.nt.name in processed):
+        processed.add p.nt.name
+        p.nt.rule.recLoop level+1
+    of pkBackRef..pkBackRefIgnoreStyle:
+      outp.prt(p.kind, $p, level)
+    else:
+      outp.prt(p.kind, $p, level)
+      for s in items(p):
+        s.recLoop level+1
+
+  pegAst.recLoop
+  echo "PEG AST traversal output"
+  echo "------------------------"
+  echo outp.data
+
+block:
+  var
+    pStack {.threadvar.}: seq[string]
+    valStack {.threadvar.}: seq[float]
+    opStack {.threadvar.}: string
+  let
+    parseArithExpr = pegAst.eventParser:
+      pkNonTerminal:
+        enter:
+          pStack.add p.nt.name
+        leave:
+          pStack.setLen pStack.high
+          if length > 0:
+            let matchStr = s.substr(start, start+length-1)
+            case p.nt.name
+            of "Value":
+              try:
+                valStack.add matchStr.parseFloat
+                echo valStack
+              except ValueError:
+                discard
+            of "Sum", "Product":
+              try:
+                let val {.used.} = matchStr.parseFloat
+              except ValueError:
+                if valStack.len > 1 and opStack.len > 0:
+                  valStack[^2] = case opStack[^1]
+                  of '+': valStack[^2] + valStack[^1]
+                  of '-': valStack[^2] - valStack[^1]
+                  of '*': valStack[^2] * valStack[^1]
+                  else: valStack[^2] / valStack[^1]
+                  valStack.setLen valStack.high
+                  echo valStack
+                  opStack.setLen opStack.high
+                  echo opStack
+      pkChar:
+        leave:
+          if length == 1 and "Value" != pStack[^1]:
+            let matchChar = s[start]
+            opStack.add matchChar
+            echo opStack
+  echo "Event parser output"
+  echo "-------------------"
+  let pLen = parseArithExpr(txt)
+  doAssert txt.len == pLen
+
+
+import std/importutils
+
+block:
+  proc pegsTest() =
+    privateAccess(NonTerminal)
+    privateAccess(Captures)
+
+    if "test" =~ peg"s <- {{\ident}}": # bug #19104
+      doAssert matches[0] == "test"
+      doAssert matches[1] == "test", $matches[1]
+
+    doAssert escapePeg("abc''def'") == r"'abc'\x27\x27'def'\x27"
+    doAssert match("(a b c)", peg"'(' @ ')'")
+    doAssert match("W_HI_Le", peg"\y 'while'")
+    doAssert(not match("W_HI_L", peg"\y 'while'"))
+    doAssert(not match("W_HI_Le", peg"\y v'while'"))
+    doAssert match("W_HI_Le", peg"y'while'")
+
+    doAssert($ +digits == $peg"\d+")
+    doAssert "0158787".match(peg"\d+")
+    doAssert "ABC 0232".match(peg"\w+\s+\d+")
+    doAssert "ABC".match(peg"\d+ / \w+")
+
+    var accum: seq[string] = @[]
+    for word in split("00232this02939is39an22example111", peg"\d+"):
+      accum.add(word)
+    doAssert(accum == @["this", "is", "an", "example"])
+
+    doAssert matchLen("key", ident) == 3
+
+    var pattern = sequence(ident, *whitespace, term('='), *whitespace, ident)
+    doAssert matchLen("key1=  cal9", pattern) == 11
+
+    var ws = newNonTerminal("ws", 1, 1)
+    ws.rule = *whitespace
+
+    var expr = newNonTerminal("expr", 1, 1)
+    expr.rule = sequence(capture(ident), *sequence(
+                  nonterminal(ws), term('+'), nonterminal(ws), nonterminal(expr)))
+
+    var c: Captures
+    var s = "a+b +  c +d+e+f"
+    doAssert rawMatch(s, expr.rule, 0, c) == len(s)
+    var a = ""
+    for i in 0..c.ml-1:
+      a.add(substr(s, c.matches[i][0], c.matches[i][1]))
+    doAssert a == "abcdef"
+    #echo expr.rule
+
+    #const filename = "lib/devel/peg/grammar.txt"
+    #var grammar = parsePeg(newFileStream(filename, fmRead), filename)
+    #echo "a <- [abc]*?".match(grammar)
+    doAssert find("_____abc_______", term("abc"), 2) == 5
+    doAssert match("_______ana", peg"A <- 'ana' / . A")
+    doAssert match("abcs%%%", peg"A <- ..A / .A / '%'")
+
+    var matches: array[0..MaxSubpatterns-1, string]
+    if "abc" =~ peg"{'a'}'bc' 'xyz' / {\ident}":
+      doAssert matches[0] == "abc"
+    else:
+      doAssert false
+
+    var g2 = peg"""S <- A B / C D
+                   A <- 'a'+
+                   B <- 'b'+
+                   C <- 'c'+
+                   D <- 'd'+
+                """
+    doAssert($g2 == "((A B) / (C D))")
+    doAssert match("cccccdddddd", g2)
+    doAssert("var1=key; var2=key2".replacef(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+           "var1<-keykey; var2<-key2key2")
+    doAssert("var1=key; var2=key2".replace(peg"{\ident}'='{\ident}", "$1<-$2$2") ==
+           "$1<-$2$2; $1<-$2$2")
+    doAssert "var1=key; var2=key2".endsWith(peg"{\ident}'='{\ident}")
+
+    if "aaaaaa" =~ peg"'aa' !. / ({'a'})+":
+      doAssert matches[0] == "a"
+    else:
+      doAssert false
+
+    if match("abcdefg", peg"c {d} ef {g}", matches, 2):
+      doAssert matches[0] == "d"
+      doAssert matches[1] == "g"
+    else:
+      doAssert false
+
+    accum = @[]
+    for x in findAll("abcdef", peg".", 3):
+      accum.add(x)
+    doAssert(accum == @["d", "e", "f"])
+
+    for x in findAll("abcdef", peg"^{.}", 3):
+      doAssert x == "d"
+
+    if "f(a, b)" =~ peg"{[0-9]+} / ({\ident} '(' {@} ')')":
+      doAssert matches[0] == "f"
+      doAssert matches[1] == "a, b"
+    else:
+      doAssert false
+
+    doAssert match("eine übersicht und außerdem", peg"(\letter \white*)+")
+    # ß is not a lower cased letter?!
+    doAssert match("eine übersicht und auerdem", peg"(\lower \white*)+")
+    doAssert match("EINE ÜBERSICHT UND AUSSERDEM", peg"(\upper \white*)+")
+    doAssert(not match("456678", peg"(\letter)+"))
+
+    doAssert("var1 = key; var2 = key2".replacef(
+      peg"\skip(\s*) {\ident}'='{\ident}", "$1<-$2$2") ==
+           "var1<-keykey;var2<-key2key2")
+
+    doAssert match("prefix/start", peg"^start$", 7)
+
+    if "foo" =~ peg"{'a'}?.*":
+      doAssert matches[0].len == 0
+    else: doAssert false
+
+    if "foo" =~ peg"{''}.*":
+      doAssert matches[0] == ""
+    else: doAssert false
+
+    if "foo" =~ peg"{'foo'}":
+      doAssert matches[0] == "foo"
+    else: doAssert false
+
+    let empty_test = peg"^\d*"
+    let str = "XYZ"
+
+    doAssert(str.find(empty_test) == 0)
+    doAssert(str.match(empty_test))
+
+    proc handleMatches(m: int, n: int, c: openArray[string]): string =
+      result = ""
+
+      if m > 0:
+        result.add ", "
+
+      result.add case n:
+        of 2: toLowerAscii(c[0]) & ": '" & c[1] & "'"
+        of 1: toLowerAscii(c[0]) & ": ''"
+        else: ""
+
+    doAssert("Var1=key1;var2=Key2;   VAR3".
+      replace(peg"{\ident}('='{\ident})* ';'* \s*",
+      handleMatches) == "var1: 'key1', var2: 'Key2', var3: ''")
+
+
+    doAssert "test1".match(peg"""{@}$""")
+    doAssert "test2".match(peg"""{(!$ .)*} $""")
+
+    doAssert "abbb".match(peg"{a} {b} $2 $^1")
+    doAssert "abBA".match(peg"{a} {b} i$2 i$^2")
+
+    doAssert "abba".match(peg"{a} {b} $^1 {} $^1")
+
+    block:
+      let grammar = peg"""
+program <- {''} stmt* $
+stmt <- call / block
+call <- 'call()' EOL
+EOL <- \n / $
+block <- 'block:' \n indBody
+indBody <- {$^1 ' '+} stmt ($^1 stmt)* {}
+"""
+      let program = """
+call()
+block:
+  block:
+    call()
+    call()
+  call()
+call()
+"""
+      var c: Captures
+      doAssert program.len == program.rawMatch(grammar, 0, c)
+      doAssert c.ml == 1
+
+    block:
+      # bug #21632
+
+      let p = peg"""
+        atext <- \w / \d
+      """
+
+      doAssert "a".match(p)
+      doAssert "1".match(p)
+
+  pegsTest()
+  static:
+    pegsTest()
diff --git a/tests/stdlib/tposix.nim b/tests/stdlib/tposix.nim
new file mode 100644
index 000000000..060482229
--- /dev/null
+++ b/tests/stdlib/tposix.nim
@@ -0,0 +1,88 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  disabled: windows
+"""
+
+# Test Posix interface
+
+when not defined(windows):
+
+  import posix
+  import std/[assertions, syncio]
+
+  var
+    u: Utsname
+
+  discard uname(u)
+
+  writeLine(stdout, u.sysname)
+  writeLine(stdout, u.nodename)
+  writeLine(stdout, u.release)
+  writeLine(stdout, u.machine)
+
+  when not (defined(nintendoswitch) or defined(macos) or defined(macosx)):
+    block:
+      type Message = object
+        value: int
+
+      const MQ_PATH: cstring = "/top_level_file"
+      const MQ_PRIORITY: cuint = 170
+      const MQ_MESSAGE_SIZE: csize_t = csize_t(sizeof(Message))
+
+      let mqd_a: posix.MqAttr = MqAttr(mq_maxmsg: 10, mq_msgsize: clong(MQ_MESSAGE_SIZE))
+      let writable: posix.Mqd = posix.mq_open(
+        MQ_PATH,
+        posix.O_CREAT or posix.O_WRONLY or posix.O_NONBLOCK,
+        posix.S_IRWXU,
+        addr(mqd_a)
+      )
+      let readable: posix.Mqd = posix.mq_open(
+        MQ_PATH,
+        posix.O_RDONLY or posix.O_NONBLOCK,
+        posix.S_IRWXU,
+        addr(mqd_a)
+      )
+
+      let sent: Message = Message(value: 88)
+      block:
+        let success: int = writable.mq_send(
+          cast[cstring](sent.addr),
+          MQ_MESSAGE_SIZE,
+          MQ_PRIORITY
+        )
+        doAssert success == 0, $success
+
+      block:
+        var buffer: Message
+        var priority: cuint
+        let bytesRead: int = readable.mq_receive(
+          cast[cstring](buffer.addr),
+          MQ_MESSAGE_SIZE,
+          priority
+        )
+        doAssert buffer == sent
+        doAssert bytesRead == int(MQ_MESSAGE_SIZE)
+
+  block:
+    var rl: RLimit
+    var res = getrlimit(RLIMIT_STACK, rl)
+    doAssert res == 0
+
+    # save old value
+    let oldrlim = rl.rlim_cur
+
+    # set new value
+    rl.rlim_cur = rl.rlim_max - 1
+    res = setrlimit(RLIMIT_STACK, rl)
+    doAssert res == 0
+
+    # get new value
+    var rl1: RLimit
+    res = getrlimit(RLIMIT_STACK, rl1)
+    doAssert res == 0
+    doAssert rl1.rlim_cur == rl.rlim_max - 1
+
+    # restore old value
+    rl.rlim_cur = oldrlim
+    res = setrlimit(RLIMIT_STACK, rl)
+    doAssert res == 0
diff --git a/tests/stdlib/tprelude.nim b/tests/stdlib/tprelude.nim
new file mode 100644
index 000000000..47f46b511
--- /dev/null
+++ b/tests/stdlib/tprelude.nim
@@ -0,0 +1,16 @@
+discard """
+  targets: "c js"
+  matrix: "; -d:nimTestTpreludeCase1"
+"""
+
+when defined nimTestTpreludeCase1:
+  include std/prelude
+else:
+  include prelude
+
+import std/assertions
+
+template main() =
+  doAssert toSeq(1..3) == @[1,2,3]
+static: main()
+main()
diff --git a/tests/stdlib/trandom.nim b/tests/stdlib/trandom.nim
new file mode 100644
index 000000000..eb32f7757
--- /dev/null
+++ b/tests/stdlib/trandom.nim
@@ -0,0 +1,310 @@
+discard """
+  joinable: false # to avoid messing with global rand state
+  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]
+import std/private/jsutils
+when not defined(js):
+  import std/os
+
+randomize(233)
+
+proc main() =
+  var occur: array[1000, int]
+
+  for i in 0..100_000:
+    let x = rand(high(occur))
+    inc occur[x]
+
+  doAssert max(occur) <= 140 and min(occur) >= 60 # gives some slack
+
+  var a = [0, 1]
+  shuffle(a)
+  doAssert a in [[0,1], [1,0]]
+
+  doAssert rand(0) == 0
+  when not defined(nimscript):
+    doAssert sample("a") == 'a'
+
+  when compileOption("rangeChecks") and not defined(nimscript):
+    doAssertRaises(RangeDefect):
+      discard rand(-1)
+
+    doAssertRaises(RangeDefect):
+      discard rand(-1.0)
+
+  # don't use causes integer overflow
+  doAssert compiles(rand[int](low(int) .. high(int)))
+
+main()
+
+block:
+  when not defined(js):
+    doAssert almostEqual(rand(12.5), 7.355175342026979)
+    doAssert almostEqual(rand(2233.3322), 499.342386778917)
+
+  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
+
+var rs: RunningStat
+for j in 1..5:
+  for i in 1 .. 100_000:
+    rs.push(gauss())
+  doAssert abs(rs.mean-0) < 0.08, $rs.mean
+  doAssert abs(rs.standardDeviation()-1.0) < 0.1
+  let bounds = [3.5, 5.0]
+  for a in [rs.max, -rs.min]:
+    doAssert a >= bounds[0] and a <= bounds[1]
+  rs.clear()
+
+block:
+  type DiceRoll = range[3..6]
+  var flag = false
+  for i in 0..<100:
+    if rand(5.DiceRoll) < 3:
+      flag = true
+  doAssert flag # because of: rand(max: int): int
+
+
+block: # random int
+  block: # there might be some randomness
+    var set = initHashSet[int](128)
+
+    for i in 1..1000:
+      incl(set, rand(high(int)))
+    doAssert len(set) == 1000
+
+  block: # single number bounds work
+    var rand: int
+    for i in 1..1000:
+      rand = rand(1000)
+      doAssert rand <= 1000
+      doAssert rand >= 0
+
+  block: # slice bounds work
+    var rand: int
+    for i in 1..1000:
+      rand = rand(100..1000)
+      doAssert rand <= 1000
+      doAssert rand >= 100
+
+  block: # again gives new numbers
+    var rand1 = rand(1000000)
+    when not (defined(js) or defined(nimscript)):
+      os.sleep(200)
+
+    var rand2 = rand(1000000)
+    doAssert rand1 != rand2
+
+block: # random float
+  block: # there might be some randomness
+    var set = initHashSet[float](128)
+
+    for i in 1..100:
+      incl(set, rand(1.0))
+    doAssert len(set) == 100
+
+  block: # single number bounds work
+    var rand: float
+    for i in 1..1000:
+      rand = rand(1000.0)
+      doAssert rand <= 1000.0
+      doAssert rand >= 0.0
+
+  block: # slice bounds work
+    var rand: float
+    for i in 1..1000:
+      rand = rand(100.0..1000.0)
+      doAssert rand <= 1000.0
+      doAssert rand >= 100.0
+
+  block: # again gives new numbers
+    var rand1: float = rand(1000000.0)
+    when not (defined(js) or defined(nimscript)):
+      os.sleep(200)
+
+    var rand2: float = rand(1000000.0)
+    doAssert rand1 != rand2
+
+block: # random sample
+  block: # "non-uniform array sample unnormalized int CDF
+    let values = [10, 20, 30, 40, 50] # values
+    let counts = [4, 3, 2, 1, 0]      # weights aka unnormalized probabilities
+    var histo = initCountTable[int]()
+    let cdf = counts.cumsummed        # unnormalized CDF
+    for i in 0 ..< 5000:
+      histo.inc(sample(values, cdf))
+    doAssert histo.len == 4              # number of non-zero in `counts`
+    # Any one bin is a binomial random var for n samples, each with prob p of
+    # adding a count to k; E[k]=p*n, Var k=p*(1-p)*n, approximately Normal for
+    # big n.  So, P(abs(k - p*n)/sqrt(p*(1-p)*n))>3.0) =~ 0.0027, while
+    # P(wholeTestFails) =~ 1 - P(binPasses)^4 =~ 1 - (1-0.0027)^4 =~ 0.01.
+    for i, c in counts:
+      if c == 0:
+        doAssert values[i] notin histo
+        continue
+      let p = float(c) / float(cdf[^1])
+      let n = 5000.0
+      let expected = p * n
+      let stdDev = sqrt(n * p * (1.0 - p))
+      doAssert abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev
+
+  block: # non-uniform array sample normalized float CDF
+    let values = [10, 20, 30, 40, 50]     # values
+    let counts = [0.4, 0.3, 0.2, 0.1, 0]  # probabilities
+    var histo = initCountTable[int]()
+    let cdf = counts.cumsummed            # normalized CDF
+    for i in 0 ..< 5000:
+      histo.inc(sample(values, cdf))
+    doAssert histo.len == 4                  # number of non-zero in ``counts``
+    for i, c in counts:
+      if c == 0:
+        doAssert values[i] notin histo
+        continue
+      let p = float(c) / float(cdf[^1])
+      let n = 5000.0
+      let expected = p * n
+      let stdDev = sqrt(n * p * (1.0 - p))
+      # NOTE: like unnormalized int CDF test, P(wholeTestFails) =~ 0.01.
+      doAssert abs(float(histo[values[i]]) - expected) <= 3.0 * stdDev
+
+block:
+  # 0 is a valid seed
+  var r = initRand(0)
+  doAssert r.rand(1.0) != r.rand(1.0)
+  r = initRand(10)
+  doAssert r.rand(1.0) != r.rand(1.0)
+  # changing the seed changes the sequence
+  var r1 = initRand(123)
+  var r2 = initRand(124)
+  doAssert r1.rand(1.0) != r2.rand(1.0)
+
+block: # bug #17467
+  let n = 1000
+  for i in -n .. n:
+    var r = initRand(i)
+    let x = r.rand(1.0)
+    doAssert x > 1e-4, $(x, i)
+      # This used to fail for each i in 0..<26844, i.e. the 1st produced value
+      # was predictable and < 1e-4, skewing distributions.
+
+block: # bug #16360, Natural overload
+  var r = initRand()
+  template test(a) =
+    let a2 = a
+    block:
+      let a3 = r.rand(a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+    block:
+      let a3 = rand(a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+  test int.high
+  test int.high - 1
+  test int.high - 2
+  test 0
+
+block: # same as above but use slice overload
+  var r = initRand()
+  template test[T](a: T) =
+    let a2: T = a
+    block:
+      let a3 = r.rand(T(0) .. a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+    block:
+      let a3 = rand(T(0) .. a2)
+      doAssert a3 <= a2
+      doAssert a3.type is a2.type
+  test cast[uint](int.high)
+  test cast[uint](int.high) + 1
+  whenJsNoBigInt64: discard
+  do:
+    test uint64.high
+    test uint64.high - 1
+  test uint.high - 2
+  test uint.high - 1
+  test uint.high
+  test int.high
+  test int.high - 1
+  test int.high - 2
+  test 0
+  test 0'u
+  test 0'u64
+
+block: # bug #16296
+  var r = initRand()
+  template test(x) =
+    let a2 = x
+    let a3 = r.rand(a2)
+    doAssert a3 <= a2.b
+    doAssert a3 >= a2.a
+    doAssert a3.type is a2.a.type
+  test(-2 .. int.high-1)
+  test(int.low .. int.high)
+  test(int.low+1 .. int.high)
+  test(int.low .. int.high-1)
+  test(int.low .. 0)
+  test(int.low .. -1)
+  test(int.low .. 1)
+  test(int64.low .. 1'i64)
+  test(10'u64 .. uint64.high)
+
+block: # bug #17670
+  type UInt48 = range[0'u64..2'u64^48-1]
+  let x = rand(UInt48)
+  doAssert x is UInt48
+
+block: # bug #17898
+  # Checks whether `initRand()` generates unique states.
+  # size should be 2^64, but we don't have time and space.
+
+  # Disable this test for js until js gets proper skipRandomNumbers.
+  when not defined(js):
+    const size = 1000
+    var
+      rands: array[size, Rand]
+      randSet: HashSet[Rand]
+    for i in 0..<size:
+      rands[i] = initRand()
+      randSet.incl rands[i]
+
+    doAssert randSet.len == size
+
+    # Checks random number sequences overlapping.
+    const numRepeat = 100
+    for i in 0..<size:
+      for j in 0..<numRepeat:
+        discard rands[i].next
+        doAssert rands[i] notin randSet
+
+block: # bug #22360
+  const size = 1000
+  var fc = 0
+  var tc = 0
+
+  for _ in 1..size:
+    let s = rand(bool)
+
+    if s:
+      inc tc
+    else:
+      inc 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/trat_float.nim b/tests/stdlib/trat_float.nim
new file mode 100644
index 000000000..663973bf9
--- /dev/null
+++ b/tests/stdlib/trat_float.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: '''type mismatch: got'''
+  file: "trat_float.nim"
+  line: "9,19"
+"""
+import rationals
+var
+  # this fails - no floats as num or den
+  r = initRational(1.0'f, 1.0'f)
diff --git a/tests/stdlib/trat_init.nim b/tests/stdlib/trat_init.nim
new file mode 100644
index 000000000..2be0c0099
--- /dev/null
+++ b/tests/stdlib/trat_init.nim
@@ -0,0 +1,14 @@
+discard """
+  output: '''true'''
+"""
+import rationals
+var
+  z = Rational[int](num: 0, den: 1)
+  o = initRational(num=1, den=1)
+  a = initRational(1, 2)
+
+try:
+  var
+    r = initRational(1, 0)  # this fails - no zero denominator
+except AssertionDefect:
+  echo "true"
diff --git a/tests/stdlib/trationals.nim b/tests/stdlib/trationals.nim
new file mode 100644
index 000000000..22d7f5c2d
--- /dev/null
+++ b/tests/stdlib/trationals.nim
@@ -0,0 +1,117 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[rationals, math]
+import std/assertions
+
+template main() =
+  var
+    z = Rational[int](num: 0, den: 1)
+    o = initRational(num = 1, den = 1)
+    a = initRational(1, 2)
+    u = 3u // 2
+    b = -1 // -2
+    m1 = -1 // 1
+    tt = 10 // 2
+
+  doAssert a == a
+  doAssert a - a == z
+  doAssert a + b == o
+  doAssert a / b == o
+  doAssert a * b == 1 // 4
+  doAssert 3 / a == 6 // 1
+  doAssert a / 3 == 1 // 6
+  doAssert tt * z == z
+  doAssert 10 * a == tt
+  doAssert a * 10 == tt
+  doAssert tt / 10 == a
+  doAssert a - m1 == 3 // 2
+  doAssert a + m1 == -1 // 2
+  doAssert m1 + tt == 16 // 4
+  doAssert m1 - tt == 6 // -1
+
+  doAssert z < o
+  doAssert z <= o
+  doAssert z == z
+  doAssert cmp(z, o) < 0
+  doAssert cmp(o, z) > 0
+
+  doAssert o == o
+  doAssert o >= o
+  doAssert not(o > o)
+  doAssert cmp(o, o) == 0
+  doAssert cmp(z, z) == 0
+  doAssert hash(o) == hash(o)
+
+  doAssert a == b
+  doAssert a >= b
+  doAssert not(b > a)
+  doAssert cmp(a, b) == 0
+  doAssert hash(a) == hash(b)
+
+  var x = 1 // 3
+
+  x *= 5 // 1
+  doAssert x == 5 // 3
+  x += 2 // 9
+  doAssert x == 17 // 9
+  x -= 9 // 18
+  doAssert x == 25 // 18
+  x /= 1 // 2
+  doAssert x == 50 // 18
+
+  var y = 1 // 3
+
+  y *= 4
+  doAssert y == 4 // 3
+  y += 5
+  doAssert y == 19 // 3
+  y -= 2
+  doAssert y == 13 // 3
+  y /= 9
+  doAssert y == 13 // 27
+
+  doAssert toRational(5) == 5 // 1
+  doAssert abs(toFloat(y) - 0.4814814814814815) < 1.0e-7
+  doAssert toInt(z) == 0
+
+  when sizeof(int) == 8:
+    doAssert toRational(0.98765432) == 2111111029 // 2137499919
+    doAssert toRational(PI) == 817696623 // 260280919
+  when sizeof(int) == 4:
+    doAssert toRational(0.98765432) == 80 // 81
+    doAssert toRational(PI) == 355 // 113
+
+  doAssert toRational(0.1) == 1 // 10
+  doAssert toRational(0.9) == 9 // 10
+
+  doAssert toRational(0.0) == 0 // 1
+  doAssert toRational(-0.25) == 1 // -4
+  doAssert toRational(3.2) == 16 // 5
+  doAssert toRational(0.33) == 33 // 100
+  doAssert toRational(0.22) == 11 // 50
+  doAssert toRational(10.0) == 10 // 1
+
+  doAssert (1 // 1) div (3 // 10) == 3
+  doAssert (-1 // 1) div (3 // 10) == -3
+  doAssert (3 // 10) mod (1 // 1) == 3 // 10
+  doAssert (-3 // 10) mod (1 // 1) == -3 // 10
+  doAssert floorDiv(1 // 1, 3 // 10) == 3
+  doAssert floorDiv(-1 // 1, 3 // 10) == -4
+  doAssert floorMod(3 // 10, 1 // 1) == 3 // 10
+  doAssert floorMod(-3 // 10, 1 // 1) == 7 // 10
+
+  when sizeof(int) == 8:
+    doAssert almostEqual(PI.toRational.toFloat, PI)
+
+  # unsigned
+  doAssert u == u
+  doAssert u + u == 3u // 1
+  doAssert 3u.toRational - u == u
+  doAssert u * 2 == 3u // 1
+
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tre.nim b/tests/stdlib/tre.nim
new file mode 100644
index 000000000..39637434d
--- /dev/null
+++ b/tests/stdlib/tre.nim
@@ -0,0 +1,122 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/re
+import std/assertions
+
+proc testAll() =
+  doAssert match("(a b c)", rex"\( .* \)")
+  doAssert match("WHiLe", re("while", {reIgnoreCase}))
+
+  doAssert "0158787".match(re"\d+")
+  doAssert "ABC 0232".match(re"\w+\s+\d+")
+  doAssert "ABC".match(rex"\d+ | \w+")
+
+  {.push warnings:off.}
+  doAssert matchLen("key", re"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b") == 3
+  {.pop.}
+
+  var pattern = re"[a-z0-9]+\s*=\s*[a-z0-9]+"
+  doAssert matchLen("key1=  cal9", pattern) == 11
+
+  doAssert find("_____abc_______", re"abc") == 5
+  doAssert findBounds("_____abc_______", re"abc") == (5,7)
+
+  var matches: array[6, string]
+  if match("abcdefg", re"c(d)ef(g)", matches, 2):
+    doAssert matches[0] == "d"
+    doAssert matches[1] == "g"
+  else:
+    doAssert false
+
+  if "abc" =~ re"(a)bcxyz|(\w+)":
+    doAssert matches[1] == "abc"
+  else:
+    doAssert false
+
+  if "abc" =~ re"(cba)?.*":
+    doAssert matches[0] == ""
+  else: doAssert false
+
+  if "abc" =~ re"().*":
+    doAssert matches[0] == ""
+  else: doAssert false
+
+  doAssert "var1=key; var2=key2".endsWith(re"\w+=\w+")
+  doAssert("var1=key; var2=key2".replacef(re"(\w+)=(\w+)", "$1<-$2$2") ==
+         "var1<-keykey; var2<-key2key2")
+  doAssert("var1=key; var2=key2".replace(re"(\w+)=(\w+)", "$1<-$2$2") ==
+         "$1<-$2$2; $1<-$2$2")
+
+  var accum: seq[string] = @[]
+  for word in split("00232this02939is39an22example111", re"\d+"):
+    accum.add(word)
+  doAssert(accum == @["", "this", "is", "an", "example", ""])
+
+  accum = @[]
+  for word in split("00232this02939is39an22example111", re"\d+", maxsplit=2):
+    accum.add(word)
+  doAssert(accum == @["", "this", "is39an22example111"])
+
+  accum = @[]
+  for word in split("AAA :   : BBB", re"\s*:\s*"):
+    accum.add(word)
+  doAssert(accum == @["AAA", "", "BBB"])
+
+  doAssert(split("abc", re"") == @["a", "b", "c"])
+  doAssert(split("", re"") == @[])
+
+  doAssert(split("a;b;c", re";") == @["a", "b", "c"])
+  doAssert(split(";a;b;c", re";") == @["", "a", "b", "c"])
+  doAssert(split(";a;b;c;", re";") == @["", "a", "b", "c", ""])
+  doAssert(split("a;b;c;", re";") == @["a", "b", "c", ""])
+  doAssert(split("00232this02939is39an22example111", re"\d+", maxsplit=2) == @["", "this", "is39an22example111"])
+
+
+  for x in findAll("abcdef", re"^{.}", 3):
+    doAssert x == "d"
+  accum = @[]
+  for x in findAll("abcdef", re".", 3):
+    accum.add(x)
+  doAssert(accum == @["d", "e", "f"])
+
+  doAssert("XYZ".find(re"^\d*") == 0)
+  doAssert("XYZ".match(re"^\d*") == true)
+
+  block:
+    var matches: array[16, string]
+    if match("abcdefghijklmnop", re"(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)", matches):
+      for i in 0..matches.high:
+        doAssert matches[i] == $chr(i + 'a'.ord)
+    else:
+      doAssert false
+
+  block:   # Buffer based RE
+    var cs: cstring = "_____abc_______"
+    doAssert(cs.find(re"abc", bufSize=15) == 5)
+    doAssert(cs.matchLen(re"_*abc", bufSize=15) == 8)
+    doAssert(cs.matchLen(re"abc", start=5, bufSize=15) == 3)
+    doAssert(cs.matchLen(re"abc", start=5, bufSize=7) == -1)
+    doAssert(cs.matchLen(re"abc_*", start=5, bufSize=10) == 5)
+    var accum: seq[string] = @[]
+    for x in cs.findAll(re"[a-z]", start=3, bufSize=15):
+      accum.add($x)
+    doAssert(accum == @["a","b","c"])
+
+  block: # bug #9306
+    doAssert replace("bar", re"^", "foo") == "foobar"
+    doAssert replace("foo", re"$", "bar") == "foobar"
+
+
+  block: # bug #9437
+    doAssert replace("foo", re"", "-") == "-f-o-o-"
+    doAssert replace("ooo", re"o", "-") == "---"
+
+  block: # bug #14468
+    accum = @[]
+    for word in split("this is an example", re"\b"):
+      accum.add(word)
+    doAssert(accum == @["this", " ", "is", " ", "an", " ", "example"])
+
+testAll()
diff --git a/tests/stdlib/treadln.nim b/tests/stdlib/treadln.nim
new file mode 100644
index 000000000..4a070e848
--- /dev/null
+++ b/tests/stdlib/treadln.nim
@@ -0,0 +1,23 @@
+
+discard """
+output: '''
+test the improved readline handling that does not care whether its
+Macintosh, Unix or Windows text format.
+'''
+"""
+
+import std/syncio
+
+# test the improved readline handling that does not care whether its
+# Macintosh, Unix or Windows text format.
+
+var
+  inp: File
+  line: string
+
+if open(inp, "tests/stdlib/treadln.nim"):
+  while not endOfFile(inp):
+    line = readLine(inp)
+    if line.len >= 2 and line[0] == '#' and line[1] == ' ':
+      echo line[2..^1]
+  close(inp)
diff --git a/tests/stdlib/tregex.nim b/tests/stdlib/tregex.nim
new file mode 100644
index 000000000..9dd66cd60
--- /dev/null
+++ b/tests/stdlib/tregex.nim
@@ -0,0 +1,29 @@
+discard """
+  output: "key: keyAYes!"
+  matrix: "--mm:refc; --mm:orc"
+"""
+# Test the new regular expression module
+# which is based on the PCRE library
+
+when defined(powerpc64):
+  # cheat as our powerpc test machine has no PCRE installed:
+  echo "key: keyAYes!"
+
+else:
+  import
+    re
+  import std/syncio
+  if "keyA = valueA" =~ re"\s*(\w+)\s*\=\s*(\w+)":
+    write(stdout, "key: ", matches[0])
+  elif "# comment!" =~ re.re"\s*(\#.*)":
+    # test re.re"" syntax
+    echo("comment: ", matches[0])
+  else:
+    echo("Bug!")
+
+  if "Username".match(re"[A-Za-z]+"):
+    echo("Yes!")
+  else:
+    echo("Bug!")
+
+  #OUT key: keyAYes!
diff --git a/tests/stdlib/tregistry.nim b/tests/stdlib/tregistry.nim
new file mode 100644
index 000000000..25aed8df8
--- /dev/null
+++ b/tests/stdlib/tregistry.nim
@@ -0,0 +1,16 @@
+discard """
+  disabled: "unix"
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+when defined(windows):
+  import std/registry
+  import std/assertions
+
+  block: # bug #14010
+    let path = "Environment"
+    let key = "D20210328T202842_key"
+    let val = "D20210328T202842_val"
+    let handle = HKEY_CURRENT_USER
+    setUnicodeValue("Environment", key, val, handle)
+    doAssert getUnicodeValue(path, key, handle) == val
diff --git a/tests/stdlib/trepr.nim b/tests/stdlib/trepr.nim
new file mode 100644
index 000000000..3956b98f9
--- /dev/null
+++ b/tests/stdlib/trepr.nim
@@ -0,0 +1,328 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--mm:refc;--mm:arc"
+"""
+
+# if excessive, could remove 'cpp' from targets
+
+from strutils import endsWith, contains, strip
+from std/macros import newLit
+import std/assertions
+
+macro deb(a): string = newLit a.repr.strip
+macro debTyped(a: typed): string = newLit a.repr.strip
+
+template main() =
+  doAssert repr({3,5}) == "{3, 5}"
+
+  block:
+    type TEnum = enum a, b
+    var val = {a, b}
+    when nimvm:
+      discard
+      #[
+      # BUG:
+      {0, 1}
+      {97..99, 65..67}
+      ]#
+    else:
+      doAssert repr(val) == "{a, b}"
+      doAssert repr({'a'..'c', 'A'..'C'}) == "{'A', 'B', 'C', 'a', 'b', 'c'}"
+
+    type
+      TObj {.pure, inheritable.} = object
+        data: int
+      TFoo = ref object of TObj
+        d2: float
+    var foo: TFoo
+    new(foo)
+
+  #[
+  BUG:
+  --gc:arc returns `"abc"`
+  regular gc returns with address, e.g. 0x1068aae60"abc", but only
+  for c,cpp backends (not js, vm)
+  ]#
+  block:
+    doAssert repr("abc").endsWith "\"abc\""
+    var b: cstring = "def"
+    doAssert repr(b).endsWith "\"def\""
+
+  block:
+    var c = @[1,2]
+    when nimvm:
+      discard # BUG: this shows [1, 2] instead of @[1, 2]
+    else:
+      # BUG (already mentioned above): some backends / gc show address, others don't
+      doAssert repr(c).endsWith "@[1, 2]"
+
+    let d = @["foo", "bar"]
+    let s = repr(d)
+    # depending on backend/gc, we get 0x106a1c350@[0x106a1c390"foo", 0x106a1c3c0"bar"]
+    doAssert "\"foo\"," in s
+
+  var arr = [1, 2, 3]
+  doAssert repr(arr) == "[1, 2, 3]"
+
+  block: # bug #7878
+    proc reprOpenarray(variable: var openArray[int]): string = repr(variable)
+    when defined(js): discard # BUG: doesn't work
+    else:
+      doAssert reprOpenarray(arr) == "[1, 2, 3]"
+
+  block: # bug #17292 repr with `do`
+    template foo(a, b, c, d) = discard
+    block:
+      let a = deb:
+        foo(1, 2, 3, 4)
+      doAssert a == "foo(1, 2, 3, 4)"
+    block:
+      let a = deb:
+        foo(1, 2, 3): 4
+      doAssert a == """
+foo(1, 2, 3):
+  4"""
+
+    block:
+      let a = deb:
+        foo(1, 2): 3
+        do: 4
+      doAssert a == """
+foo(1, 2):
+  3
+do:
+  4"""
+
+    block:
+      let a = deb:
+        foo(1): 3
+        do: 3
+        do: 4
+      doAssert a == """
+foo(1):
+  3
+do:
+  3
+do:
+  4"""
+
+    block:
+      let a = deb:
+        foo(1):
+          3
+        do:
+          discard
+          3
+        do:
+          discard
+          4
+
+      doAssert a == """
+foo(1):
+  3
+do:
+  discard
+  3
+do:
+  discard
+  4"""
+
+    block:
+      let a = deb:
+        foo: 1
+        do: 2
+        do: 3
+        do: 4
+      doAssert a == """
+foo:
+  1
+do:
+  2
+do:
+  3
+do:
+  4"""
+
+  block: # bug #17292 repr with `(discard)` (`discard` would result in illegal code)
+    let a = deb:
+      let f {.inject.} = () => (discard)
+    doAssert a == """
+let f {.inject.} = () =>
+    (discard )"""
+
+    let a2 = deb:
+      block:
+        discard
+      discard
+
+      block:
+        when true: discard
+
+      # let a = b => discard # illegal
+      discard b => (discard) # legal
+
+      block:
+        return
+    doAssert a2 == """
+block:
+  discard
+discard
+block:
+  when true:
+    discard
+discard b =>
+    (discard )
+block:
+  return"""
+
+  block: # bug #17292 (bug 4)
+    let a = deb:
+      proc `=destroy`() = discard
+      proc `'foo`(): int = discard
+      proc `foo bar baz`(): int = discard
+    let a2 = """
+proc `=destroy`() =
+  discard
+
+proc `'foo`(): int =
+  discard
+
+proc `foo bar baz`(): int =
+  discard"""
+    doAssert a2 == a
+
+  block: # setters: `foo=`
+    let a = deb:
+      proc `foo=`() = discard
+    doAssert a == """
+proc `foo=`() =
+  discard"""
+
+  block: # bug #14850
+    block:
+      let a = deb:
+        template bar(): untyped =
+          foo1:
+            discard
+            4
+          foo2(1):
+            discard
+            4
+          foo3(1):
+            discard
+            4
+          do: 1
+          do: 2
+          x.add foo4
+          x.add: foo5: 3
+          x.add foo6 do: 4
+          a.add(foo7 do:
+            echo "baz"
+            4)
+
+      doAssert a == """
+template bar(): untyped =
+  foo1:
+    discard
+    4
+  foo2(1):
+    discard
+    4
+  foo3(1):
+    discard
+    4
+  do:
+    1
+  do:
+    2
+  x.add foo4
+  x.add:
+    foo5:
+      3
+  x.add foo6 do:
+    4
+  a.add(foo7 do:
+    echo "baz"
+    4)"""
+
+  block: # one liner doc comments
+    let a1 = deb:
+      func fn1(): int = 1  ## comment
+      func fn2(): int = 1
+        ## comment
+    let a2 = debTyped:
+      func fn1(): int = 1  ## comment
+      func fn2(): int = 1
+        ## comment
+    doAssert a1 == """
+func fn1(): int =
+  ## comment
+  1
+
+func fn2(): int =
+  ## comment
+  1"""
+    doAssert a2 == """
+func fn1(): int =
+  ## comment
+  result = 1
+
+func fn2(): int =
+  ## comment
+  result = 1"""
+
+  block: # block calls
+    let a = deb:
+      foo(a, b, (c, d)):
+        e
+        f
+      do: g
+      of h: i
+      elif j: k
+      except m: n
+      do () -> u: v
+      finally: o
+
+      a + b:
+        c
+        d
+      do:
+        e
+        f
+      else: g
+
+      *a: b
+      do: c
+
+    doAssert a == """foo(a, b, (c, d)):
+  e
+  f
+do:
+  g
+of h:
+  i
+elif j:
+  k
+except m:
+  n
+do -> u:
+  v
+finally:
+  o
+a + b:
+  c
+  d
+do:
+  e
+  f
+else:
+  g
+*a:
+  b
+do:
+  c"""
+
+  doAssert repr(1..2) == "1 .. 2"
+
+static: main()
+main()
diff --git a/tests/stdlib/trlocks.nim b/tests/stdlib/trlocks.nim
new file mode 100644
index 000000000..135d9b028
--- /dev/null
+++ b/tests/stdlib/trlocks.nim
@@ -0,0 +1,14 @@
+discard """
+  action: "compile"
+  # Disallow joining to ensure it can compile in isolation.
+  # See #15584
+  joinable: false
+  cmd: "nim $target --threads:on $options $file"
+"""
+
+# bugfix #15584
+
+import rlocks
+
+var r: RLock
+r.initRLock()
diff --git a/tests/stdlib/tropes.nim b/tests/stdlib/tropes.nim
new file mode 100644
index 000000000..eb0edc364
--- /dev/null
+++ b/tests/stdlib/tropes.nim
@@ -0,0 +1,104 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/ropes
+import std/assertions
+
+template main() =
+  block:
+    let r: Rope = nil
+    doAssert r[0] == '\0'
+    doAssert $r == ""
+
+  block:
+    var
+      r1 = rope("Hello, ")
+      r2 = rope("Nim-Lang")
+
+    let r = r1 & r2
+    let s = $r
+    doAssert s == "Hello, Nim-Lang"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    let r = rope("Hello, Nim-Lang")
+
+    let s = $r
+    doAssert s == "Hello, Nim-Lang"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    var r: Rope
+    r.add rope("Nim ")
+    r.add rope("is ")
+    r.add rope("a ")
+    r.add rope("great ")
+    r.add rope("language")
+
+    let s = $r
+    doAssert s == "Nim is a great language"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    var r: Rope
+    r.add rope("My Conquest")
+    r.add rope(" is ")
+    r.add rope("the Sea of Stars")
+
+    let s = $r
+    doAssert s == "My Conquest is the Sea of Stars"
+    for i in 0 ..< r.len:
+      doAssert r[i] == s[i]
+
+    doAssert r[66] == '\0'
+
+  block:
+    var r: Rope
+    r.add rope("My Conquest")
+    r.add rope(" is ")
+    r.add rope("the Sea of Stars")
+
+    doAssert $r == "My Conquest is the Sea of Stars"
+
+    var i: int
+    for item in r:
+      doAssert r[i] == item
+      inc i
+
+    doAssert r[66] == '\0'
+
+  block:
+    let r1 = "$1 $2 $3" % [rope("Nim"), rope("is"), rope("a great language")]
+    doAssert $r1 == "Nim is a great language"
+
+    let r2 = "$# $# $#" % [rope("Nim"), rope("is"), rope("a great language")]
+    doAssert $r2 == "Nim is a great language"
+
+  block: # `[]`
+    let r1 = rope("Hello, Nim!")
+
+    doAssert r1[-2] == '\0'
+    doAssert r1[0] == 'H'
+    doAssert r1[7] == 'N'
+    doAssert r1[22] == '\0'
+
+    let r2 = rope("Hello") & rope(", Nim!")
+
+    doAssert r2[-2] == '\0'
+    doAssert r2[0] == 'H'
+    doAssert r2[7] == 'N'
+    doAssert r2[22] == '\0'
+
+static: main()
+main()
diff --git a/tests/stdlib/trst.nim b/tests/stdlib/trst.nim
new file mode 100644
index 000000000..ceab34bc9
--- /dev/null
+++ b/tests/stdlib/trst.nim
@@ -0,0 +1,1994 @@
+discard """
+  output: '''
+
+[Suite] RST parsing
+
+[Suite] RST tables
+
+[Suite] RST indentation
+
+[Suite] Markdown indentation
+
+[Suite] Warnings
+
+[Suite] RST include directive
+
+[Suite] RST escaping
+
+[Suite] RST inline markup
+
+[Suite] Misc isssues
+'''
+matrix: "--mm:refc; --mm:orc"
+"""
+
+# tests for rst module
+
+import ../../lib/packages/docutils/[rstgen, rst, rstast]
+import unittest, strutils
+import std/private/miscdollars
+import os
+import std/[assertions, syncio]
+
+const preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
+# legacy nimforum / old default mode:
+const preferRst = {roSupportMarkdown, roNimFile, roSandboxDisabled}
+const pureRst = {roNimFile, roSandboxDisabled}
+
+proc toAst(input: string,
+            rstOptions: RstParseOptions = preferMarkdown,
+            error: ref string = nil,
+            warnings: ref seq[string] = nil): string =
+  ## If `error` is nil then no errors should be generated.
+  ## The same goes for `warnings`.
+  proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
+                      arg: string) =
+    let mc = msgkind.whichMsgClass
+    let a = $msgkind % arg
+    var message: string
+    toLocation(message, filename, line, col + ColRstOffset)
+    message.add " $1: $2" % [$mc, a]
+    if mc == mcError:
+      if error == nil:
+        raise newException(EParseError, "[unexpected error] " & message)
+      error[] = message
+      # we check only first error because subsequent ones may be meaningless
+      raise newException(EParseError, "")
+    else:
+      doAssert warnings != nil, "unexpected RST warning '" & message & "'"
+      warnings[].add message
+  try:
+    const filen = "input"
+
+    proc myFindFile(filename: string): string =
+      # we don't find any files in online mode:
+      result = ""
+
+    var (rst, _, _) = rstParse(input, filen, line=LineRstInit, column=ColRstInit,
+                               rstOptions, myFindFile, nil, testMsgHandler)
+    result = treeRepr(rst)
+  except EParseError as e:
+    if e.msg != "":
+      result = e.msg
+
+suite "RST parsing":
+  test "Standalone punctuation is not parsed as heading overlines":
+    check(dedent"""
+        Paragraph
+
+        !""".toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Paragraph'
+          rnParagraph
+            rnLeaf  '!'
+      """)
+
+    check(dedent"""
+        Paragraph1
+
+        ...
+
+        Paragraph2""".toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Paragraph1'
+          rnParagraph
+            rnLeaf  '...'
+          rnParagraph
+            rnLeaf  'Paragraph2'
+      """)
+
+    check(dedent"""
+        ---
+        Paragraph""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  '---'
+          rnLeaf  ' '
+          rnLeaf  'Paragraph'
+      """)
+
+  test "References are whitespace-neutral and case-insensitive":
+    # refname is 'lexical-analysis', the same for all the 3 variants:
+    check(dedent"""
+        Lexical Analysis
+        ================
+
+        Ref. `Lexical Analysis`_ or `Lexical analysis`_ or `lexical analysis`_.
+        """.toAst ==
+      dedent"""
+        rnInner
+          rnHeadline  level=1  anchor='lexical-analysis'
+            rnLeaf  'Lexical'
+            rnLeaf  ' '
+            rnLeaf  'Analysis'
+          rnParagraph
+            rnLeaf  'Ref'
+            rnLeaf  '.'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'Lexical'
+                rnLeaf  ' '
+                rnLeaf  'Analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  ' '
+            rnLeaf  'or'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'Lexical'
+                rnLeaf  ' '
+                rnLeaf  'analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  ' '
+            rnLeaf  'or'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'lexical'
+                rnLeaf  ' '
+                rnLeaf  'analysis'
+              rnLeaf  'lexical-analysis'
+            rnLeaf  '.'
+            rnLeaf  ' '
+      """)
+
+  test "RST quoted literal blocks":
+    let expected =
+      dedent"""
+        rnInner
+          rnLeaf  'Paragraph'
+          rnLeaf  ':'
+          rnLiteralBlock
+            rnLeaf  '>x'
+        """
+
+    check(dedent"""
+        Paragraph::
+
+        >x""".toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        Paragraph::
+
+            >x""".toAst(rstOptions = preferRst) == expected)
+
+  test "RST quoted literal blocks, :: at a separate line":
+    let expected =
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'Paragraph'
+          rnLiteralBlock
+            rnLeaf  '>x
+        >>y'
+      """
+
+    check(dedent"""
+        Paragraph
+
+        ::
+
+        >x
+        >>y""".toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        Paragraph
+
+        ::
+
+          >x
+          >>y""".toAst(rstOptions = preferRst) == expected)
+
+  test "Markdown quoted blocks":
+    check(dedent"""
+        Paragraph.
+        >x""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'Paragraph'
+          rnLeaf  '.'
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnLeaf  'x'
+      """)
+
+    # bug #17987
+    check(dedent"""
+        foo https://github.com/nim-lang/Nim/issues/8258
+
+        > bar""".toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'foo'
+            rnLeaf  ' '
+            rnStandaloneHyperlink
+              rnLeaf  'https://github.com/nim-lang/Nim/issues/8258'
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnLeaf  'bar'
+      """)
+
+    let expected = dedent"""
+        rnInner
+          rnLeaf  'Paragraph'
+          rnLeaf  '.'
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnInner
+                rnLeaf  'x1'
+                rnLeaf  ' '
+                rnLeaf  'x2'
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnInner
+                rnLeaf  'y1'
+                rnLeaf  ' '
+                rnLeaf  'y2'
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnLeaf  'z'
+        """
+
+    check(dedent"""
+        Paragraph.
+        >x1 x2
+        >>y1 y2
+        >z""".toAst == expected)
+
+    check(dedent"""
+        Paragraph.
+        > x1 x2
+        >> y1 y2
+        > z""".toAst == expected)
+
+    check(dedent"""
+        >x
+        >y
+        >z""".toAst ==
+      dedent"""
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnInner
+              rnLeaf  'x'
+              rnLeaf  ' '
+              rnLeaf  'y'
+              rnLeaf  ' '
+              rnLeaf  'z'
+      """)
+
+    check(dedent"""
+        > z
+        > > >y
+        """.toAst ==
+      dedent"""
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnLeaf  'z'
+          rnMarkdownBlockQuoteItem  quotationDepth=3
+            rnLeaf  'y'
+        """)
+
+  test "Markdown quoted blocks: lazy":
+    let expected = dedent"""
+        rnInner
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnInner
+                rnLeaf  'x'
+                rnLeaf  ' '
+                rnLeaf  'continuation1'
+                rnLeaf  ' '
+                rnLeaf  'continuation2'
+          rnParagraph
+            rnLeaf  'newParagraph'
+      """
+    check(dedent"""
+        >>x
+        continuation1
+        continuation2
+
+        newParagraph""".toAst == expected)
+
+    check(dedent"""
+        >> x
+        continuation1
+        continuation2
+
+        newParagraph""".toAst == expected)
+
+    # however mixing more than 1 non-lazy line and lazy one(s) splits quote
+    # in our parser, which appeared the easiest way to handle such cases:
+    var warnings = new seq[string]
+    check(dedent"""
+        >> x
+        >> continuation1
+        continuation2
+
+        newParagraph""".toAst(warnings=warnings) ==
+      dedent"""
+        rnInner
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnLeaf  'x'
+            rnMarkdownBlockQuoteItem  quotationDepth=2
+              rnInner
+                rnLeaf  'continuation1'
+                rnLeaf  ' '
+                rnLeaf  'continuation2'
+          rnParagraph
+            rnLeaf  'newParagraph'
+        """)
+    check(warnings[] == @[
+        "input(2, 1) Warning: RST style: two or more quoted lines " &
+        "are followed by unquoted line 3"])
+
+  test "Markdown quoted blocks: not lazy":
+    # here is where we deviate from CommonMark specification: 'bar' below is
+    # not considered as continuation of 2-level '>> foo' quote.
+    check(dedent"""
+        >>> foo
+        > bar
+        >> baz
+        """.toAst() ==
+      dedent"""
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=3
+            rnLeaf  'foo'
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnLeaf  'bar'
+          rnMarkdownBlockQuoteItem  quotationDepth=2
+            rnLeaf  'baz'
+        """)
+
+
+  test "Markdown quoted blocks: inline markup works":
+    check(dedent"""
+        > hi **bold** text
+        """.toAst == dedent"""
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnInner
+                rnLeaf  'hi'
+                rnLeaf  ' '
+                rnStrongEmphasis
+                  rnLeaf  'bold'
+                rnLeaf  ' '
+                rnLeaf  'text'
+        """)
+
+  test "Markdown quoted blocks: blank line separator":
+    let expected = dedent"""
+      rnInner
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnInner
+              rnLeaf  'x'
+              rnLeaf  ' '
+              rnLeaf  'y'
+        rnMarkdownBlockQuote
+          rnMarkdownBlockQuoteItem  quotationDepth=1
+            rnInner
+              rnLeaf  'z'
+              rnLeaf  ' '
+              rnLeaf  't'
+      """
+    check(dedent"""
+        >x
+        >y
+
+        > z
+        > t""".toAst == expected)
+
+    check(dedent"""
+        >x
+        y
+
+        > z
+         t""".toAst == expected)
+
+  test "Markdown quoted blocks: nested body blocks/elements work #1":
+    let expected = dedent"""
+      rnMarkdownBlockQuote
+        rnMarkdownBlockQuoteItem  quotationDepth=1
+          rnBulletList
+            rnBulletItem
+              rnInner
+                rnLeaf  'x'
+            rnBulletItem
+              rnInner
+                rnLeaf  'y'
+      """
+
+    check(dedent"""
+        > - x
+          - y
+        """.toAst == expected)
+
+    # TODO: if bug #17340 point 28 is resolved then this may work:
+    # check(dedent"""
+    #     > - x
+    #     - y
+    #     """.toAst == expected)
+
+    check(dedent"""
+        > - x
+        > - y
+        """.toAst == expected)
+
+    check(dedent"""
+        >
+        > - x
+        >
+        > - y
+        >
+        """.toAst == expected)
+
+  test "Markdown quoted blocks: nested body blocks/elements work #2":
+    let expected = dedent"""
+      rnAdmonition  adType=note
+        [nil]
+        [nil]
+        rnDefList
+          rnDefItem
+            rnDefName
+              rnLeaf  'deflist'
+              rnLeaf  ':'
+            rnDefBody
+              rnMarkdownBlockQuote
+                rnMarkdownBlockQuoteItem  quotationDepth=2
+                  rnInner
+                    rnLeaf  'quote'
+                    rnLeaf  ' '
+                    rnLeaf  'continuation'
+      """
+
+    check(dedent"""
+        .. Note:: deflist:
+                    >> quote
+                    continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        .. Note::
+           deflist:
+             >> quote
+             continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+    check(dedent"""
+        .. Note::
+           deflist:
+             >> quote
+             >> continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+    # spaces are not significant between `>`:
+    check(dedent"""
+        .. Note::
+           deflist:
+             > > quote
+             > > continuation
+        """.toAst(rstOptions = preferRst) == expected)
+
+  test "Markdown quoted blocks: de-indent handled well":
+    check(dedent"""
+        >
+        >   - x
+        >   - y
+        >
+        > Paragraph.
+        """.toAst(rstOptions = preferRst) == dedent"""
+          rnMarkdownBlockQuote
+            rnMarkdownBlockQuoteItem  quotationDepth=1
+              rnInner
+                rnBlockQuote
+                  rnBulletList
+                    rnBulletItem
+                      rnInner
+                        rnLeaf  'x'
+                    rnBulletItem
+                      rnInner
+                        rnLeaf  'y'
+                rnParagraph
+                  rnLeaf  'Paragraph'
+                  rnLeaf  '.'
+          """)
+
+  let expectCodeBlock = dedent"""
+      rnCodeBlock
+        [nil]
+        rnFieldList
+          rnField
+            rnFieldName
+              rnLeaf  'default-language'
+            rnFieldBody
+              rnLeaf  'Nim'
+        rnLiteralBlock
+          rnLeaf  'let a = 1
+      ```'
+      """
+
+  test "Markdown footnotes":
+    # Testing also 1) correct order of manually-numbered and automatically-
+    # numbered footnotes; 2) no spaces between references (html & 3 below):
+
+    check(dedent"""
+        Paragraph [^1] [^html-hyphen][^3] and [^latex]
+
+        [^1]: footnote1
+
+        [^html-hyphen]: footnote2
+           continuation2
+
+        [^latex]: footnote4
+
+        [^3]: footnote3
+            continuation3
+        """.toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'Paragraph'
+            rnLeaf  ' '
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '1'
+              rnLeaf  'footnote-1'
+            rnLeaf  ' '
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '2'
+              rnLeaf  'footnote-htmlminushyphen'
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '3'
+              rnLeaf  'footnote-3'
+            rnLeaf  ' '
+            rnLeaf  'and'
+            rnLeaf  ' '
+            rnFootnoteRef
+              rnInner
+                rnLeaf  '4'
+              rnLeaf  'footnote-latex'
+          rnFootnoteGroup
+            rnFootnote  anchor='footnote-1'
+              rnInner
+                rnLeaf  '1'
+              rnLeaf  'footnote1'
+            rnFootnote  anchor='footnote-htmlminushyphen'
+              rnInner
+                rnLeaf  '2'
+              rnInner
+                rnLeaf  'footnote2'
+                rnLeaf  ' '
+                rnLeaf  'continuation2'
+            rnFootnote  anchor='footnote-latex'
+              rnInner
+                rnLeaf  '4'
+              rnLeaf  'footnote4'
+            rnFootnote  anchor='footnote-3'
+              rnInner
+                rnLeaf  '3'
+              rnInner
+                rnLeaf  'footnote3'
+                rnLeaf  ' '
+                rnLeaf  'continuation3'
+      """)
+
+  test "Markdown code blocks with more > 3 backticks":
+    check(dedent"""
+        ````
+        let a = 1
+        ```
+        ````""".toAst == expectCodeBlock)
+
+  test "Markdown code blocks with ~~~":
+    check(dedent"""
+        ~~~
+        let a = 1
+        ```
+        ~~~""".toAst == expectCodeBlock)
+    check(dedent"""
+        ~~~~~
+        let a = 1
+        ```
+        ~~~~~""".toAst == expectCodeBlock)
+
+  test "Markdown code blocks with Nim-specific arguments":
+    check(dedent"""
+        ```nim number-lines=1 test
+        let a = 1
+        ```""".toAst ==
+      dedent"""
+        rnCodeBlock
+          rnDirArg
+            rnLeaf  'nim'
+          rnFieldList
+            rnField
+              rnFieldName
+                rnLeaf  'number-lines'
+              rnFieldBody
+                rnLeaf  '1'
+            rnField
+              rnFieldName
+                rnLeaf  'test'
+              rnFieldBody
+          rnLiteralBlock
+            rnLeaf  'let a = 1'
+        """)
+
+    check(dedent"""
+        ```nim test = "nim c $1"  number-lines = 1
+        let a = 1
+        ```""".toAst ==
+      dedent"""
+        rnCodeBlock
+          rnDirArg
+            rnLeaf  'nim'
+          rnFieldList
+            rnField
+              rnFieldName
+                rnLeaf  'test'
+              rnFieldBody
+                rnLeaf  '"nim c $1"'
+            rnField
+              rnFieldName
+                rnLeaf  'number-lines'
+              rnFieldBody
+                rnLeaf  '1'
+          rnLiteralBlock
+            rnLeaf  'let a = 1'
+        """)
+
+  test "additional indentation < 4 spaces is handled fine":
+    check(dedent"""
+        Indentation
+
+          ```nim
+            let a = 1
+          ```""".toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Indentation'
+          rnParagraph
+            rnCodeBlock
+              rnDirArg
+                rnLeaf  'nim'
+              [nil]
+              rnLiteralBlock
+                rnLeaf  '  let a = 1'
+      """)
+      # | |
+      # |  \ indentation of exactly two spaces before 'let a = 1'
+
+  test "no blank line is required before or after Markdown code block":
+    let inputBacktick = dedent"""
+        Some text
+        ```
+        CodeBlock()
+        ```
+        Other text"""
+    let inputTilde = dedent"""
+        Some text
+        ~~~~~~~~~
+        CodeBlock()
+        ~~~~~~~~~
+        Other text"""
+    let expected = dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Some'
+            rnLeaf  ' '
+            rnLeaf  'text'
+          rnParagraph
+            rnCodeBlock
+              [nil]
+              rnFieldList
+                rnField
+                  rnFieldName
+                    rnLeaf  'default-language'
+                  rnFieldBody
+                    rnLeaf  'Nim'
+              rnLiteralBlock
+                rnLeaf  'CodeBlock()'
+            rnLeaf  ' '
+            rnLeaf  'Other'
+            rnLeaf  ' '
+            rnLeaf  'text'
+      """
+    check inputBacktick.toAst == expected
+    check inputTilde.toAst == expected
+
+  test "option list has priority over definition list":
+    for opt in [preferMarkdown, preferRst]:
+      check(dedent"""
+          --defusages
+                        file
+          -o            set
+          """.toAst(rstOptions = opt) ==
+        dedent"""
+          rnOptionList
+            rnOptionListItem  order=1
+              rnOptionGroup
+                rnLeaf  '--'
+                rnLeaf  'defusages'
+              rnDescription
+                rnInner
+                  rnLeaf  'file'
+            rnOptionListItem  order=2
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'o'
+              rnDescription
+                rnLeaf  'set'
+          """)
+
+  test "items of 1 option list can be separated by blank lines":
+    check(dedent"""
+        -a  desc1
+
+        -b  desc2
+        """.toAst ==
+      dedent"""
+        rnOptionList
+          rnOptionListItem  order=1
+            rnOptionGroup
+              rnLeaf  '-'
+              rnLeaf  'a'
+            rnDescription
+              rnLeaf  'desc1'
+          rnOptionListItem  order=2
+            rnOptionGroup
+              rnLeaf  '-'
+              rnLeaf  'b'
+            rnDescription
+              rnLeaf  'desc2'
+      """)
+
+  test "definition list does not gobble up the following blocks":
+    check(dedent"""
+        defName
+            defBody
+
+        -b  desc2
+        """.toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnDefList
+            rnDefItem
+              rnDefName
+                rnLeaf  'defName'
+              rnDefBody
+                rnInner
+                  rnLeaf  'defBody'
+          rnOptionList
+            rnOptionListItem  order=1
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'b'
+              rnDescription
+                rnLeaf  'desc2'
+      """)
+
+  test "definition lists work correctly with additional indentation in Markdown":
+    check(dedent"""
+        Paragraph:
+          -c  desc1
+          -b  desc2
+        """.toAst() ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'Paragraph'
+            rnLeaf  ':'
+          rnOptionList
+            rnOptionListItem  order=1
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'c'
+              rnDescription
+                rnLeaf  'desc1'
+            rnOptionListItem  order=2
+              rnOptionGroup
+                rnLeaf  '-'
+                rnLeaf  'b'
+              rnDescription
+                rnLeaf  'desc2'
+      """)
+
+  test "RST comment":
+    check(dedent"""
+        .. comment1
+         comment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnLeaf  'someParagraph'
+        """)
+
+    check(dedent"""
+        ..
+         comment1
+         comment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnLeaf  'someParagraph'
+        """)
+
+  test "check that additional line right after .. ends comment":
+    check(dedent"""
+        ..
+
+         notAcomment1
+         notAcomment2
+        someParagraph""".toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnBlockQuote
+            rnInner
+              rnLeaf  'notAcomment1'
+              rnLeaf  ' '
+              rnLeaf  'notAcomment2'
+          rnParagraph
+            rnLeaf  'someParagraph'
+        """)
+
+  test "check that additional line right after .. ends comment (Markdown mode)":
+    # in Markdown small indentation does not matter so this should
+    # just be split to 2 paragraphs.
+    check(dedent"""
+        ..
+
+         notAcomment1
+         notAcomment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'notAcomment1'
+            rnLeaf  ' '
+            rnLeaf  'notAcomment2'
+          rnParagraph
+            rnLeaf  'someParagraph'
+        """)
+
+  test "but blank lines after 2nd non-empty line don't end the comment":
+    check(dedent"""
+        ..
+           comment1
+
+
+         comment2
+        someParagraph""".toAst ==
+      dedent"""
+        rnLeaf  'someParagraph'
+        """)
+
+  test "using .. as separator b/w directives and block quotes":
+    check(dedent"""
+        .. note:: someNote
+
+        ..
+
+          someBlockQuote""".toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnAdmonition  adType=note
+            [nil]
+            [nil]
+            rnLeaf  'someNote'
+          rnBlockQuote
+            rnInner
+              rnLeaf  'someBlockQuote'
+        """)
+
+  test "no redundant blank lines in literal blocks":
+    check(dedent"""
+      Check::
+
+
+        code
+
+      """.toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnLeaf  'Check'
+          rnLeaf  ':'
+          rnLiteralBlock
+            rnLeaf  'code'
+      """)
+
+  test "Markdown indented code blocks":
+    check(dedent"""
+      See
+
+          some code""".toAst ==
+      dedent"""
+        rnInner
+          rnInner
+            rnLeaf  'See'
+          rnLiteralBlock
+            rnLeaf  'some code'
+      """)
+
+    # not a code block -- no blank line before:
+    check(dedent"""
+      See
+          some code""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'See'
+          rnLeaf  ' '
+          rnLeaf  'some'
+          rnLeaf  ' '
+          rnLeaf  'code'
+      """)
+
+suite "RST tables":
+
+  test "formatting in tables works":
+    check(
+      dedent"""
+        =========  ===
+        `build`    `a`
+        =========  ===
+        """.toAst ==
+      dedent"""
+        rnTable  colCount=2
+          rnTableRow
+            rnTableDataCell
+              rnInlineCode
+                rnDirArg
+                  rnLeaf  'nim'
+                [nil]
+                rnLiteralBlock
+                  rnLeaf  'build'
+            rnTableDataCell
+              rnInlineCode
+                rnDirArg
+                  rnLeaf  'nim'
+                [nil]
+                rnLiteralBlock
+                  rnLeaf  'a'
+      """)
+
+  test "tables with slightly overflowed cells cause an error (1)":
+    var error = new string
+    check(
+      dedent"""
+        ======   ======
+         Inputs  Output
+        ======   ======
+        """.toAst(rstOptions = pureRst, error = error) == "")
+    check(error[] == "input(2, 2) Error: Illformed table: " &
+                     "this word crosses table column from the right")
+
+    # In nimforum compatibility mode & Markdown we raise a warning instead:
+    let expected = dedent"""
+      rnTable  colCount=2
+        rnTableRow
+          rnTableDataCell
+            rnLeaf  'Inputs'
+          rnTableDataCell
+            rnLeaf  'Output'
+      """
+    for opt in [preferRst, preferMarkdown]:
+      var warnings = new seq[string]
+
+      check(
+        dedent"""
+          ======   ======
+           Inputs  Output
+          ======   ======
+          """.toAst(rstOptions = opt, warnings = warnings) == expected)
+      check(warnings[] == @[
+        "input(2, 2) Warning: RST style: this word crosses table column from the right"])
+
+  test "tables with slightly overflowed cells cause an error (2)":
+    var error = new string
+    check("" == dedent"""
+      =====  =====  ======
+      Input  Output
+      =====  =====  ======
+      False  False  False
+      =====  =====  ======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(2, 8) Error: Illformed table: " &
+                     "this word crosses table column from the right")
+
+  test "tables with slightly underflowed cells cause an error":
+    var error = new string
+    check("" == dedent"""
+      =====  =====  ======
+      Input Output
+      =====  =====  ======
+      False  False  False
+      =====  =====  ======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(2, 7) Error: Illformed table: " &
+                     "this word crosses table column from the left")
+
+  test "tables with unequal underlines should be reported (1)":
+    var error = new string
+    error[] = "none"
+    check("" == dedent"""
+      =====  ======
+      Input  Output
+      =====  ======
+      False  False
+      =====  =======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(5, 14) Error: Illformed table: " &
+                     "end of table column #2 should end at position 13")
+
+  test "tables with unequal underlines should be reported (2)":
+    var error = new string
+    check("" == dedent"""
+      =====  ======
+      Input  Output
+      =====  =======
+      False  False
+      =====  ======
+      """.toAst(rstOptions = pureRst, error = error))
+    check(error[] == "input(3, 14) Error: Illformed table: " &
+                     "end of table column #2 should end at position 13")
+
+  test "tables with empty first cells":
+    check(
+      dedent"""
+          = = =
+          x y z
+              t
+          = = =
+          """.toAst ==
+      dedent"""
+        rnTable  colCount=3
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'x'
+            rnTableDataCell
+              rnInner
+                rnLeaf  'y'
+                rnLeaf  ' '
+            rnTableDataCell
+              rnInner
+                rnLeaf  'z'
+                rnLeaf  ' '
+                rnLeaf  't'
+        """)
+
+  test "tables with spanning cells & separators":
+    check(
+      dedent"""
+        =====  =====  ======
+           Inputs     Output
+        ------------  ------
+          A      B    A or B
+        =====  =====  ======
+        False  False  False
+        True   False  True
+        -----  -----  ------
+        False  True   True
+        True   True   True
+        =====  =====  ======
+        """.toAst ==
+      dedent"""
+        rnTable  colCount=3
+          rnTableRow
+            rnTableHeaderCell  span=2
+              rnLeaf  'Inputs'
+            rnTableHeaderCell  span=1
+              rnLeaf  'Output'
+          rnTableRow  endsHeader
+            rnTableHeaderCell
+              rnLeaf  'A'
+            rnTableHeaderCell
+              rnLeaf  'B'
+            rnTableHeaderCell
+              rnInner
+                rnLeaf  'A'
+                rnLeaf  ' '
+                rnLeaf  'or'
+                rnLeaf  ' '
+                rnLeaf  'B'
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'False'
+            rnTableDataCell
+              rnLeaf  'False'
+            rnTableDataCell
+              rnLeaf  'False'
+          rnTableRow
+            rnTableDataCell  span=1
+              rnLeaf  'True'
+            rnTableDataCell  span=1
+              rnLeaf  'False'
+            rnTableDataCell  span=1
+              rnLeaf  'True'
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'False'
+            rnTableDataCell
+              rnLeaf  'True'
+            rnTableDataCell
+              rnLeaf  'True'
+          rnTableRow
+            rnTableDataCell
+              rnLeaf  'True'
+            rnTableDataCell
+              rnLeaf  'True'
+            rnTableDataCell
+              rnLeaf  'True'
+      """)
+
+  test "tables with spanning cells with uneqal underlines cause an error":
+    var error = new string
+    check(
+      dedent"""
+        =====  =====  ======
+           Inputs     Output
+        ------------- ------
+          A      B    A or B
+        =====  =====  ======
+        """.toAst(error=error) == "")
+    check(error[] == "input(3, 1) Error: Illformed table: " &
+                     "spanning underline does not match main table columns")
+
+  let expTable = dedent"""
+      rnTable  colCount=2
+        rnTableRow
+          rnTableDataCell
+            rnLeaf  'Inputs'
+          rnTableDataCell
+            rnLeaf  'Output'
+      """
+
+  test "only tables with `=` columns specs are allowed (1)":
+    var warnings = new seq[string]
+    check(
+      dedent"""
+        ------  ------
+        Inputs  Output
+        ------  ------
+        """.toAst(warnings=warnings) ==
+      expTable)
+    check(warnings[] ==
+          @["input(1, 1) Warning: RST style: " &
+              "only tables with `=` columns specification are allowed",
+            "input(3, 1) Warning: RST style: " &
+              "only tables with `=` columns specification are allowed"])
+
+  test "only tables with `=` columns specs are allowed (2)":
+    var warnings = new seq[string]
+    check(
+      dedent"""
+        ======  ======
+        Inputs  Output
+        ~~~~~~  ~~~~~~
+        """.toAst(warnings=warnings) ==
+      expTable)
+    check(warnings[] ==
+          @["input(3, 1) Warning: RST style: "&
+              "only tables with `=` columns specification are allowed"])
+
+
+suite "RST indentation":
+  test "nested bullet lists":
+    let input = dedent """
+      * - bullet1
+        - bullet2
+      * - bullet3
+        - bullet4
+      """
+    let output = input.toAst
+    check(output == dedent"""
+      rnBulletList
+        rnBulletItem
+          rnBulletList
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet1'
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet2'
+        rnBulletItem
+          rnBulletList
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet3'
+            rnBulletItem
+              rnInner
+                rnLeaf  'bullet4'
+      """)
+
+  test "nested markup blocks":
+    let input = dedent"""
+      #) .. Hint:: .. Error:: none
+      #) .. Warning:: term0
+                        Definition0
+      #) some
+         paragraph1
+      #) term1
+           Definition1
+         term2
+           Definition2
+    """
+    check(input.toAst(rstOptions = preferRst) == dedent"""
+      rnEnumList  labelFmt=1)
+        rnEnumItem
+          rnAdmonition  adType=hint
+            [nil]
+            [nil]
+            rnAdmonition  adType=error
+              [nil]
+              [nil]
+              rnLeaf  'none'
+        rnEnumItem
+          rnAdmonition  adType=warning
+            [nil]
+            [nil]
+            rnDefList
+              rnDefItem
+                rnDefName
+                  rnLeaf  'term0'
+                rnDefBody
+                  rnInner
+                    rnLeaf  'Definition0'
+        rnEnumItem
+          rnInner
+            rnLeaf  'some'
+            rnLeaf  ' '
+            rnLeaf  'paragraph1'
+        rnEnumItem
+          rnDefList
+            rnDefItem
+              rnDefName
+                rnLeaf  'term1'
+              rnDefBody
+                rnInner
+                  rnLeaf  'Definition1'
+            rnDefItem
+              rnDefName
+                rnLeaf  'term2'
+              rnDefBody
+                rnInner
+                  rnLeaf  'Definition2'
+      """)
+
+  test "code-block parsing":
+    let input1 = dedent"""
+      .. code-block:: nim
+          :test: "nim c $1"
+
+        template additive(typ: typedesc) =
+          discard
+      """
+    let input2 = dedent"""
+      .. code-block:: nim
+        :test: "nim c $1"
+
+        template additive(typ: typedesc) =
+          discard
+      """
+    let input3 = dedent"""
+      .. code-block:: nim
+         :test: "nim c $1"
+         template additive(typ: typedesc) =
+           discard
+      """
+    let inputWrong = dedent"""
+      .. code-block:: nim
+       :test: "nim c $1"
+
+         template additive(typ: typedesc) =
+           discard
+      """
+    let ast = dedent"""
+      rnCodeBlock
+        rnDirArg
+          rnLeaf  'nim'
+        rnFieldList
+          rnField
+            rnFieldName
+              rnLeaf  'test'
+            rnFieldBody
+              rnInner
+                rnLeaf  '"'
+                rnLeaf  'nim'
+                rnLeaf  ' '
+                rnLeaf  'c'
+                rnLeaf  ' '
+                rnLeaf  '$'
+                rnLeaf  '1'
+                rnLeaf  '"'
+          rnField
+            rnFieldName
+              rnLeaf  'default-language'
+            rnFieldBody
+              rnLeaf  'Nim'
+        rnLiteralBlock
+          rnLeaf  'template additive(typ: typedesc) =
+        discard'
+      """
+    check input1.toAst == ast
+    check input2.toAst == ast
+    check input3.toAst == ast
+    # "template..." should be parsed as a definition list attached to ":test:":
+    check inputWrong.toAst != ast
+
+  test "Markdown definition lists work in conjunction with bullet lists":
+    check(dedent"""
+        * some term
+          : the definition
+
+        Paragraph.""".toAst ==
+      dedent"""
+        rnInner
+          rnBulletList
+            rnBulletItem
+              rnMdDefList
+                rnDefItem
+                  rnDefName
+                    rnLeaf  'some'
+                    rnLeaf  ' '
+                    rnLeaf  'term'
+                  rnDefBody
+                    rnInner
+                      rnLeaf  'the'
+                      rnLeaf  ' '
+                      rnLeaf  'definition'
+          rnParagraph
+            rnLeaf  'Paragraph'
+            rnLeaf  '.'
+      """)
+
+  test "Markdown definition lists work with blank lines and extra paragraphs":
+    check(dedent"""
+        Term1
+
+        :   Definition1
+
+        Term2 *inline markup*
+
+        :   Definition2
+
+            Paragraph2
+
+        Term3
+        : * point1
+          * point2
+        : term3definition2
+      """.toAst == dedent"""
+        rnMdDefList
+          rnDefItem
+            rnDefName
+              rnLeaf  'Term1'
+            rnDefBody
+              rnInner
+                rnLeaf  'Definition1'
+          rnDefItem
+            rnDefName
+              rnLeaf  'Term2'
+              rnLeaf  ' '
+              rnEmphasis
+                rnLeaf  'inline'
+                rnLeaf  ' '
+                rnLeaf  'markup'
+            rnDefBody
+              rnParagraph
+                rnLeaf  'Definition2'
+              rnParagraph
+                rnLeaf  'Paragraph2'
+          rnDefItem
+            rnDefName
+              rnLeaf  'Term3'
+            rnDefBody
+              rnBulletList
+                rnBulletItem
+                  rnInner
+                    rnLeaf  'point1'
+                rnBulletItem
+                  rnInner
+                    rnLeaf  'point2'
+            rnDefBody
+              rnInner
+                rnLeaf  'term3definition2'
+      """)
+
+suite "Markdown indentation":
+  test "Markdown paragraph indentation":
+    # Additional spaces (<=3) of indentation does not break the paragraph.
+    # TODO: in 2nd case de-indentation causes paragraph to break, this is
+    # reasonable but does not seem to conform the Markdown spec.
+    check(dedent"""
+      Start1
+        stop1
+
+        Start2
+      stop2
+      """.toAst ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Start1'
+            rnLeaf  ' '
+            rnLeaf  'stop1'
+          rnParagraph
+            rnLeaf  'Start2'
+          rnParagraph
+            rnLeaf  'stop2'
+            rnLeaf  ' '
+      """)
+
+suite "Warnings":
+  test "warnings for broken footnotes/links/substitutions":
+    let input = dedent"""
+      firstParagraph
+
+      footnoteRef [som]_
+
+      link `a broken Link`_
+
+      substitution |undefined subst|
+
+      link short.link_
+
+      lastParagraph
+      """
+    var warnings = new seq[string]
+    let output = input.toAst(rstOptions=preferRst, warnings=warnings)
+    check(warnings[] == @[
+        "input(3, 14) Warning: broken link 'citation-som'",
+        "input(5, 7) Warning: broken link 'a broken Link'",
+        "input(7, 15) Warning: unknown substitution 'undefined subst'",
+        "input(9, 6) Warning: broken link 'short.link'"
+        ])
+
+  test "Pandoc Markdown concise link warning points to target":
+    var warnings = new seq[string]
+    check(
+      "ref [here][target]".toAst(warnings=warnings) ==
+      dedent"""
+        rnInner
+          rnLeaf  'ref'
+          rnLeaf  ' '
+          rnPandocRef
+            rnInner
+              rnLeaf  'here'
+            rnInner
+              rnLeaf  'target'
+      """)
+    check warnings[] == @["input(1, 12) Warning: broken link 'target'"]
+
+  test "With include directive and blank lines at the beginning":
+    "other.rst".writeFile(dedent"""
+
+
+        firstParagraph
+
+        here brokenLink_""")
+    let input = ".. include:: other.rst"
+    var warnings = new seq[string]
+    let output = input.toAst(warnings=warnings)
+    check warnings[] == @["other.rst(5, 6) Warning: broken link 'brokenLink'"]
+    check(output == dedent"""
+      rnInner
+        rnParagraph
+          rnLeaf  'firstParagraph'
+        rnParagraph
+          rnLeaf  'here'
+          rnLeaf  ' '
+          rnRstRef
+            rnLeaf  'brokenLink'
+      """)
+    removeFile("other.rst")
+
+  test "warnings for ambiguous links (references + anchors)":
+    # Reference like `x`_ generates a link alias x that may clash with others
+    let input = dedent"""
+      Manual reference: `foo <#foo,string,string>`_
+
+      .. _foo:
+
+      Paragraph.
+
+      Ref foo_
+      """
+    var warnings = new seq[string]
+    let output = input.toAst(warnings=warnings)
+    check(warnings[] == @[
+      dedent """
+      input(7, 5) Warning: ambiguous doc link `foo`
+        clash:
+          (3, 8): (manual directive anchor)
+          (1, 45): (implicitly-generated hyperlink alias)"""
+    ])
+    # reference should be resolved to the manually set anchor:
+    check(output ==
+      dedent"""
+        rnInner
+          rnParagraph
+            rnLeaf  'Manual'
+            rnLeaf  ' '
+            rnLeaf  'reference'
+            rnLeaf  ':'
+            rnLeaf  ' '
+            rnHyperlink
+              rnInner
+                rnLeaf  'foo'
+              rnInner
+                rnLeaf  '#foo,string,string'
+          rnParagraph  anchor='foo'
+            rnLeaf  'Paragraph'
+            rnLeaf  '.'
+          rnParagraph
+            rnLeaf  'Ref'
+            rnLeaf  ' '
+            rnInternalRef
+              rnInner
+                rnLeaf  'foo'
+              rnLeaf  'foo'
+            rnLeaf  ' '
+      """)
+
+suite "RST include directive":
+  test "Include whole":
+    "other.rst".writeFile("**test1**")
+    let input = ".. include:: other.rst"
+    doAssert "<strong>test1</strong>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+  test "Include starting from":
+    "other.rst".writeFile("""
+And this should **NOT** be visible in `docs.html`
+OtherStart
+*Visible*
+""")
+
+    let input = """
+.. include:: other.rst
+             :start-after: OtherStart
+"""
+    check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+  test "Include everything before":
+    "other.rst".writeFile("""
+*Visible*
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+""")
+
+    let input = """
+.. include:: other.rst
+             :end-before: OtherEnd
+"""
+    doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+
+  test "Include everything between":
+    "other.rst".writeFile("""
+And this should **NOT** be visible in `docs.html`
+OtherStart
+*Visible*
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+""")
+
+    let input = """
+.. include:: other.rst
+             :start-after: OtherStart
+             :end-before: OtherEnd
+"""
+    check "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+
+  test "Ignore premature ending string":
+    "other.rst".writeFile("""
+
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+OtherStart
+*Visible*
+OtherEnd
+And this should **NOT** be visible in `docs.html`
+""")
+
+    let input = """
+.. include:: other.rst
+             :start-after: OtherStart
+             :end-before: OtherEnd
+"""
+    doAssert "<em>Visible</em>" == rstToHtml(input, {roSandboxDisabled}, defaultConfig())
+    removeFile("other.rst")
+
+suite "RST escaping":
+  test "backspaces":
+    check("""\ this""".toAst == dedent"""
+      rnLeaf  'this'
+      """)
+
+    check("""\\ this""".toAst == dedent"""
+      rnInner
+        rnLeaf  '\'
+        rnLeaf  ' '
+        rnLeaf  'this'
+      """)
+
+    check("""\\\ this""".toAst == dedent"""
+      rnInner
+        rnLeaf  '\'
+        rnLeaf  'this'
+      """)
+
+    check("""\\\\ this""".toAst == dedent"""
+      rnInner
+        rnLeaf  '\'
+        rnLeaf  '\'
+        rnLeaf  ' '
+        rnLeaf  'this'
+      """)
+
+suite "RST inline markup":
+  test "* and ** surrounded by spaces are not inline markup":
+    check("a * b * c ** d ** e".toAst == dedent"""
+      rnInner
+        rnLeaf  'a'
+        rnLeaf  ' '
+        rnLeaf  '*'
+        rnLeaf  ' '
+        rnLeaf  'b'
+        rnLeaf  ' '
+        rnLeaf  '*'
+        rnLeaf  ' '
+        rnLeaf  'c'
+        rnLeaf  ' '
+        rnLeaf  '**'
+        rnLeaf  ' '
+        rnLeaf  'd'
+        rnLeaf  ' '
+        rnLeaf  '**'
+        rnLeaf  ' '
+        rnLeaf  'e'
+      """)
+
+  test "end-string has repeating symbols":
+    check("*emphasis content****".toAst == dedent"""
+      rnEmphasis
+        rnLeaf  'emphasis'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '***'
+      """)
+
+    check("""*emphasis content\****""".toAst == dedent"""
+      rnEmphasis
+        rnLeaf  'emphasis'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '*'
+        rnLeaf  '**'
+      """)  # exact configuration of leafs with * is not really essential,
+            # only total number of * is essential
+
+    check("**strong content****".toAst == dedent"""
+      rnStrongEmphasis
+        rnLeaf  'strong'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '**'
+      """)
+
+    check("""**strong content*\****""".toAst == dedent"""
+      rnStrongEmphasis
+        rnLeaf  'strong'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '*'
+        rnLeaf  '*'
+        rnLeaf  '*'
+      """)
+
+    check("``lit content`````".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  'lit'
+        rnLeaf  ' '
+        rnLeaf  'content'
+        rnLeaf  '```'
+      """)
+
+  test "interpreted text parsing: code fragments":
+    check(dedent"""
+        .. default-role:: option
+
+        `--gc:refc`""".toAst ==
+      dedent"""
+        rnInner
+          rnDefaultRole
+            rnDirArg
+              rnLeaf  'option'
+            [nil]
+            [nil]
+          rnParagraph
+            rnCodeFragment
+              rnInner
+                rnLeaf  '--'
+                rnLeaf  'gc'
+                rnLeaf  ':'
+                rnLeaf  'refc'
+              rnLeaf  'option'
+        """)
+
+  test """interpreted text can be ended with \` """:
+    let output = (".. default-role:: literal\n" & """`\``""").toAst
+    check(output.endsWith """
+  rnParagraph
+    rnInlineLiteral
+      rnLeaf  '`'""" & "\n")
+
+    let output2 = """`\``""".toAst
+    check(output2 == dedent"""
+      rnInlineCode
+        rnDirArg
+          rnLeaf  'nim'
+        [nil]
+        rnLiteralBlock
+          rnLeaf  '`'
+      """)
+
+    let output3 = """`proc \`+\``""".toAst
+    check(output3 == dedent"""
+      rnInlineCode
+        rnDirArg
+          rnLeaf  'nim'
+        [nil]
+        rnLiteralBlock
+          rnLeaf  'proc `+`'
+      """)
+
+    check("""`\\`""".toAst ==
+      dedent"""
+        rnInlineCode
+          rnDirArg
+            rnLeaf  'nim'
+          [nil]
+          rnLiteralBlock
+            rnLeaf  '\\'
+        """)
+
+  test "Markdown-style code/backtick":
+    # no whitespace is required before `
+    check("`try`...`except`".toAst ==
+      dedent"""
+        rnInner
+          rnInlineCode
+            rnDirArg
+              rnLeaf  'nim'
+            [nil]
+            rnLiteralBlock
+              rnLeaf  'try'
+          rnLeaf  '...'
+          rnInlineCode
+            rnDirArg
+              rnLeaf  'nim'
+            [nil]
+            rnLiteralBlock
+              rnLeaf  'except'
+        """)
+
+
+  test """inline literals can contain \ anywhere""":
+    check("""``\``""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+      """)
+
+    check("""``\\``""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '\'
+      """)
+
+    check("""``\```""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '`'
+      """)
+
+    check("""``\\```""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '\'
+        rnLeaf  '`'
+      """)
+
+    check("""``\````""".toAst == dedent"""
+      rnInlineLiteral
+        rnLeaf  '\'
+        rnLeaf  '`'
+        rnLeaf  '`'
+      """)
+
+  test "references with _ at the end":
+    check(dedent"""
+      .. _lnk: https
+
+      lnk_""".toAst ==
+      dedent"""
+        rnHyperlink
+          rnInner
+            rnLeaf  'lnk'
+          rnInner
+            rnLeaf  'https'
+      """)
+
+  test "not a hyper link":
+    check(dedent"""
+      .. _lnk: https
+
+      lnk___""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'lnk'
+          rnLeaf  '___'
+      """)
+
+  test "no punctuation in the end of a standalone URI is allowed":
+    check(dedent"""
+        [see (http://no.org)], end""".toAst(rstOptions = preferRst) ==
+      dedent"""
+        rnInner
+          rnLeaf  '['
+          rnLeaf  'see'
+          rnLeaf  ' '
+          rnLeaf  '('
+          rnStandaloneHyperlink
+            rnLeaf  'http://no.org'
+          rnLeaf  ')'
+          rnLeaf  ']'
+          rnLeaf  ','
+          rnLeaf  ' '
+          rnLeaf  'end'
+        """)
+
+    # but `/` at the end is OK
+    check(
+      dedent"""
+        See http://no.org/ end""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'See'
+          rnLeaf  ' '
+          rnStandaloneHyperlink
+            rnLeaf  'http://no.org/'
+          rnLeaf  ' '
+          rnLeaf  'end'
+        """)
+
+    # a more complex URL with some made-up ending '&='.
+    # Github Markdown would include final &= and
+    # so would rst2html.py in contradiction with RST spec.
+    check(
+      dedent"""
+        See https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO&= end""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'See'
+          rnLeaf  ' '
+          rnStandaloneHyperlink
+            rnLeaf  'https://www.google.com/url?sa=t&source=web&cd=&cad=rja&url=https%3A%2F%2Fnim-lang.github.io%2FNim%2Frst.html%23features&usg=AO'
+          rnLeaf  '&'
+          rnLeaf  '='
+          rnLeaf  ' '
+          rnLeaf  'end'
+        """)
+
+  test "Markdown-style link can be split to a few lines":
+    check(dedent"""
+        is [term-rewriting
+        macros](manual.html#term-rewriting-macros)""".toAst ==
+      dedent"""
+        rnInner
+          rnLeaf  'is'
+          rnLeaf  ' '
+          rnHyperlink
+            rnLeaf  'term-rewriting macros'
+            rnLeaf  'manual.html#term-rewriting-macros'
+      """)
+
+  test "URL with balanced parentheses (Markdown rule)":
+    # 2 balanced parens, 1 unbalanced:
+    check(dedent"""
+        https://en.wikipedia.org/wiki/APL_((programming_language)))""".toAst ==
+      dedent"""
+        rnInner
+          rnStandaloneHyperlink
+            rnLeaf  'https://en.wikipedia.org/wiki/APL_((programming_language))'
+          rnLeaf  ')'
+      """)
+
+    # the same for Markdown-style link:
+    check(dedent"""
+        [foo [bar]](https://en.wikipedia.org/wiki/APL_((programming_language))))""".toAst ==
+      dedent"""
+        rnInner
+          rnHyperlink
+            rnLeaf  'foo [bar]'
+            rnLeaf  'https://en.wikipedia.org/wiki/APL_((programming_language))'
+          rnLeaf  ')'
+      """)
+
+    # unbalanced (here behavior is more RST-like actually):
+    check(dedent"""
+        https://en.wikipedia.org/wiki/APL_(programming_language(""".toAst ==
+      dedent"""
+        rnInner
+          rnStandaloneHyperlink
+            rnLeaf  'https://en.wikipedia.org/wiki/APL_(programming_language'
+          rnLeaf  '('
+      """)
+
+    # unbalanced [, but still acceptable:
+    check(dedent"""
+        [my {link example](http://example.com/bracket_(symbol_[))""".toAst ==
+      dedent"""
+        rnHyperlink
+          rnLeaf  'my {link example'
+          rnLeaf  'http://example.com/bracket_(symbol_[)'
+      """)
+
+  test "not a Markdown link":
+    # bug #17340 (27) `f` will be considered as a protocol and blocked as unsafe
+    var warnings = new seq[string]
+    check("[T](f: var Foo)".toAst(warnings = warnings) ==
+      dedent"""
+        rnInner
+          rnLeaf  '['
+          rnLeaf  'T'
+          rnLeaf  ']'
+          rnLeaf  '('
+          rnLeaf  'f'
+          rnLeaf  ':'
+          rnLeaf  ' '
+          rnLeaf  'var'
+          rnLeaf  ' '
+          rnLeaf  'Foo'
+          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
new file mode 100644
index 000000000..6253e7146
--- /dev/null
+++ b/tests/stdlib/trstgen.nim
@@ -0,0 +1,1692 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+outputsub: ""
+"""
+
+# tests for rstgen module.
+
+import ../../lib/packages/docutils/rstgen
+import ../../lib/packages/docutils/rst
+import unittest, strutils, strtabs
+import std/private/miscdollars
+import std/assertions
+
+const
+  NoSandboxOpts = {roPreferMarkdown, roSupportMarkdown, roNimFile, roSandboxDisabled}
+  preferMarkdown = {roPreferMarkdown, roSupportMarkdown, roNimFile}
+  preferRst = {roSupportMarkdown, roNimFile}
+
+proc toHtml(input: string,
+            rstOptions: RstParseOptions = preferMarkdown,
+            error: ref string = nil,
+            warnings: ref seq[string] = nil): string =
+  ## If `error` is nil then no errors should be generated.
+  ## The same goes for `warnings`.
+  proc testMsgHandler(filename: string, line, col: int, msgkind: MsgKind,
+                      arg: string) =
+    let mc = msgkind.whichMsgClass
+    let a = $msgkind % arg
+    var message: string
+    toLocation(message, filename, line, col + ColRstOffset)
+    message.add " $1: $2" % [$mc, a]
+    if mc == mcError:
+      if error == nil:
+        raise newException(EParseError, "[unexpected error] " & message)
+      error[] = message
+      # we check only first error because subsequent ones may be meaningless
+      raise newException(EParseError, "")
+    else:
+      doAssert warnings != nil, "unexpected RST warning '" & message & "'"
+      warnings[].add message
+  try:
+    result = rstToHtml(input, rstOptions, defaultConfig(),
+                       msgHandler=testMsgHandler)
+  except EParseError as e:
+    if e.msg != "":
+      result = e.msg
+
+# inline code tags (for parsing originated from highlite.nim)
+proc id(str: string): string = """<span class="Identifier">"""  & str & "</span>"
+proc op(str: string): string = """<span class="Operator">"""    & str & "</span>"
+proc pu(str: string): string = """<span class="Punctuation">""" & str & "</span>"
+proc optionListLabel(opt: string): string =
+  """<div class="option-list-label"><tt><span class="option">""" &
+  opt &
+  "</span></tt></div>"
+
+
+suite "YAML syntax highlighting":
+  test "Basics":
+    let input = """.. code-block:: yaml
+    %YAML 1.2
+    ---
+    a string: string
+    a list:
+      - item 1
+      - item 2
+    a map:
+    ? key
+    : value
+    ..."""
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
+<span class="Keyword">---</span>
+<span class="StringLit">a string</span><span class="Punctuation">:</span> <span class="StringLit">string</span>
+<span class="StringLit">a list</span><span class="Punctuation">:</span>
+  <span class="Punctuation">-</span> <span class="StringLit">item 1</span>
+  <span class="Punctuation">-</span> <span class="StringLit">item 2</span>
+<span class="StringLit">a map</span><span class="Punctuation">:</span>
+<span class="Punctuation">?</span> <span class="StringLit">key</span>
+<span class="Punctuation">:</span> <span class="StringLit">value</span>
+<span class="Keyword">...</span></pre>"""
+
+  test "Block scalars":
+    let input = """.. code-block:: yaml
+    a literal block scalar: |
+      some text
+      # not a comment
+     # a comment, since less indented
+      # another comment
+    a folded block scalar: >2
+       some text
+      # not a comment since indented as specified
+     # a comment
+    another literal block scalar:
+      |+ # comment after header
+     allowed, since more indented than parent"""
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="StringLit">a literal block scalar</span><span class="Punctuation">:</span> <span class="Command">|</span><span class="Command"></span><span class="LongStringLit">
+  some text
+  # not a comment
+ </span><span class="Comment"># a comment, since less indented</span>
+  <span class="Comment"># another comment</span>
+<span class="StringLit">a folded block scalar</span><span class="Punctuation">:</span> <span class="Command">&gt;2</span><span class="Command"></span><span class="LongStringLit">
+   some text
+  # not a comment since indented as specified
+ </span><span class="Comment"># a comment</span>
+<span class="StringLit">another literal block scalar</span><span class="Punctuation">:</span>
+  <span class="Command">|+</span> <span class="Comment"># comment after header</span><span class="LongStringLit">
+ allowed, since more indented than parent</span></pre>"""
+
+  test "Directives":
+    let input = """.. code-block:: yaml
+    %YAML 1.2
+    ---
+    %not a directive
+    ...
+    %a directive
+    ...
+    a string
+    % not a directive
+    ...
+    %TAG ! !foo:"""
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Directive">%YAML 1.2</span>
+<span class="Keyword">---</span>
+<span class="StringLit">%not a directive</span>
+<span class="Keyword">...</span>
+<span class="Directive">%a directive</span>
+<span class="Keyword">...</span>
+<span class="StringLit">a string</span>
+<span class="StringLit">% not a directive</span>
+<span class="Keyword">...</span>
+<span class="Directive">%TAG ! !foo:</span></pre>"""
+
+  test "Flow Style and Numbers":
+    let input = """.. code-block:: yaml
+    {
+      "quoted string": 42,
+      'single quoted string': false,
+      [ list, "with", 'entries' ]: 73.32e-73,
+      more numbers: [-783, 11e78],
+      not numbers: [ 42e, 0023, +32.37, 8 ball]
+    }"""
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Punctuation">{</span>
+  <span class="StringLit">&quot;</span><span class="StringLit">quoted string&quot;</span><span class="Punctuation">:</span> <span class="DecNumber">42</span><span class="Punctuation">,</span>
+  <span class="StringLit">'single quoted string'</span><span class="Punctuation">:</span> <span class="StringLit">false</span><span class="Punctuation">,</span>
+  <span class="Punctuation">[</span> <span class="StringLit">list</span><span class="Punctuation">,</span> <span class="StringLit">&quot;</span><span class="StringLit">with&quot;</span><span class="Punctuation">,</span> <span class="StringLit">'entries'</span> <span class="Punctuation">]</span><span class="Punctuation">:</span> <span class="FloatNumber">73.32e-73</span><span class="Punctuation">,</span>
+  <span class="StringLit">more numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span><span class="DecNumber">-783</span><span class="Punctuation">,</span> <span class="FloatNumber">11e78</span><span class="Punctuation">]</span><span class="Punctuation">,</span>
+  <span class="StringLit">not numbers</span><span class="Punctuation">:</span> <span class="Punctuation">[</span> <span class="StringLit">42e</span><span class="Punctuation">,</span> <span class="StringLit">0023</span><span class="Punctuation">,</span> <span class="StringLit">+32.37</span><span class="Punctuation">,</span> <span class="StringLit">8 ball</span><span class="Punctuation">]</span>
+<span class="Punctuation">}</span></pre>"""
+
+  test "Directives: warnings":
+    let input = dedent"""
+      .. non-existent-warning: Paragraph.
+
+      .. another.wrong:warning::: Paragraph.
+      """
+    var warnings = new seq[string]
+    let output = input.toHtml(warnings=warnings)
+    check output == ""
+    doAssert warnings[].len == 2
+    check "(1, 24) Warning: RST style:" in warnings[0]
+    check "double colon :: may be missing at end of 'non-existent-warning'" in warnings[0]
+    check "(3, 25) Warning: RST style:" in warnings[1]
+    check "RST style: too many colons for a directive (should be ::)" in warnings[1]
+
+  test "not a directive":
+    let input = "..warning:: I am not a warning."
+    check input.toHtml == input
+
+  test "Anchors, Aliases, Tags":
+    let input = """.. code-block:: yaml
+    --- !!map
+    !!str string: !<tag:yaml.org,2002:int> 42
+    ? &anchor !!seq []:
+    : !localtag foo
+    alias: *anchor
+    """
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Keyword">---</span> <span class="TagStart">!!map</span>
+<span class="TagStart">!!str</span> <span class="StringLit">string</span><span class="Punctuation">:</span> <span class="TagStart">!&lt;tag:yaml.org,2002:int&gt;</span> <span class="DecNumber">42</span>
+<span class="Punctuation">?</span> <span class="Label">&amp;anchor</span> <span class="TagStart">!!seq</span> <span class="Punctuation">[</span><span class="Punctuation">]</span><span class="Punctuation">:</span>
+<span class="Punctuation">:</span> <span class="TagStart">!localtag</span> <span class="StringLit">foo</span>
+<span class="StringLit">alias</span><span class="Punctuation">:</span> <span class="Reference">*anchor</span></pre>"""
+
+  test "Edge cases":
+    let input = """.. code-block:: yaml
+    ...
+     %a string:
+      a:string:not:a:map
+    ...
+    not a list:
+      -2
+      -3
+      -4
+    example.com/not/a#comment:
+      ?not a map key
+    """
+    let output = input.toHtml({})
+    doAssert output == """<pre class = "listing"><span class="Keyword">...</span>
+ <span class="StringLit">%a string</span><span class="Punctuation">:</span>
+  <span class="StringLit">a:string:not:a:map</span>
+<span class="Keyword">...</span>
+<span class="StringLit">not a list</span><span class="Punctuation">:</span>
+  <span class="DecNumber">-2</span>
+  <span class="DecNumber">-3</span>
+  <span class="DecNumber">-4</span>
+<span class="StringLit">example.com/not/a#comment</span><span class="Punctuation">:</span>
+  <span class="StringLit">?not a map key</span></pre>"""
+
+
+suite "RST/Markdown general":
+  test "RST emphasis":
+    doAssert rstToHtml("*Hello* **world**!", {},
+      newStringTable(modeStyleInsensitive)) ==
+      "<em>Hello</em> <strong>world</strong>!"
+
+  test "Markdown links":
+    check("(( [Nim](https://nim-lang.org/) ))".toHtml ==
+        """(( <a class="reference external" href="https://nim-lang.org/">Nim</a> ))""")
+    check("(([Nim](https://nim-lang.org/)))".toHtml ==
+        """((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
+    check("[[Nim](https://nim-lang.org/)]".toHtml ==
+        """[<a class="reference external" href="https://nim-lang.org/">Nim</a>]""")
+
+  test "Markdown tables":
+    let input1 = """
+| A1 header    | A2 \| not fooled
+| :---         | ----:       |
+| C1           | C2 **bold** | ignored |
+| D1 `code \|` | D2          | also ignored
+| E1 \| text   |
+|              | F2 without pipe
+not in table"""
+    let output1 = input1.toHtml
+    #[
+    TODO: `\|` inside a table cell should render as `|`
+        `|` outside a table cell should render as `\|`
+    consistently with markdown, see https://stackoverflow.com/a/66557930/1426932
+    ]#
+    check(output1 == """
+<table border="1" class="docutils"><tr><th>A1 header</th><th>A2 | not fooled</th></tr>
+<tr><td>C1</td><td>C2 <strong>bold</strong></td></tr>
+<tr><td>D1 <tt class="docutils literal"><span class="pre">""" & id"code" & " " & op"\|" & """</span></tt></td><td>D2</td></tr>
+<tr><td>E1 | text</td><td></td></tr>
+<tr><td></td><td>F2 without pipe</td></tr>
+</table><p>not in table</p>""")
+    let input2 = """
+| A1 header | A2 |
+| --- | --- |"""
+    let output2 = input2.toHtml
+    doAssert output2 == """<table border="1" class="docutils"><tr><th>A1 header</th><th>A2</th></tr>
+</table>"""
+
+  test "RST tables":
+    let input1 = """
+Test 2 column/4 rows table:
+====   ===
+H0     H1
+====   ===
+A0     A1
+====   ===
+A2     A3
+====   ===
+A4     A5
+====   === """
+    let output1 = rstToLatex(input1, {})
+    doAssert "{LL}" in output1  # 2 columns
+    doAssert count(output1, "\\\\") == 4  # 4 rows
+    for cell in ["H0", "H1", "A0", "A1", "A2", "A3", "A4", "A5"]:
+      doAssert cell in output1
+
+    let input2 = """
+Now test 3 columns / 2 rows, and also borders containing 4 =, 3 =, 1 = signs:
+
+====   ===  =
+H0     H1   H
+====   ===  =
+A0     A1   X
+       Ax   Y
+====   ===  = """
+    let output2 = rstToLatex(input2, {})
+    doAssert "{LLL}" in output2  # 3 columns
+    doAssert count(output2, "\\\\") == 2  # 2 rows
+    for cell in ["H0", "H1", "H", "A0", "A1", "X", "Ax", "Y"]:
+      doAssert cell in output2
+
+
+  test "RST adornments":
+    let input1 = """
+Check that a few punctuation symbols are not parsed as adornments:
+:word1: word2 .... word3 """
+    let output1 = input1.toHtml
+    discard output1
+
+  test "RST sections":
+    let input1 = """
+Long chapter name
+'''''''''''''''''''
+"""
+    let output1 = input1.toHtml
+    doAssert "Long chapter name" in output1 and "<h1" in output1
+
+    let input2 = """
+Short chapter name:
+
+ChA
+===
+"""
+    let output2 = input2.toHtml
+    doAssert "ChA" in output2 and "<h1" in output2
+
+    let input3 = """
+Very short chapter name:
+
+X
+~
+"""
+    let output3 = input3.toHtml
+    doAssert "X" in output3 and "<h1" in output3
+
+    let input4 = """
+Check that short underline is not enough to make section:
+
+Wrong chapter
+------------
+
+"""
+    var error4 = new string
+    let output4 = input4.toHtml(error = error4)
+    check(error4[] == "input(3, 1) Error: new section expected (underline " &
+            "\'------------\' is too short)")
+
+    let input5 = """
+Check that punctuation after adornment and indent are not detected as adornment.
+
+Some chapter
+--------------
+
+  "punctuation symbols" """
+    let output5 = input5.toHtml
+    doAssert "&quot;punctuation symbols&quot;" in output5 and "<h1" in output5
+
+    # check that EOF after adornment does not prevent it parsing as heading
+    let input6 = dedent """
+      Some chapter
+      ------------"""
+    let output6 = input6.toHtml
+    doAssert "<h1 id=\"some-chapter\">Some chapter</h1>" in output6
+
+    # check that overline and underline match
+    let input7 = dedent """
+      ------------
+      Some chapter
+      -----------
+      """
+    var error7 = new string
+    let output7 = input7.toHtml(error=error7)
+    check(error7[] == "input(1, 1) Error: new section expected (underline " &
+            "\'-----------\' does not match overline \'------------\')")
+
+    let input8 = dedent """
+      -----------
+          Overflow
+      -----------
+      """
+    var error8 = new string
+    let output8 = input8.toHtml(error=error8)
+    check(error8[] == "input(1, 1) Error: new section expected (overline " &
+            "\'-----------\' is too short)")
+
+    # check that hierarchy of title styles works
+    let input9good = dedent """
+      Level1
+      ======
+
+      Level2
+      ------
+
+      Level3
+      ~~~~~~
+
+      L1
+      ==
+
+      Another2
+      --------
+
+      More3
+      ~~~~~
+
+      """
+    let output9good = input9good.toHtml(preferRst)
+    doAssert "<h1 id=\"level1\">Level1</h1>" in output9good
+    doAssert "<h2 id=\"level2\">Level2</h2>" in output9good
+    doAssert "<h3 id=\"level3\">Level3</h3>" in output9good
+    doAssert "<h1 id=\"l1\">L1</h1>" in output9good
+    doAssert "<h2 id=\"another2\">Another2</h2>" in output9good
+    doAssert "<h3 id=\"more3\">More3</h3>" in output9good
+
+    # check that swap causes an exception
+    let input9Bad = dedent """
+      Level1
+      ======
+
+      Level2
+      ------
+
+      Level3
+      ~~~~~~
+
+      L1
+      ==
+
+      More
+      ~~~~
+
+      Another
+      -------
+
+      """
+    var error9Bad = new string
+    let output9Bad = input9Bad.toHtml(preferRst, error=error9Bad)
+    check(error9Bad[] == "input(15, 1) Error: new section expected (section " &
+            "level inconsistent: underline ~~~~~ unexpectedly found, while " &
+            "the following intermediate section level(s) are missing on " &
+            "lines 12..15: underline -----)")
+
+  test "RST sections overline":
+    # the same as input9good but with overline headings
+    # first overline heading has a special meaning: document title
+    let input = dedent """
+      ======
+      Title0
+      ======
+
+      +++++++++
+      SubTitle0
+      +++++++++
+
+      ------
+      Level1
+      ------
+
+      Level2
+      ------
+
+      ~~~~~~
+      Level3
+      ~~~~~~
+
+      --
+      L1
+      --
+
+      Another2
+      --------
+
+      ~~~~~
+      More3
+      ~~~~~
+
+      """
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames = files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == "Title0"
+    doAssert rstGenera.meta[metaSubtitle] == "SubTitle0"
+    doAssert "<h1 id=\"level1\"><center>Level1</center></h1>" in output
+    doAssert "<h2 id=\"level2\">Level2</h2>" in output
+    doAssert "<h3 id=\"level3\"><center>Level3</center></h3>" in output
+    doAssert "<h1 id=\"l1\"><center>L1</center></h1>" in output
+    doAssert "<h2 id=\"another2\">Another2</h2>" in output
+    doAssert "<h3 id=\"more3\"><center>More3</center></h3>" in output
+
+  test "RST sections overline 2":
+    # check that a paragraph prevents interpreting overlines as document titles
+    let input = dedent """
+      Paragraph
+
+      ======
+      Title0
+      ======
+
+      +++++++++
+      SubTitle0
+      +++++++++
+      """
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == ""
+    doAssert rstGenera.meta[metaSubtitle] == ""
+    doAssert "<h1 id=\"title0\"><center>Title0</center></h1>" in output
+    doAssert "<h2 id=\"subtitle0\"><center>SubTitle0</center></h2>" in output
+
+  test "RST+Markdown sections":
+    # check that RST and Markdown headings don't interfere
+    let input = dedent """
+      ======
+      Title0
+      ======
+
+      MySection1a
+      +++++++++++
+
+      # MySection1b
+
+      MySection1c
+      +++++++++++
+
+      ##### MySection5a
+
+      MySection2a
+      -----------
+      """
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {roSupportMarkdown})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == "Title0"
+    doAssert rstGenera.meta[metaSubtitle] == ""
+    doAssert output ==
+             "\n<h1 id=\"mysection1a\">MySection1a</h1>" & # RST
+             "\n<h1 id=\"mysection1b\">MySection1b</h1>" & # Markdown
+             "\n<h1 id=\"mysection1c\">MySection1c</h1>" & # RST
+             "\n<h5 id=\"mysection5a\">MySection5a</h5>" & # Markdown
+             "\n<h2 id=\"mysection2a\">MySection2a</h2>"   # RST
+
+  test "RST inline text":
+    let input1 = "GC_step"
+    let output1 = input1.toHtml
+    doAssert output1 == "GC_step"
+
+  test "RST anchors/links to headings":
+    # Currently in TOC mode anchors are modified (for making links from
+    # the TOC unique)
+    let inputNoToc = dedent"""
+        Type relations
+        ==============
+
+        Convertible relation
+        --------------------
+
+        Ref. `Convertible relation`_
+        """
+    let outputNoToc = inputNoToc.toHtml
+    check outputNoToc.count("id=\"type-relations\"") == 1
+    check outputNoToc.count("id=\"convertible-relation\"") == 1
+    check outputNoToc.count("href=\"#convertible-relation\"") == 1
+
+    let inputTocCases = @[
+      dedent"""
+        .. contents::
+
+        Type relations
+        ==============
+
+        Convertible relation
+        --------------------
+
+        Ref. `Convertible relation`_
+
+        Guards and locks
+        ================
+        """,
+      dedent"""
+        Ref. `Convertible relation`_
+
+        .. contents::
+
+        Type relations
+        ==============
+
+        Convertible relation
+        --------------------
+
+        Guards and locks
+        ================
+        """
+    ]
+    for inputToc in inputTocCases:
+      let outputToc = inputToc.toHtml
+      check outputToc.count("id=\"type-relations\"") == 1
+      check outputToc.count("id=\"type-relations-convertible-relation\"") == 1
+      check outputToc.count("id=\"convertible-relation\">") == 0
+      # Besides "Ref.", heading also contains link to itself:
+      check outputToc.count(
+          "href=\"#type-relations-convertible-relation\">") == 2
+      check outputToc.count("href=\"#convertible-relation\"") == 0
+
+  test "RST links":
+    let input1 = """
+Want to learn about `my favorite programming language`_?
+
+.. _my favorite programming language: https://nim-lang.org"""
+    let output1 = input1.toHtml
+    doAssert "<a" in output1 and "href=\"https://nim-lang.org\"" in output1
+
+  test "RST transitions":
+    let input1 = """
+context1
+
+~~~~
+
+context2
+"""
+    let output1 = input1.toHtml(preferRst)
+    doAssert "<hr" in output1
+
+    let input2 = """
+This is too short to be a transition:
+
+---
+context2
+---
+"""
+    var error2 = new string
+    let output2 = input2.toHtml(error=error2)
+    check(error2[] == "input(3, 1) Error: new section expected (overline " &
+            "\'---\' is too short)")
+
+  test "RST literal block":
+    let input1 = """
+Test literal block
+
+::
+
+  check """
+    let output1 = input1.toHtml(preferRst)
+    doAssert "<pre>" in output1
+
+  test "Markdown code block":
+    let input1 = """
+```
+let x = 1
+``` """
+    let output1 = input1.toHtml({roSupportMarkdown, roPreferMarkdown})
+    doAssert "<pre" in output1 and "class=\"Keyword\"" notin output1
+
+    # Check Nim highlighting by default in .nim files:
+    let output1nim = input1.toHtml({roSupportMarkdown, roPreferMarkdown,
+                                    roNimFile})
+    doAssert "<pre" in output1nim and "class=\"Keyword\"" in output1nim
+
+    let input2 = """
+Parse the block with language specifier:
+```Nim
+let x = 1
+``` """
+    let output2 = input2.toHtml
+    doAssert "<pre" in output2 and "class=\"Keyword\"" in output2
+
+  test "interpreted text":
+    check("""`foo.bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"foo" & op"." & id"bar" & "</span></tt>")
+    check("""`foo\`\`bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"foo" & pu"`" & pu"`" & id"bar" & "</span></tt>")
+    check("""`foo\`bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"foo" & pu"`" & id"bar" & "</span></tt>")
+    check("""`\`bar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      pu"`" & id"bar" & "</span></tt>")
+    check("""`a\b\x\\ar`""".toHtml ==
+      """<tt class="docutils literal"><span class="pre">""" &
+      id"a" & op"""\""" & id"b" & op"""\""" & id"x" & op"""\\""" & id"ar" &
+      "</span></tt>")
+
+  test "inline literal":
+    check """``foo.bar``""".toHtml == """<tt class="docutils literal"><span class="pre">foo.bar</span></tt>"""
+    check """``foo\bar``""".toHtml == """<tt class="docutils literal"><span class="pre">foo\bar</span></tt>"""
+    check """``f\`o\\o\b`ar``""".toHtml == """<tt class="docutils literal"><span class="pre">f\`o\\o\b`ar</span></tt>"""
+
+  test "default-role":
+    # nim(default) -> literal -> nim -> code(=literal)
+    let input = dedent"""
+      Par1 `value1`.
+
+      .. default-role:: literal
+
+      Par2 `value2`.
+
+      .. default-role:: nim
+
+      Par3 `value3`.
+
+      .. default-role:: code
+
+      Par4 `value4`."""
+    let p1 = """Par1 <tt class="docutils literal"><span class="pre">""" & id"value1" & "</span></tt>."
+    let p2 = """<p>Par2 <tt class="docutils literal"><span class="pre">value2</span></tt>.</p>"""
+    let p3 = """<p>Par3 <tt class="docutils literal"><span class="pre">""" & id"value3" & "</span></tt>.</p>"
+    let p4 = """<p>Par4 <tt class="docutils literal"><span class="pre">value4</span></tt>.</p>"""
+    let expected = p1 & p2 & "\n" & p3 & "\n" & p4
+    check(
+      input.toHtml(NoSandboxOpts) == expected
+    )
+
+  test "role directive":
+    let input = dedent"""
+      .. role:: y(code)
+         :language: yaml
+
+      .. role:: brainhelp(code)
+         :language: brainhelp
+    """
+    var warnings = new seq[string]
+    let output = input.toHtml(
+      NoSandboxOpts,
+      warnings=warnings
+    )
+    check(warnings[].len == 1 and "language 'brainhelp' not supported" in warnings[0])
+
+  test "RST comments":
+    let input1 = """
+
+Check that comment disappears:
+
+..
+  some comment """
+    let output1 = input1.toHtml
+    doAssert output1 == "Check that comment disappears:"
+
+  test "RST line blocks + headings":
+    let input = """
+=====
+Test1
+=====
+
+|
+|
+| line block
+| other line
+
+"""
+    var rstGenera: RstGenerator
+    var output: string
+    let (rst, files, _) = rstParse(input, "", 1, 1, {})
+    rstGenera.initRstGenerator(outHtml, defaultConfig(), "input", filenames=files)
+    rstGenera.renderRstToOut(rst, output)
+    doAssert rstGenera.meta[metaTitle] == "Test1"
+      # check that title was not overwritten to '|'
+    doAssert output == "<p><br/><br/>line block<br/>other line<br/></p>"
+    let output1l = rstToLatex(input, {})
+    doAssert "line block\n\n" in output1l
+    doAssert "other line\n\n" in output1l
+    doAssert output1l.count("\\vspace") == 2 + 2  # +2 surrounding paddings
+
+  test "RST line blocks":
+    let input2 = dedent"""
+      Paragraph1
+
+      |
+
+      Paragraph2"""
+
+    let output2 = input2.toHtml
+    doAssert "Paragraph1<p><br/></p> <p>Paragraph2</p>" == output2
+
+    let input3 = dedent"""
+      | xxx
+      |   yyy
+      |     zzz"""
+
+    let output3 = input3.toHtml
+    doAssert "xxx<br/>" in output3
+    doAssert "<span style=\"margin-left: 1.0em\">yyy</span><br/>" in output3
+    doAssert "<span style=\"margin-left: 2.0em\">zzz</span><br/>" in output3
+
+    # check that '|   ' with a few spaces is still parsed as new line
+    let input4 = dedent"""
+      | xxx
+      |
+      |     zzz"""
+
+    let output4 = input4.toHtml
+    doAssert "xxx<br/><br/>" in output4
+    doAssert "<span style=\"margin-left: 2.0em\">zzz</span><br/>" in output4
+
+  test "RST enumerated lists":
+    let input1 = dedent """
+      1. line1
+         1
+      2. line2
+         2
+
+      3. line3
+         3
+
+
+      4. line4
+         4
+
+
+
+      5. line5
+         5
+      """
+    let output1 = input1.toHtml
+    for i in 1..5:
+      doAssert ($i & ". line" & $i) notin output1
+      doAssert ("<li>line" & $i & " " & $i & "</li>") in output1
+
+    let input2 = dedent """
+      3. line3
+
+      4. line4
+
+
+      5. line5
+
+
+
+      7. line7
+
+
+
+
+      8. line8
+      """
+    let output2 = input2.toHtml
+    for i in [3, 4, 5, 7, 8]:
+      doAssert ($i & ". line" & $i) notin output2
+      doAssert ("<li>line" & $i & "</li>") in output2
+
+    # check that nested enumerated lists work
+    let input3 = dedent """
+      1.  a) string1
+      2. string2
+      """
+    let output3 = input3.toHtml
+    doAssert count(output3, "<ol ") == 2
+    doAssert count(output3, "</ol>") == 2
+    doAssert "<li>string1</li>" in output3 and "<li>string2</li>" in output3
+
+    let input4 = dedent """
+      Check that enumeration specifiers are respected
+
+      9. string1
+      10. string2
+      12. string3
+
+      b) string4
+      c) string5
+      e) string6
+      """
+    let output4 = input4.toHtml
+    doAssert count(output4, "<ol ") == 4
+    doAssert count(output4, "</ol>") == 4
+    for enumerator in [9, 12]:
+      doAssert "start=\"$1\"" % [$enumerator] in output4
+    for enumerator in [2, 5]:  # 2=b, 5=e
+      doAssert "start=\"$1\"" % [$enumerator] in output4
+
+    let input5 = dedent """
+      Check that auto-numbered enumeration lists work.
+
+      #. string1
+
+      #. string2
+
+      #. string3
+
+      #) string5
+      #) string6
+      """
+    let output5 = input5.toHtml
+    doAssert count(output5, "<ol ") == 2
+    doAssert count(output5, "</ol>") == 2
+    doAssert count(output5, "<li>") == 5
+
+    let input5a = dedent """
+      Auto-numbered RST list can start with 1 even when Markdown support is on.
+
+      1. string1
+      #. string2
+      #. string3
+      """
+    let output5a = input5a.toHtml
+    doAssert count(output5a, "<ol ") == 1
+    doAssert count(output5a, "</ol>") == 1
+    doAssert count(output5a, "<li>") == 3
+
+    let input6 = dedent """
+      ... And for alphabetic enumerators too!
+
+      b. string1
+      #. string2
+      #. string3
+      """
+    let output6 = input6.toHtml
+    doAssert count(output6, "<ol ") == 1
+    doAssert count(output6, "</ol>") == 1
+    doAssert count(output6, "<li>") == 3
+    doAssert "start=\"2\"" in output6 and "class=\"loweralpha simple\"" in output6
+
+    let input7 = dedent """
+      ... And for uppercase alphabetic enumerators.
+
+      C. string1
+      #. string2
+      #. string3
+      """
+    let output7 = input7.toHtml
+    doAssert count(output7, "<ol ") == 1
+    doAssert count(output7, "</ol>") == 1
+    doAssert count(output7, "<li>") == 3
+    doAssert "start=\"3\"" in output7 and "class=\"upperalpha simple\"" in output7
+
+    # check that it's not recognized as enum.list without indentation on 2nd line
+    let input8 = dedent """
+      Paragraph.
+
+      A. stringA
+      B. stringB
+      C. string1
+      string2
+      """
+    var warnings8 = new seq[string]
+    let output8 = input8.toHtml(warnings = warnings8)
+    check(warnings8[].len == 1)
+    check("input(6, 1) Warning: RST style: \n" &
+          "not enough indentation on line 6" in warnings8[0])
+    doAssert output8 == "Paragraph.<ol class=\"upperalpha simple\">" &
+        "<li>stringA</li>\n<li>stringB</li>\n</ol>\n<p>C. string1 string2 </p>"
+
+  test "Markdown enumerated lists":
+    let input1 = dedent """
+      Below are 2 enumerated lists: Markdown-style (5 items) and RST (1 item)
+      1. line1
+      1. line2
+      1. line3
+      1. line4
+
+      1. line5
+
+      #. lineA
+      """
+    let output1 = input1.toHtml
+    for i in 1..5:
+      doAssert ($i & ". line" & $i) notin output1
+      doAssert ("<li>line" & $i & "</li>") in output1
+    doAssert count(output1, "<ol ") == 2
+    doAssert count(output1, "</ol>") == 2
+
+  test "RST bullet lists":
+    let input1 = dedent """
+      * line1
+        1
+      * line2
+        2
+
+      * line3
+        3
+
+
+      * line4
+        4
+
+
+
+      * line5
+        5
+      """
+    let output1 = input1.toHtml
+    for i in 1..5:
+      doAssert ("<li>line" & $i & " " & $i & "</li>") in output1
+    doAssert count(output1, "<ul ") == 1
+    doAssert count(output1, "</ul>") == 1
+
+  test "Nim RST footnotes and citations":
+    # check that auto-label footnote enumerated properly after a manual one
+    let input1 = dedent """
+      .. [1] Body1.
+      .. [#note] Body2
+
+      Ref. [#note]_
+      """
+    let output1 = input1.toHtml(preferRst)
+    doAssert output1.count(">[1]</a>") == 1
+    doAssert output1.count(">[2]</a>") == 2
+    doAssert "href=\"#footnote-note\"" in output1
+    doAssert ">[-1]" notin output1
+    doAssert "Body1." in output1
+    doAssert "Body2" in output1
+
+    # check that there are NO footnotes/citations, only comments:
+    let input2 = dedent """
+      .. [1 #] Body1.
+      .. [# note] Body2.
+      .. [wrong citation] That gives you a comment.
+
+      .. [not&allowed] That gives you a comment.
+
+      Not references[#note]_[1 #]_ [wrong citation]_ and [not&allowed]_.
+      """
+    let output2 = input2.toHtml(preferRst)
+    doAssert output2 == "Not references[#note]_[1 #]_ [wrong citation]_ and [not&amp;allowed]_."
+
+    # check that auto-symbol footnotes work:
+    let input3 = dedent """
+      Ref. [*]_ and [*]_ and [*]_.
+
+      .. [*] Body1
+      .. [*] Body2.
+
+
+      .. [*] Body3.
+      .. [*] Body4
+
+      And [*]_.
+      """
+    let output3 = input3.toHtml(preferRst)
+    # both references and footnotes. Footnotes have link to themselves.
+    doAssert output3.count("href=\"#footnotesym-1\">[*]</a>") == 2
+    doAssert output3.count("href=\"#footnotesym-2\">[**]</a>") == 2
+    doAssert output3.count("href=\"#footnotesym-3\">[***]</a>") == 2
+    doAssert output3.count("href=\"#footnotesym-4\">[^]</a>") == 2
+    # footnote group
+    doAssert output3.count("<hr class=\"footnote\">" &
+                           "<div class=\"footnote-group\">") == 1
+    # footnotes
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-1\">[*]</a></strong></sup></div>") == 1
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-2\">[**]</a></strong></sup></div>") == 1
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-3\">[***]</a></strong></sup></div>") == 1
+    doAssert output3.count("<div class=\"footnote-label\"><sup><strong>" &
+               "<a href=\"#footnotesym-4\">[^]</a></strong></sup></div>") == 1
+    for i in 1 .. 4: doAssert ("Body" & $i) in output3
+
+    # check manual, auto-number and auto-label footnote enumeration
+    let input4 = dedent """
+      .. [3] Manual1.
+      .. [#] Auto-number1.
+      .. [#mylabel] Auto-label1.
+      .. [#note] Auto-label2.
+      .. [#] Auto-number2.
+
+      Ref. [#note]_ and [#]_ and [#]_.
+      """
+    let output4 = input4.toHtml(preferRst)
+    doAssert ">[-1]" notin output1
+    let order = @[
+        "footnote-3", "[3]", "Manual1.",
+        "footnoteauto-1", "[1]", "Auto-number1",
+        "footnote-mylabel", "[2]", "Auto-label1",
+        "footnote-note", "[4]", "Auto-label2",
+        "footnoteauto-2", "[5]", "Auto-number2",
+        ]
+    for i in 0 .. order.len-2:
+      let pos1 = output4.find(order[i])
+      let pos2 = output4.find(order[i+1])
+      doAssert pos1 >= 0
+      doAssert pos2 >= 0
+      doAssert pos1 < pos2
+
+    # forgot [#]_
+    let input5 = dedent """
+      .. [3] Manual1.
+      .. [#] Auto-number1.
+      .. [#note] Auto-label2.
+
+      Ref. [#note]_
+      """
+    var error5 = new string
+    let output5 = input5.toHtml(preferRst, error=error5)
+    check(error5[] == "input(1, 1) Error: mismatch in number of footnotes " &
+            "and their refs: 1 (lines 2) != 0 (lines ) for auto-numbered " &
+            "footnotes")
+
+    # extra [*]_
+    let input6 = dedent """
+      Ref. [*]_
+
+      .. [*] Auto-Symbol.
+
+      Ref. [*]_
+      """
+    var error6 = new string
+    let output6 = input6.toHtml(preferRst, error=error6)
+    check(error6[] == "input(1, 1) Error: mismatch in number of footnotes " &
+            "and their refs: 1 (lines 3) != 2 (lines 2, 6) for auto-symbol " &
+            "footnotes")
+
+    let input7 = dedent """
+      .. [Some:CITATION-2020] Citation.
+
+      Ref. [some:citation-2020]_.
+      """
+    let output7 = input7.toHtml(preferRst)
+    doAssert output7.count("href=\"#citation-somecoloncitationminus2020\"") == 2
+    doAssert output7.count("[Some:CITATION-2020]") == 1
+    doAssert output7.count("[some:citation-2020]") == 1
+    doAssert output3.count("<hr class=\"footnote\">" &
+                           "<div class=\"footnote-group\">") == 1
+
+    let input8 = dedent """
+      .. [Some] Citation.
+
+      Ref. [som]_.
+      """
+    var warnings8 = new seq[string]
+    let output8 = input8.toHtml(preferRst, warnings=warnings8)
+    check(warnings8[] == @["input(3, 7) Warning: broken link 'citation-som'"])
+
+    # check that footnote group does not break parsing of other directives:
+    let input9 = dedent """
+      .. [Some] Citation.
+
+      .. _`internal anchor`:
+
+      .. [Another] Citation.
+      .. just comment.
+      .. [Third] Citation.
+
+      Paragraph1.
+
+      Paragraph2 ref `internal anchor`_.
+      """
+    let output9 = input9.toHtml(preferRst)
+    # _`internal anchor` got erased:
+    check "href=\"#internal-anchor\"" notin output9
+    check "href=\"#citation-another\"" in output9
+    doAssert output9.count("<hr class=\"footnote\">" &
+                           "<div class=\"footnote-group\">") == 1
+    doAssert output9.count("<div class=\"footnote-label\">") == 3
+    doAssert "just comment" notin output9
+
+    # check that nested citations/footnotes work
+    let input10 = dedent """
+      Paragraph1 [#]_.
+
+      .. [First] Citation.
+
+         .. [#] Footnote.
+
+            .. [Third] Citation.
+      """
+    let output10 = input10.toHtml(preferRst)
+    doAssert output10.count("<hr class=\"footnote\">" &
+                            "<div class=\"footnote-group\">") == 3
+    doAssert output10.count("<div class=\"footnote-label\">") == 3
+    doAssert "<a href=\"#citation-first\">[First]</a>" in output10
+    doAssert "<a href=\"#footnoteauto-1\">[1]</a>" in output10
+    doAssert "<a href=\"#citation-third\">[Third]</a>" in output10
+
+    let input11 = ".. [note]\n"  # should not crash
+    let output11 = input11.toHtml(preferRst)
+    doAssert "<a href=\"#citation-note\">[note]</a>" in output11
+
+    # check that references to auto-numbered footnotes work
+    let input12 = dedent """
+      Ref. [#]_ and [#]_ STOP.
+
+      .. [#] Body1.
+      .. [#] Body3
+      .. [2] Body2.
+      """
+    let output12 = input12.toHtml(preferRst)
+    let orderAuto = @[
+        "#footnoteauto-1", "[1]",
+        "#footnoteauto-2", "[3]",
+        "STOP.",
+        "Body1.", "Body3", "Body2."
+        ]
+    for i in 0 .. orderAuto.len-2:
+      let pos1 = output12.find(orderAuto[i])
+      let pos2 = output12.find(orderAuto[i+1])
+      doAssert pos1 >= 0
+      doAssert pos2 >= 0
+      doAssert pos1 < pos2
+
+  test "Nim (RST extension) code-block":
+    # check that presence of fields doesn't consume the following text as
+    # its code (which is a literal block)
+    let input0 = dedent """
+      .. code-block:: nim
+         :number-lines: 0
+
+      Paragraph1"""
+    let output0 = input0.toHtml
+    doAssert "<p>Paragraph1</p>" in output0
+
+  test "Nim code-block :number-lines:":
+    let input = dedent """
+      .. code-block:: nim
+         :number-lines: 55
+
+         x
+         y
+      """
+    check "<pre class=\"line-nums\">55\n56\n</pre>" in input.toHtml
+
+  test "Nim code-block indentation":
+    let input = dedent """
+      .. code-block:: nim
+        :number-lines: 55
+
+       x
+      """
+    let output = input.toHtml
+    check "<pre class=\"line-nums\">55\n</pre>" in output
+    check "<span class=\"Identifier\">x</span>" in output
+
+  test "Nim code-block indentation":
+    let input = dedent """
+      .. code-block:: nim
+        :number-lines: 55
+         let a = 1
+      """
+    var error = new string
+    let output = input.toHtml(error=error)
+    check(error[] == "input(2, 3) Error: invalid field: " &
+                     "extra arguments were given to number-lines: ' let a = 1'")
+    check "" == output
+
+  test "code-block warning":
+    let input = dedent """
+      .. code:: Nim
+         :unsupportedField: anything
+
+      .. code:: unsupportedLang
+
+         anything
+
+      ```anotherLang
+      someCode
+      ```
+      """
+    let warnings = new seq[string]
+    let output = input.toHtml(warnings=warnings)
+    check(warnings[] == @[
+        "input(2, 4) Warning: field 'unsupportedField' not supported",
+        "input(4, 11) Warning: language 'unsupportedLang' not supported",
+        "input(8, 4) Warning: language 'anotherLang' not supported"
+        ])
+    check(output == "<pre class = \"listing\">anything</pre>" &
+                    "<p><pre class = \"listing\">someCode</pre> </p>")
+
+  test "RST admonitions":
+    # check that all admonitions are implemented
+    let input0 = dedent """
+      .. admonition:: endOf admonition
+      .. attention:: endOf attention
+      .. caution:: endOf caution
+      .. danger:: endOf danger
+      .. error:: endOf error
+      .. hint:: endOf hint
+      .. important:: endOf important
+      .. note:: endOf note
+      .. tip:: endOf tip
+      .. warning:: endOf warning
+    """
+    let output0 = input0.toHtml(
+      NoSandboxOpts
+    )
+    for a in ["admonition", "attention", "caution", "danger", "error", "hint",
+        "important", "note", "tip", "warning" ]:
+      doAssert "endOf " & a & "</div>" in output0
+
+    # Test that admonition does not swallow up the next paragraph.
+    let input1 = dedent """
+      .. error:: endOfError
+
+      Test paragraph.
+    """
+    let output1 = input1.toHtml(
+      NoSandboxOpts
+    )
+    doAssert "endOfError</div>" in output1
+    doAssert "<p>Test paragraph. </p>" in output1
+    doAssert "class=\"admonition admonition-error\"" in output1
+
+    # Test that second line is parsed as continuation of the first line.
+    let input2 = dedent """
+      .. error:: endOfError
+        Test2p.
+
+      Test paragraph.
+    """
+    let output2 = input2.toHtml(
+      NoSandboxOpts
+    )
+    doAssert "endOfError Test2p.</div>" in output2
+    doAssert "<p>Test paragraph. </p>" in output2
+    doAssert "class=\"admonition admonition-error\"" in output2
+
+    let input3 = dedent """
+      .. note:: endOfNote
+    """
+    let output3 = input3.toHtml(
+      NoSandboxOpts
+    )
+    doAssert "endOfNote</div>" in output3
+    doAssert "class=\"admonition admonition-info\"" in output3
+
+  test "RST internal links":
+    let input1 = dedent """
+      Start.
+
+      .. _target000:
+
+      Paragraph.
+
+      .. _target001:
+
+      * bullet list
+      * Y
+
+      .. _target002:
+
+      1. enumeration list
+      2. Y
+
+      .. _target003:
+
+      term 1
+        Definition list 1.
+
+      .. _target004:
+
+      | line block
+
+      .. _target005:
+
+      :a: field list value
+
+      .. _target006:
+
+      -a  option description
+
+      .. _target007:
+
+      ::
+
+        Literal block
+
+      .. _target008:
+
+      Doctest blocks are not implemented.
+
+      .. _target009:
+
+          block quote
+
+      .. _target010:
+
+      =====  =====  =======
+        A      B    A and B
+      =====  =====  =======
+      False  False  False
+      =====  =====  =======
+
+      .. _target100:
+
+      .. CAUTION:: admonition
+
+      .. _target101:
+
+      .. code:: nim
+
+         const pi = 3.14
+
+      .. _target102:
+
+      .. code-block::
+
+         const pi = 3.14
+
+      Paragraph2.
+
+      .. _target202:
+
+      ----
+
+      That was a transition.
+    """
+    let output1 = input1.toHtml(
+      preferRst
+    )
+    doAssert "<p id=\"target000\""     in output1
+    doAssert "<ul id=\"target001\""    in output1
+    doAssert "<ol id=\"target002\""    in output1
+    doAssert "<dl id=\"target003\""    in output1
+    doAssert "<p id=\"target004\""     in output1
+    doAssert "<table id=\"target005\"" in output1  # field list
+    doAssert "<div id=\"target006\""   in output1  # option list
+    doAssert "<pre id=\"target007\""   in output1
+    doAssert "<blockquote id=\"target009\"" in output1
+    doAssert "<table id=\"target010\"" in output1  # just table
+    doAssert "<span id=\"target100\""  in output1
+    doAssert "<pre id=\"target101\""   in output1  # code
+    doAssert "<pre id=\"target102\""   in output1  # code-block
+    doAssert "<hr id=\"target202\""    in output1
+
+  test "RST internal links for sections":
+    let input1 = dedent """
+      .. _target101:
+      .. _target102:
+
+      Section xyz
+      -----------
+
+      Ref. target101_
+    """
+    let output1 = input1.toHtml
+    # "target101" should be erased and changed to "section-xyz":
+    check "href=\"#target101\"" notin output1
+    check "id=\"target101\""    notin output1
+    check "href=\"#target102\"" notin output1
+    check "id=\"target102\""    notin output1
+    check "id=\"section-xyz\""     in output1
+    check "href=\"#section-xyz\""  in output1
+
+    let input2 = dedent """
+      .. _target300:
+
+      Section xyz
+      ===========
+
+      .. _target301:
+
+      SubsectionA
+      -----------
+
+      Ref. target300_ and target301_.
+
+      .. _target103:
+
+      .. [cit2020] note.
+
+      Ref. target103_.
+
+    """
+    let output2 = input2.toHtml(preferRst)
+    # "target101" should be erased and changed to "section-xyz":
+    doAssert "href=\"#target300\"" notin output2
+    doAssert "id=\"target300\""    notin output2
+    doAssert "href=\"#target301\"" notin output2
+    doAssert "id=\"target301\""    notin output2
+    doAssert "<h1 id=\"section-xyz\"" in output2
+    doAssert "<h2 id=\"subsectiona\"" in output2
+    # links should preserve their original names but point to section labels:
+    doAssert "href=\"#section-xyz\">target300" in output2
+    doAssert "href=\"#subsectiona\">target301" in output2
+    doAssert "href=\"#citation-cit2020\">target103" in output2
+
+    let output2l = rstToLatex(input2, {})
+    doAssert "\\label{section-xyz}\\hypertarget{section-xyz}{}" in output2l
+    doAssert "\\hyperlink{section-xyz}{target300}"  in output2l
+    doAssert "\\hyperlink{subsectiona}{target301}"  in output2l
+
+  test "RST internal links (inline)":
+    let input1 = dedent """
+      Paragraph with _`some definition`.
+
+      Ref. `some definition`_.
+    """
+    let output1 = input1.toHtml
+    doAssert "<span class=\"target\" " &
+        "id=\"some-definition\">some definition</span>" in output1
+    doAssert "Ref. <a class=\"reference internal\" " &
+        "href=\"#some-definition\">some definition</a>" in output1
+
+  test "RST references (additional symbols)":
+    # check that ., _, -, +, : are allowed symbols in references without ` `
+    let input1 = dedent """
+      sec.1
+      -----
+
+      2-other:sec+c_2
+      ^^^^^^^^^^^^^^^
+
+      .. _link.1_2021:
+
+      Paragraph
+
+      Ref. sec.1_! and 2-other:sec+c_2_;and link.1_2021_.
+    """
+    let output1 = input1.toHtml
+    doAssert "id=\"secdot1\"" in output1
+    doAssert "id=\"Z2minusothercolonsecplusc-2\"" in output1
+    check "id=\"linkdot1-2021\"" in output1
+    let ref1 = "<a class=\"reference internal\" href=\"#secdot1\">sec.1</a>"
+    let ref2 = "<a class=\"reference internal\" href=\"#Z2minusothercolonsecplusc-2\">2-other:sec+c_2</a>"
+    let ref3 = "<a class=\"reference internal\" href=\"#linkdot1-2021\">link.1_2021</a>"
+    let refline = "Ref. " & ref1 & "! and " & ref2 & ";and " & ref3 & "."
+    doAssert refline in output1
+
+  test "Option lists 1":
+    # check that "* b" is not consumed by previous bullet item because of
+    # incorrect indentation handling in option lists
+    let input = dedent """
+      * a
+        -m   desc
+        -n   very long
+             desc
+      * b"""
+    let output = input.toHtml
+    check(output.count("<ul") == 1)
+    check(output.count("<li>") == 2)
+    check(output.count("<div class=\"option-list\"") == 1)
+    check(optionListLabel("-m") &
+          """<div class="option-list-description">desc</div></div>""" in
+          output)
+    check(optionListLabel("-n") &
+          """<div class="option-list-description">very long desc</div></div>""" in
+          output)
+
+  test "Option lists 2":
+    # check that 2nd option list is not united with the 1st
+    let input = dedent """
+      * a
+        -m   desc
+        -n   very long
+             desc
+      -d  option"""
+    let output = input.toHtml
+    check(output.count("<ul") == 1)
+    check output.count("<div class=\"option-list\"") == 2
+    check(optionListLabel("-m") &
+          """<div class="option-list-description">desc</div></div>""" in
+          output)
+    check(optionListLabel("-n") &
+          """<div class="option-list-description">very long desc</div></div>""" in
+          output)
+    check(optionListLabel("-d") &
+          """<div class="option-list-description">option</div></div>""" in
+          output)
+    check "<p>option</p>" notin output
+
+  test "Option list 3 (double /)":
+    let input = dedent """
+      * a
+        //compile  compile1
+        //doc      doc1
+                   cont
+      -d  option"""
+    let output = input.toHtml
+    check(output.count("<ul") == 1)
+    check output.count("<div class=\"option-list\"") == 2
+    check(optionListLabel("compile") &
+          """<div class="option-list-description">compile1</div></div>""" in
+          output)
+    check(optionListLabel("doc") &
+          """<div class="option-list-description">doc1 cont</div></div>""" in
+          output)
+    check(optionListLabel("-d") &
+          """<div class="option-list-description">option</div></div>""" in
+          output)
+    check "<p>option</p>" notin output
+
+  test "Roles: subscript prefix/postfix":
+    let expected = "See <sub>some text</sub>."
+    check "See :subscript:`some text`.".toHtml == expected
+    check "See `some text`:subscript:.".toHtml == expected
+
+  test "Roles: correct parsing from beginning of line":
+    let expected = "<sup>3</sup>He is an isotope of helium."
+    check """:superscript:`3`\ He is an isotope of helium.""".toHtml == expected
+    check """:sup:`3`\ He is an isotope of helium.""".toHtml == expected
+    check """`3`:sup:\ He is an isotope of helium.""".toHtml == expected
+    check """`3`:superscript:\ He is an isotope of helium.""".toHtml == expected
+
+  test "Roles: warnings":
+    let input = dedent"""
+      See function :py:func:`spam`.
+
+      See also `egg`:py:class:.
+      """
+    var warnings = new seq[string]
+    let output = input.toHtml(warnings=warnings)
+    doAssert warnings[].len == 2
+    check "(1, 14) Warning: " in warnings[0]
+    check "language 'py:func' not supported" in warnings[0]
+    check "(3, 15) Warning: " in warnings[1]
+    check "language 'py:class' not supported" in warnings[1]
+    check("""<p>See function <span class="py:func">spam</span>.</p>""" & "\n" &
+          """<p>See also <span class="py:class">egg</span>. </p>""" ==
+          output)
+
+  test "(not) Roles: check escaping 1":
+    let expected = """See :subscript:<tt class="docutils literal">""" &
+                   """<span class="pre">""" & id"some" & " " & id"text" &
+                   "</span></tt>."
+    check """See \:subscript:`some text`.""".toHtml == expected
+    check """See :subscript\:`some text`.""".toHtml == expected
+
+  test "(not) Roles: check escaping 2":
+    check("""See :subscript:\`some text\`.""".toHtml ==
+          "See :subscript:`some text`.")
+
+  test "Field list":
+    check(":field: text".toHtml ==
+            """<table class="docinfo" frame="void" rules="none">""" &
+            """<col class="docinfo-name" /><col class="docinfo-content" />""" &
+            """<tbody valign="top"><tr><th class="docinfo-name">field:</th>""" &
+            """<td>text</td></tr>""" & "\n</tbody></table>")
+
+  test "Field list: body after newline":
+    let output = dedent"""
+      :field:
+        text1""".toHtml
+    check "<table class=\"docinfo\"" in output
+    check ">field:</th>" in output
+    check "<td>text1</td>" in output
+
+  test "Field list (incorrect)":
+    check ":field:text".toHtml == ":field:text"
+
+suite "RST/Code highlight":
+  test "Basic Python code highlight":
+    let pythonCode = """
+    .. code-block:: python
+
+      def f_name(arg=42):
+          print(f"{arg}")
+
+    """
+
+    let expected = """<blockquote><p><span class="Keyword">def</span> f_name<span class="Punctuation">(</span><span class="Punctuation">arg</span><span class="Operator">=</span><span class="DecNumber">42</span><span class="Punctuation">)</span><span class="Punctuation">:</span>
+    print<span class="Punctuation">(</span><span class="RawData">f&quot;{arg}&quot;</span><span class="Punctuation">)</span></p></blockquote>"""
+
+    check strip(rstToHtml(pythonCode, {}, newStringTable(modeCaseSensitive))) ==
+      strip(expected)
+
+
+suite "invalid targets":
+  test "invalid image target":
+    let input1 = dedent """.. image:: /images/myimage.jpg
+      :target: https://bar.com
+      :alt: Alt text for the image"""
+    let output1 = input1.toHtml
+    check output1 == """<a class="reference external" href="https://bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
+
+    let input2 = dedent """.. image:: /images/myimage.jpg
+      :target: javascript://bar.com
+      :alt: Alt text for the image"""
+    let output2 = input2.toHtml
+    check output2 == """<img src="/images/myimage.jpg" alt="Alt text for the image"/>"""
+
+    let input3 = dedent """.. image:: /images/myimage.jpg
+      :target: bar.com
+      :alt: Alt text for the image"""
+    let output3 = input3.toHtml
+    check output3 == """<a class="reference external" href="bar.com"><img src="/images/myimage.jpg" alt="Alt text for the image"/></a>"""
+
+  test "invalid links":
+    check("(([Nim](https://nim-lang.org/)))".toHtml ==
+        """((<a class="reference external" href="https://nim-lang.org/">Nim</a>))""")
+    # unknown protocol is treated just like plain text, not a link
+    var warnings = new seq[string]
+    check("(([Nim](javascript://nim-lang.org/)))".toHtml(warnings=warnings) ==
+        """(([Nim](javascript://nim-lang.org/)))""")
+    check(warnings[] == @["input(1, 9) Warning: broken link 'javascript'"])
+    warnings[].setLen 0
+    check("`Nim <javascript://nim-lang.org/>`_".toHtml(warnings=warnings) ==
+      """Nim &lt;javascript://nim-lang.org/&gt;""")
+    check(warnings[] == @["input(1, 33) Warning: broken link 'javascript'"])
+
+suite "local file inclusion":
+  test "cannot include files in sandboxed mode":
+    var error = new string
+    discard ".. include:: ./readme.md".toHtml(error=error)
+    check(error[] == "input(1, 11) Error: disabled directive: 'include'")
+
+  test "code-block file directive is disabled":
+    var error = new string
+    discard ".. code-block:: nim\n    :file: ./readme.md".toHtml(error=error)
+    check(error[] == "input(2, 20) Error: disabled directive: 'file'")
+
+  test "code-block file directive is disabled - Markdown":
+    var error = new string
+    discard "```nim file = ./readme.md\n```".toHtml(error=error)
+    check(error[] == "input(1, 23) Error: disabled directive: 'file'")
+
+proc documentToHtml*(doc: string, isMarkdown: bool = false): string {.gcsafe.} =
+  var options = {roSupportMarkdown}
+  if isMarkdown:
+    options.incl roPreferMarkdown
+  result = rstToHtml(doc, options, defaultConfig())
diff --git a/tests/stdlib/tsequtils.nim b/tests/stdlib/tsequtils.nim
new file mode 100644
index 000000000..1094ae233
--- /dev/null
+++ b/tests/stdlib/tsequtils.nim
@@ -0,0 +1,547 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+# xxx move all tests under `main`
+
+import std/sequtils
+import strutils
+from algorithm import sorted
+import std/assertions
+
+{.experimental: "strictEffects".}
+{.push warningAsError[Effect]: on.}
+{.experimental: "strictFuncs".}
+
+# helper for testing double substitution side effects which are handled
+# by `evalOnceAs`
+var counter = 0
+proc identity[T](a: T): auto =
+  counter.inc
+  a
+
+block: # concat test
+  let
+    s1 = @[1, 2, 3]
+    s2 = @[4, 5]
+    s3 = @[6, 7]
+    total = concat(s1, s2, s3)
+  doAssert total == @[1, 2, 3, 4, 5, 6, 7]
+
+block: # count test
+  let
+    s1 = @[1, 2, 3, 2]
+    s2 = @['a', 'b', 'x', 'a']
+    a1 = [1, 2, 3, 2]
+    a2 = ['a', 'b', 'x', 'a']
+    r0 = count(s1, 0)
+    r1 = count(s1, 1)
+    r2 = count(s1, 2)
+    r3 = count(s2, 'y')
+    r4 = count(s2, 'x')
+    r5 = count(s2, 'a')
+    ar0 = count(a1, 0)
+    ar1 = count(a1, 1)
+    ar2 = count(a1, 2)
+    ar3 = count(a2, 'y')
+    ar4 = count(a2, 'x')
+    ar5 = count(a2, 'a')
+  doAssert r0 == 0
+  doAssert r1 == 1
+  doAssert r2 == 2
+  doAssert r3 == 0
+  doAssert r4 == 1
+  doAssert r5 == 2
+  doAssert ar0 == 0
+  doAssert ar1 == 1
+  doAssert ar2 == 2
+  doAssert ar3 == 0
+  doAssert ar4 == 1
+  doAssert ar5 == 2
+
+block: # cycle tests
+  let
+    a = @[1, 2, 3]
+    b: seq[int] = @[]
+    c = [1, 2, 3]
+
+  doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  doAssert a.cycle(0) == @[]
+  #doAssert a.cycle(-1) == @[] # will not compile!
+  doAssert b.cycle(3) == @[]
+  doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
+  doAssert c.cycle(0) == @[]
+
+block: # repeat tests
+  doAssert repeat(10, 5) == @[10, 10, 10, 10, 10]
+  doAssert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]]
+  doAssert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]]
+
+block: # deduplicates test
+  let
+    dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
+    dup2 = @["a", "a", "c", "d", "d"]
+    dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4]
+    dup4 = ["a", "a", "c", "d", "d"]
+    unique1 = deduplicate(dup1)
+    unique2 = deduplicate(dup2)
+    unique3 = deduplicate(dup3)
+    unique4 = deduplicate(dup4)
+    unique5 = deduplicate(dup1.sorted, true)
+    unique6 = deduplicate(dup2, true)
+    unique7 = deduplicate(dup3.sorted, true)
+    unique8 = deduplicate(dup4, true)
+  doAssert unique1 == @[1, 3, 4, 2, 8]
+  doAssert unique2 == @["a", "c", "d"]
+  doAssert unique3 == @[1, 3, 4, 2, 8]
+  doAssert unique4 == @["a", "c", "d"]
+  doAssert unique5 == @[1, 2, 3, 4, 8]
+  doAssert unique6 == @["a", "c", "d"]
+  doAssert unique7 == @[1, 2, 3, 4, 8]
+  doAssert unique8 == @["a", "c", "d"]
+
+block: # zip test
+  let
+    short = @[1, 2, 3]
+    long = @[6, 5, 4, 3, 2, 1]
+    words = @["one", "two", "three"]
+    ashort = [1, 2, 3]
+    along = [6, 5, 4, 3, 2, 1]
+    awords = ["one", "two", "three"]
+    zip1 = zip(short, long)
+    zip2 = zip(short, words)
+    zip3 = zip(ashort, along)
+  doAssert zip1 == @[(1, 6), (2, 5), (3, 4)]
+  doAssert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
+  doAssert zip3 == @[(1, 6), (2, 5), (3, 4)]
+  doAssert zip1[2][1] == 4
+  doAssert zip2[2][1] == "three"
+  doAssert zip3[2][1] == 4
+  when (NimMajor, NimMinor) <= (1, 0):
+    let
+      # In Nim 1.0.x and older, zip returned a seq of tuple strictly
+      # with fields named "a" and "b".
+      zipAb = zip(ashort, awords)
+    doAssert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")]
+    doAssert zipAb[2].b == "three"
+  else:
+    let
+      # As zip returns seq of anonymous tuples, they can be assigned
+      # to any variable that's a sequence of named tuples too.
+      zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords)
+      zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words)
+    doAssert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")]
+    doAssert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")]
+    doAssert zipXy[2].y == "three"
+    doAssert zipMn[2].n == "three"
+
+block: # distribute tests
+  let numbers = @[1, 2, 3, 4, 5, 6, 7]
+  doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+  doAssert numbers.distribute(6)[0] == @[1, 2]
+  doAssert numbers.distribute(6)[5] == @[7]
+  let a = @[1, 2, 3, 4, 5, 6, 7]
+  doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
+  doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
+  doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
+  doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
+  doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
+  doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
+  doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
+  doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
+  doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
+  doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
+  doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
+  doAssert a.distribute(6, false) == @[
+    @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
+  doAssert a.distribute(8, false) == a.distribute(8, true)
+  doAssert a.distribute(90, false) == a.distribute(90, true)
+  var b = @[0]
+  for f in 1 .. 25: b.add(f)
+  doAssert b.distribute(5, true)[4].len == 5
+  doAssert b.distribute(5, false)[4].len == 2
+
+block: # map test
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    m1 = map(numbers, proc(x: int): int = 2*x)
+    m2 = map(anumbers, proc(x: int): int = 2*x)
+  doAssert m1 == @[2, 8, 10, 16, 18, 14, 8]
+  doAssert m2 == @[2, 8, 10, 16, 18, 14, 8]
+
+block: # apply test
+  var a = @["1", "2", "3", "4"]
+  apply(a, proc(x: var string) = x &= "42")
+  doAssert a == @["142", "242", "342", "442"]
+
+block: # filter proc test
+  let
+    colors = @["red", "yellow", "black"]
+    acolors = ["red", "yellow", "black"]
+    f1 = filter(colors, proc(x: string): bool = x.len < 6)
+    f2 = filter(colors) do (x: string) -> bool: x.len > 5
+    f3 = filter(acolors, proc(x: string): bool = x.len < 6)
+    f4 = filter(acolors) do (x: string) -> bool: x.len > 5
+  doAssert f1 == @["red", "black"]
+  doAssert f2 == @["yellow"]
+  doAssert f3 == @["red", "black"]
+  doAssert f4 == @["yellow"]
+
+block: # filter iterator test
+  let numbers = @[1, 4, 5, 8, 9, 7, 4]
+  let anumbers = [1, 4, 5, 8, 9, 7, 4]
+  doAssert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
+    @[4, 8, 4]
+  doAssert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) ==
+    @[4, 8, 4]
+
+block: # keepIf test
+  var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
+  keepIf(floats, proc(x: float): bool = x > 10)
+  doAssert floats == @[13.0, 12.5, 10.1]
+
+block: # insert tests
+  var dest = @[1, 1, 1, 1, 1, 1, 1, 1]
+  let
+    src = @[2, 2, 2, 2, 2, 2]
+    outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
+  dest.insert(src, 3)
+  doAssert dest == outcome, """\
+  Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
+  at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
+
+block: # filterIt test
+  let
+    temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
+    acceptable = filterIt(temperatures, it < 50 and it > -10)
+    notAcceptable = filterIt(temperatures, it > 50 or it < -10)
+  doAssert acceptable == @[-2.0, 24.5, 44.31]
+  doAssert notAcceptable == @[-272.15, 99.9, -113.44]
+
+block: # keepItIf test
+  var candidates = @["foo", "bar", "baz", "foobar"]
+  keepItIf(candidates, it.len == 3 and it[0] == 'b')
+  doAssert candidates == @["bar", "baz"]
+
+block: # all
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert all(numbers, proc (x: int): bool = return x < 10) == true
+  doAssert all(numbers, proc (x: int): bool = return x < 9) == false
+  doAssert all(len0seq, proc (x: int): bool = return false) == true
+  doAssert all(anumbers, proc (x: int): bool = return x < 10) == true
+  doAssert all(anumbers, proc (x: int): bool = return x < 9) == false
+
+block: # allIt
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert allIt(numbers, it < 10) == true
+  doAssert allIt(numbers, it < 9) == false
+  doAssert allIt(len0seq, false) == true
+  doAssert allIt(anumbers, it < 10) == true
+  doAssert allIt(anumbers, it < 9) == false
+
+block: # any
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert any(numbers, proc (x: int): bool = return x > 8) == true
+  doAssert any(numbers, proc (x: int): bool = return x > 9) == false
+  doAssert any(len0seq, proc (x: int): bool = return true) == false
+  doAssert any(anumbers, proc (x: int): bool = return x > 8) == true
+  doAssert any(anumbers, proc (x: int): bool = return x > 9) == false
+
+block: # anyIt
+  let
+    numbers = @[1, 4, 5, 8, 9, 7, 4]
+    anumbers = [1, 4, 5, 8, 9, 7, 4]
+    len0seq: seq[int] = @[]
+  doAssert anyIt(numbers, it > 8) == true
+  doAssert anyIt(numbers, it > 9) == false
+  doAssert anyIt(len0seq, true) == false
+  doAssert anyIt(anumbers, it > 8) == true
+  doAssert anyIt(anumbers, it > 9) == false
+
+block: # toSeq test
+  block:
+    let
+      numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      oddNumbers = toSeq(filter(numeric) do (x: int) -> bool:
+        if x mod 2 == 1:
+          result = true)
+    doAssert oddNumbers == @[1, 3, 5, 7, 9]
+
+  block:
+    doAssert [1, 2].toSeq == @[1, 2]
+    doAssert @[1, 2].toSeq == @[1, 2]
+
+    doAssert @[1, 2].toSeq == @[1, 2]
+    doAssert toSeq(@[1, 2]) == @[1, 2]
+
+  block:
+    iterator myIter(seed: int): auto =
+      for i in 0..<seed:
+        yield i
+    doAssert toSeq(myIter(2)) == @[0, 1]
+
+  block:
+    iterator myIter(): auto {.inline.} =
+      yield 1
+      yield 2
+
+    doAssert myIter.toSeq == @[1, 2]
+    doAssert toSeq(myIter) == @[1, 2]
+
+  when not defined(js):
+    # pending #4695
+    block:
+        iterator myIter(): int {.closure.} =
+          yield 1
+          yield 2
+
+        doAssert myIter.toSeq == @[1, 2]
+        doAssert toSeq(myIter) == @[1, 2]
+
+    block:
+      proc myIter(): auto =
+        iterator ret(): int {.closure.} =
+          yield 1
+          yield 2
+        result = ret
+
+      doAssert myIter().toSeq == @[1, 2]
+      doAssert toSeq(myIter()) == @[1, 2]
+
+    block:
+      proc myIter(n: int): auto =
+        var counter = 0
+        iterator ret(): int {.closure.} =
+          while counter < n:
+            yield counter
+            counter.inc
+        result = ret
+
+      block:
+        let myIter3 = myIter(3)
+        doAssert myIter3.toSeq == @[0, 1, 2]
+      block:
+        let myIter3 = myIter(3)
+        doAssert toSeq(myIter3) == @[0, 1, 2]
+      block:
+        # makes sure this does not hang forever
+        doAssert myIter(3).toSeq == @[0, 1, 2]
+        doAssert toSeq(myIter(3)) == @[0, 1, 2]
+
+block:
+  # tests https://github.com/nim-lang/Nim/issues/7187
+  counter = 0
+  let ret = toSeq(@[1, 2, 3].identity().filter(proc (x: int): bool = x < 3))
+  doAssert ret == @[1, 2]
+  doAssert counter == 1
+block: # foldl tests
+  let
+    numbers = @[5, 9, 11]
+    addition = foldl(numbers, a + b)
+    subtraction = foldl(numbers, a - b)
+    multiplication = foldl(numbers, a * b)
+    words = @["nim", "is", "cool"]
+    concatenation = foldl(words, a & b)
+  doAssert addition == 25, "Addition is (((5)+9)+11)"
+  doAssert subtraction == -15, "Subtraction is (((5)-9)-11)"
+  doAssert multiplication == 495, "Multiplication is (((5)*9)*11)"
+  doAssert concatenation == "nimiscool"
+
+block: # foldr tests
+  let
+    numbers = @[5, 9, 11]
+    addition = foldr(numbers, a + b)
+    subtraction = foldr(numbers, a - b)
+    multiplication = foldr(numbers, a * b)
+    words = @["nim", "is", "cool"]
+    concatenation = foldr(words, a & b)
+  doAssert addition == 25, "Addition is (5+(9+(11)))"
+  doAssert subtraction == 7, "Subtraction is (5-(9-(11)))"
+  doAssert multiplication == 495, "Multiplication is (5*(9*(11)))"
+  doAssert concatenation == "nimiscool"
+  doAssert toSeq(1..3).foldr(a + b) == 6 # issue #14404
+
+block: # mapIt + applyIt test
+  counter = 0
+  var
+    nums = @[1, 2, 3, 4]
+    strings = nums.identity.mapIt($(4 * it))
+  doAssert counter == 1
+  nums.applyIt(it * 3)
+  doAssert nums[0] + nums[3] == 15
+  doAssert strings[2] == "12"
+
+block: # newSeqWith tests
+  var seq2D = newSeqWith(4, newSeq[bool](2))
+  seq2D[0][0] = true
+  seq2D[1][0] = true
+  seq2D[0][1] = true
+  doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
+
+block: # bug #21538
+  var x: seq[int] = @[2, 4]
+  var y = newSeqWith(x.pop(), true)
+  doAssert y == @[true, true, true, true]
+
+block: # mapLiterals tests
+  let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int)
+  doAssert x is array[4, int]
+  doAssert mapLiterals((1, ("abc"), 2), float, nested = false) ==
+    (float(1), "abc", float(2))
+  doAssert mapLiterals(([1], ("abc"), 2), `$`, nested = true) ==
+    (["1"], "abc", "2")
+
+block: # mapIt with openArray
+  counter = 0
+  proc foo(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+  doAssert foo([identity(1), identity(2)]) == @[10, 20]
+  doAssert counter == 2
+
+block: # mapIt with direct openArray
+  proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+  counter = 0
+  doAssert foo1(openArray[int]([identity(1), identity(2)])) == @[10, 20]
+  doAssert counter == 2
+
+  # Corner cases (openArray literals should not be common)
+  template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
+  counter = 0
+  doAssert foo2(openArray[int]([identity(1), identity(2)])) == @[10, 20]
+  doAssert counter == 2
+
+  counter = 0
+  doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1, 2]
+  doAssert counter == 2
+
+block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468
+  # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type
+  # of elements)
+  doAssert: not compiles(mapIt(@[], it))
+  doAssert: not compiles(mapIt([], it))
+  doAssert newSeq[int](0).mapIt(it) == @[]
+
+block: # mapIt redifinition check, see https://github.com/nim-lang/Nim/issues/8580
+  let s2 = [1, 2].mapIt(it)
+  doAssert s2 == @[1, 2]
+
+block:
+  counter = 0
+  doAssert [1, 2].identity().mapIt(it*2).mapIt(it*10) == @[20, 40]
+  # https://github.com/nim-lang/Nim/issues/7187 test case
+  doAssert counter == 1
+
+block: # mapIt with invalid RHS for `let` (#8566)
+  type X = enum
+    A, B
+  doAssert mapIt(X, $it) == @["A", "B"]
+
+block:
+  # bug #9093
+  let inp = "a:b,c:d"
+
+  let outp = inp.split(",").mapIt(it.split(":"))
+  doAssert outp == @[@["a", "b"], @["c", "d"]]
+
+
+block:
+  proc iter(len: int): auto =
+    result = iterator(): int =
+      for i in 0..<len:
+        yield i
+
+  # xxx: obscure CT error: basic_types.nim(16, 16) Error: internal error: symbol has no generated name: true
+  when not defined(js):
+    doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
+
+block: # strictFuncs tests with ref object
+  type Foo = ref object
+
+  let foo1 = Foo()
+  let foo2 = Foo()
+  let foos = @[foo1, foo2]
+
+  # Procedures that are `func`
+  discard concat(foos, foos)
+  discard count(foos, foo1)
+  discard cycle(foos, 3)
+  discard deduplicate(foos)
+  discard minIndex(foos)
+  discard maxIndex(foos)
+  discard distribute(foos, 2)
+  var mutableFoos = foos
+  mutableFoos.delete(0..1)
+  mutableFoos.insert(foos)
+
+  # Some procedures that are `proc`, but were reverted from `func`
+  discard repeat(foo1, 3)
+  discard zip(foos, foos)
+  let fooTuples = @[(foo1, 1), (foo2, 2)]
+  discard unzip(fooTuples)
+
+template main =
+  # xxx move all tests here
+  block: # delete tests
+    let outcome = @[1, 1, 1, 1, 1, 1, 1, 1]
+    var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
+    dest.delete(3, 8)
+    doAssert outcome == dest, """\
+    Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
+    is [1,1,1,1,1,1,1,1]"""
+    var x = @[1, 2, 3]
+    x.delete(100, 100)
+    doAssert x == @[1, 2, 3]
+
+  block: # delete tests
+    var a = @[10, 11, 12, 13, 14]
+    doAssertRaises(IndexDefect): a.delete(4..5)
+    doAssertRaises(IndexDefect): a.delete(4..<6)
+    doAssertRaises(IndexDefect): a.delete(-1..1)
+    doAssertRaises(IndexDefect): a.delete(-1 .. -1)
+    doAssertRaises(IndexDefect): a.delete(5..5)
+    doAssertRaises(IndexDefect): a.delete(5..3)
+    doAssertRaises(IndexDefect): a.delete(5..<5) # edge case
+    doAssert a == @[10, 11, 12, 13, 14]
+    a.delete(4..4)
+    doAssert a == @[10, 11, 12, 13]
+    a.delete(1..2)
+    doAssert a == @[10, 13]
+    a.delete(1..<1) # empty slice
+    doAssert a == @[10, 13]
+    a.delete(0..<0)
+    doAssert a == @[10, 13]
+    a.delete(0..0)
+    doAssert a == @[13]
+    a.delete(0..0)
+    doAssert a == @[]
+    doAssertRaises(IndexDefect): a.delete(0..0)
+    doAssertRaises(IndexDefect): a.delete(0..<0) # edge case
+    block:
+      type A = object
+        a0: int
+      var a = @[A(a0: 10), A(a0: 11), A(a0: 12)]
+      a.delete(0..1)
+      doAssert a == @[A(a0: 12)]
+    block:
+      type A = ref object
+      let a0 = A()
+      let a1 = A()
+      let a2 = A()
+      var a = @[a0, a1, a2]
+      a.delete(0..1)
+      doAssert a == @[a2]
+
+static: main()
+main()
+
+{.pop.}
diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim
new file mode 100644
index 000000000..c8498f23e
--- /dev/null
+++ b/tests/stdlib/tsetutils.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+import std/setutils
+import std/assertions
+
+type 
+  Colors = enum
+    red, green = 5, blue = 10
+  Bar = enum
+    bar0 = -1, bar1, bar2
+
+template main =
+  block: # toSet
+    doAssert "abcbb".toSet == {'a', 'b', 'c'}
+    doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13}
+    doAssert toSet(0u16..30) == {0u16..30}
+    type A = distinct char
+    doAssert [A('x')].toSet == {A('x')}
+
+  block: # fullSet
+    doAssert fullSet(Colors) == {red, green, blue}
+    doAssert fullSet(char) == {0.chr..255.chr}
+    doAssert fullSet(Bar) == {bar0, bar1, bar2}
+    doAssert fullSet(bool) == {true, false}
+
+  block: # complement
+    doAssert {red, blue}.complement == {green}
+    doAssert (complement {red, green, blue}).card == 0
+    doAssert (complement {false}) == {true}
+    doAssert {bar0}.complement == {bar1, bar2}
+    doAssert {range[0..10](0), 1, 2, 3}.complement == {range[0..10](4), 5, 6, 7, 8, 9, 10}
+    doAssert {'0'..'9'}.complement == {0.char..255.char} - {'0'..'9'}
+
+  block: # `[]=`
+    type A = enum
+      a0, a1, a2, a3
+    var s = {a0, a3}
+    s[a0] = false
+    s[a1] = false
+    doAssert s == {a3}
+    s[a2] = true
+    s[a3] = true
+    doAssert s == {a2, a3}
+
+main()
+static: main()
diff --git a/tests/stdlib/tsharedlist.nim b/tests/stdlib/tsharedlist.nim
new file mode 100644
index 000000000..b91302d19
--- /dev/null
+++ b/tests/stdlib/tsharedlist.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "--mm:orc; --mm:refc"
+"""
+
+import std/sharedlist
+import std/assertions
+
+block:
+  var
+    list: SharedList[int]
+    count: int
+
+  init(list)
+
+  for i in 1 .. 250:
+    list.add i
+
+  for i in list:
+    inc count
+
+  doAssert count == 250
+
+  deinitSharedList(list)
+
+
+block: # bug #17696
+  var keysList = SharedList[string]()
+  init(keysList)
+
+  keysList.add("a")
+  keysList.add("b")
+  keysList.add("c")
+  keysList.add("d")
+  keysList.add("e")
+  keysList.add("f")
+
+
+  # Remove element "b" and "d" from the list. 
+  keysList.iterAndMutate(proc (key: string): bool =
+    if key == "b" or key == "d": # remove only "b" and "d"
+      return true
+    return false
+  )
+
+  var results: seq[string]
+  for key in keysList.items:
+    results.add key
+
+  doAssert results == @["a", "f", "c", "e"]
diff --git a/tests/stdlib/tsharedtable.nim b/tests/stdlib/tsharedtable.nim
new file mode 100644
index 000000000..10ad5f658
--- /dev/null
+++ b/tests/stdlib/tsharedtable.nim
@@ -0,0 +1,90 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+output: '''
+'''
+"""
+
+import sharedtables
+import std/assertions
+
+block:
+  var table: SharedTable[int, int]
+
+  init(table)
+  table[1] = 10
+  doAssert table.mget(1) == 10
+  doAssert table.mgetOrPut(3, 7) == 7
+  doAssert table.mgetOrPut(3, 99) == 7
+  deinitSharedTable(table)
+
+import sequtils, algorithm
+proc sortedPairs[T](t: T): auto = toSeq(t.pairs).sorted
+template sortedItems(t: untyped): untyped = sorted(toSeq(t))
+
+import tables # refs issue #13504
+
+block: # we use Table as groundtruth, it's well tested elsewhere
+  template testDel(t, t0) =
+    template put2(i) =
+      t[i] = i
+      t0[i] = i
+
+    template add2(i, val) =
+      t.add(i, val)
+      t0.add(i, val)
+
+    template del2(i) =
+      t.del(i)
+      t0.del(i)
+
+    template checkEquals() =
+      doAssert t.len == t0.len
+      for k,v in t0:
+        doAssert t.mgetOrPut(k, -1) == v # sanity check
+        doAssert t.mget(k) == v
+
+    let n = 100
+    let n2 = n*2
+    let n3 = n*3
+    let n4 = n*4
+    let n5 = n*5
+
+    for i in 0..<n:
+      put2(i)
+    for i in 0..<n:
+      if i mod 3 == 0:
+        del2(i)
+    for i in n..<n2:
+      put2(i)
+    for i in 0..<n2:
+      if i mod 7 == 0:
+        del2(i)
+
+    checkEquals()
+
+    for i in n2..<n3:
+      t0[i] = -2
+      doAssert t.mgetOrPut(i, -2) == -2
+      doAssert t.mget(i) == -2
+
+    for i in 0..<n4:
+      let ok = i in t0
+      if not ok: t0[i] = -i
+      doAssert t.hasKeyOrPut(i, -i) == ok
+
+    checkEquals()
+
+    for i in n4..<n5:
+      add2(i, i*10)
+      add2(i, i*11)
+      add2(i, i*12)
+      del2(i)
+      del2(i)
+
+    checkEquals()
+
+  var t: SharedTable[int, int]
+  init(t) # ideally should be auto-init
+  var t0: Table[int, int]
+  testDel(t, t0)
+  deinitSharedTable(t)
diff --git a/tests/stdlib/tsince.nim b/tests/stdlib/tsince.nim
new file mode 100644
index 000000000..a0a4229cb
--- /dev/null
+++ b/tests/stdlib/tsince.nim
@@ -0,0 +1,32 @@
+import std/private/since
+import std/assertions
+
+proc fun1(): int {.since: (1, 3).} = 12
+proc fun1Bad(): int {.since: (99, 3).} = 12
+proc fun2(): int {.since: (1, 3, 1).} = 12
+proc fun2Bad(): int {.since: (99, 3, 1).} = 12
+
+doAssert fun1() == 12
+doAssert declared(fun1)
+doAssert not declared(fun1Bad)
+
+doAssert fun2() == 12
+doAssert declared(fun2)
+doAssert not declared(fun2Bad)
+
+var ok = false
+since (1, 3):
+  ok = true
+doAssert ok
+
+ok = false
+since (1, 3, 1):
+  ok = true
+doAssert ok
+
+since (99, 3):
+  doAssert false
+
+template fun3(): int {.since: (1, 3).} = 12
+
+doAssert declared(fun3)
diff --git a/tests/stdlib/tsocketstreams.nim b/tests/stdlib/tsocketstreams.nim
new file mode 100644
index 000000000..a37e7c34c
--- /dev/null
+++ b/tests/stdlib/tsocketstreams.nim
@@ -0,0 +1,65 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+OM
+NIM
+3
+NIM
+NIM
+Hello server!
+Hi there client!
+'''"""
+import std/socketstreams, net, streams
+
+block UDP:
+  var recvSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+  var recvStream = newReadSocketStream(recvSocket)
+  recvSocket.bindAddr(Port(12345), "127.0.0.1")
+
+  var sendSocket = newSocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
+  sendSocket.connect("127.0.0.1", Port(12345))
+  var sendStream = newWriteSocketStream(sendSocket)
+  sendStream.write "NOM\n"
+  sendStream.setPosition(1)
+  echo sendStream.peekStr(2)
+  sendStream.write "I"
+  sendStream.setPosition(0)
+  echo sendStream.readStr(3)
+  echo sendStream.getPosition()
+  sendStream.flush()
+
+  echo recvStream.readLine()
+  recvStream.setPosition(0)
+  echo recvStream.readLine()
+  recvStream.close()
+
+block TCP:
+  var server = newSocket()
+  server.setSockOpt(OptReusePort, true)
+  server.bindAddr(Port(12345))
+  server.listen()
+
+  var
+    client = newSocket()
+    clientRequestStream = newWriteSocketStream(client)
+    clientResponseStream = newReadSocketStream(client)
+  client.connect("127.0.0.1", Port(12345))
+  clientRequestStream.writeLine("Hello server!")
+  clientRequestStream.flush()
+
+  var
+    incoming: Socket
+    address: string
+  server.acceptAddr(incoming, address)
+  var
+    serverRequestStream = newReadSocketStream(incoming)
+    serverResponseStream = newWriteSocketStream(incoming)
+  echo serverRequestStream.readLine()
+  serverResponseStream.writeLine("Hi there client!")
+  serverResponseStream.flush()
+  serverResponseStream.close()
+  serverRequestStream.close()
+
+  echo clientResponseStream.readLine()
+  clientResponseStream.close()
+  clientRequestStream.close()
diff --git a/tests/stdlib/tsortcall.nim b/tests/stdlib/tsortcall.nim
new file mode 100644
index 000000000..32e004921
--- /dev/null
+++ b/tests/stdlib/tsortcall.nim
@@ -0,0 +1,69 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import algorithm
+import unittest
+
+
+suite "test sort, sorted, and isSorted procs":
+  proc foosort(ships: var seq[int]) = sort(ships, system.cmp[int])
+
+  type
+    User = object
+      name: string
+      age: int
+
+  func newUser(name: string, age: int): User =
+    result.name = name
+    result.age = age
+
+  proc compareUsers(x, y: User): int =
+    if x.age == y.age: return 0
+    if x.age < y.age: return -1
+    return 1
+
+  setup:
+    var
+      unSortedIntSeq = @[1, 4, 3, 5, -1]
+      unSortedUserSeq = @[newUser("Andreas", 34), newUser("Alice", 12), newUser("Bob", 23)]
+
+    let
+      sortedIntSeq = @[-1, 1, 3, 4, 5]
+      sortedUserSeq = @[newUser("Alice", 12), newUser("Bob", 23), newUser("Andreas", 34)]
+
+  test "test the shortcut versions of sort, sorted, and isSorted":
+    check(not unSortedIntSeq.isSorted)
+    check sorted(unSortedIntSeq) == sortedIntSeq
+    check sorted(unSortedIntSeq).isSorted
+
+    unSortedIntSeq.sort()
+    check unSortedIntSeq == sortedIntSeq
+    check unSortedIntSeq.isSorted
+
+  test "test the shortcut versions with descending sort order":
+    check(not unSortedIntSeq.isSorted(SortOrder.Descending))
+    check sorted(unSortedIntSeq, SortOrder.Descending) == reversed sortedIntSeq
+    check sorted(unSortedIntSeq).isSorted(SortOrder.Ascending)
+
+    unSortedIntSeq.sort(SortOrder.Descending)
+    check unSortedIntSeq == reversed sortedIntSeq
+    check unSortedIntSeq.isSorted(SortOrder.Descending)
+
+  test "test the versions that accept a custom compareUsers function":
+    check(not unSortedUserSeq.isSorted(compareUsers))
+    check sorted(unSortedUserSeq, compareUsers) == sortedUserSeq
+    check sorted(unSortedUserSeq, compareUsers).isSorted(compareUsers)
+
+    unSortedUserSeq.sort(compareUsers)
+    check unSortedUserSeq == sortedUserSeq
+    check unSortedUserSeq.isSorted(compareUsers)
+
+  test "test the long versions with descending sort order":
+    check(not unSortedUserSeq.isSorted(compareUsers, SortOrder.Descending))
+    check sorted(unSortedUserSeq, compareUsers, SortOrder.Descending) == reversed sortedUserSeq
+    check sorted(unSortedUserSeq, compareUsers,
+                  SortOrder.Descending).isSorted(compareUsers, SortOrder.Descending)
+    unSortedUserSeq.sort(compareUsers, SortOrder.Descending)
+    check unSortedUserSeq == reversed sortedUserSeq
+    check unSortedUserSeq.isSorted(compareUsers, SortOrder.Descending)
diff --git a/tests/stdlib/tsqlitebindatas.nim b/tests/stdlib/tsqlitebindatas.nim
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/stdlib/tsqlitebindatas.nim
diff --git a/tests/stdlib/tsqlparser.nim b/tests/stdlib/tsqlparser.nim
new file mode 100644
index 000000000..6f123f21d
--- /dev/null
+++ b/tests/stdlib/tsqlparser.nim
@@ -0,0 +1,13 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''true'''
+"""
+
+# Just check that we can parse 'somesql' and render it without crashes.
+
+import parsesql, streams, os
+
+var tree = parseSql(newFileStream(parentDir(currentSourcePath) / "somesql.sql"), "somesql")
+discard renderSql(tree)
+
+echo "true"
diff --git a/tests/stdlib/tssl.nim b/tests/stdlib/tssl.nim
new file mode 100644
index 000000000..1628b9326
--- /dev/null
+++ b/tests/stdlib/tssl.nim
@@ -0,0 +1,138 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  disabled: "freebsd" # see #15713
+  disabled: "openbsd" # see #15713
+  disabled: "netbsd" # see #15713
+"""
+
+import std/[net, nativesockets, assertions, typedthreads]
+
+when defined(posix): import os, posix
+else:
+  import winlean
+  const SD_SEND = 1
+
+when not defined(ssl):
+  {.error: "This test must be compiled with -d:ssl".}
+
+const DummyData = "dummy data\n"
+
+proc abruptShutdown(port: Port) {.thread.} =
+  let clientContext = newContext(verifyMode = CVerifyNone)
+  var client = newSocket(buffered = false)
+  clientContext.wrapSocket(client)
+  client.connect("localhost", port)
+
+  discard client.recvLine()
+  client.getFd.close()
+
+proc notifiedShutdown(port: Port) {.thread.} =
+  let clientContext = newContext(verifyMode = CVerifyNone)
+  var client = newSocket(buffered = false)
+  clientContext.wrapSocket(client)
+  client.connect("localhost", port)
+
+  discard client.recvLine()
+  client.close()
+
+proc main() =
+  when defined(posix):
+    var
+      ignoreAction = Sigaction(sa_handler: SIG_IGN)
+      oldSigPipeHandler: Sigaction
+    if sigemptyset(ignoreAction.sa_mask) == -1:
+      raiseOSError(osLastError(), "Couldn't create an empty signal set")
+    if sigaction(SIGPIPE, ignoreAction, oldSigPipeHandler) == -1:
+      raiseOSError(osLastError(), "Couldn't ignore SIGPIPE")
+
+  let serverContext = newContext(verifyMode = CVerifyNone,
+                                 certFile = "tests/testdata/mycert.pem",
+                                 keyFile = "tests/testdata/mycert.pem")
+
+  block peer_close_during_write_without_shutdown:
+    var server = newSocket(buffered = false)
+    defer: server.close()
+    serverContext.wrapSocket(server)
+    server.bindAddr(address = "localhost")
+    let (_, port) = server.getLocalAddr()
+    server.listen()
+
+    var clientThread: Thread[Port]
+    createThread(clientThread, abruptShutdown, port)
+
+    var peer: Socket
+    try:
+      server.accept(peer)
+      peer.send(DummyData)
+
+      joinThread clientThread
+
+      while true:
+        # Send data until we get EPIPE.
+        peer.send(DummyData, {})
+    except OSError:
+      discard
+    finally:
+      peer.close()
+
+  when defined(posix):
+    if sigaction(SIGPIPE, oldSigPipeHandler, nil) == -1:
+      raiseOSError(osLastError(), "Couldn't restore SIGPIPE handler")
+
+  block peer_close_before_received_shutdown:
+    var server = newSocket(buffered = false)
+    defer: server.close()
+    serverContext.wrapSocket(server)
+    server.bindAddr(address = "localhost")
+    let (_, port) = server.getLocalAddr()
+    server.listen()
+
+    var clientThread: Thread[Port]
+    createThread(clientThread, abruptShutdown, port)
+
+    var peer: Socket
+    try:
+      server.accept(peer)
+      peer.send(DummyData)
+
+      joinThread clientThread
+
+      # Tell the OS to close off the write side so shutdown attempts will
+      # be met with SIGPIPE.
+      when defined(posix):
+        discard peer.getFd.shutdown(SHUT_WR)
+      else:
+        discard peer.getFd.shutdown(SD_SEND)
+    finally:
+      peer.close()
+
+  block peer_close_after_received_shutdown:
+    var server = newSocket(buffered = false)
+    defer: server.close()
+    serverContext.wrapSocket(server)
+    server.bindAddr(address = "localhost")
+    let (_, port) = server.getLocalAddr()
+    server.listen()
+
+    var clientThread: Thread[Port]
+    createThread(clientThread, notifiedShutdown, port)
+
+    var peer: Socket
+    try:
+      server.accept(peer)
+      peer.send(DummyData)
+
+      doAssert peer.recv(1024) == "" # Get the shutdown notification
+      joinThread clientThread
+
+      # Tell the OS to close off the write side so shutdown attempts will
+      # be met with SIGPIPE.
+      when defined(posix):
+        discard peer.getFd.shutdown(SHUT_WR)
+      else:
+        discard peer.getFd.shutdown(SD_SEND)
+    finally:
+      peer.close()
+
+when isMainModule: main()
diff --git a/tests/stdlib/tssl.nims b/tests/stdlib/tssl.nims
new file mode 100644
index 000000000..4739e7f07
--- /dev/null
+++ b/tests/stdlib/tssl.nims
@@ -0,0 +1,5 @@
+--threads:on
+--d:ssl
+when defined(freebsd) or defined(netbsd):
+  # See https://github.com/nim-lang/Nim/pull/15066#issuecomment-665541265 and https://github.com/nim-lang/Nim/issues/15493
+  --tlsEmulation:off
diff --git a/tests/stdlib/tstackframes.nim b/tests/stdlib/tstackframes.nim
new file mode 100644
index 000000000..b0f05d51d
--- /dev/null
+++ b/tests/stdlib/tstackframes.nim
@@ -0,0 +1,34 @@
+import std/[strformat,os,osproc,assertions]
+import stdtest/unittest_light
+
+proc main(opt: string, expected: string) =
+  const nim = getCurrentCompilerExe()
+  const file = currentSourcePath().parentDir / "mstackframes.nim"
+  let cmd = fmt"{nim} c -r --excessiveStackTrace:off --stacktraceMsgs:{opt} --hints:off {file}"
+  let (output, exitCode) = execCmdEx(cmd)
+  assertEquals output, expected
+  doAssert exitCode == 0
+
+main("on"): """
+mstackframes.nim(38)     mstackframes
+mstackframes.nim(29)     main
+  z: 0
+  z: 1
+mstackframes.nim(20)     main2 ("main2", 5, 1)
+mstackframes.nim(20)     main2 ("main2", 4, 2)
+mstackframes.nim(20)     main2 ("main2", 3, 3)
+mstackframes.nim(19)     main2 ("main2", 2, 4)
+mstackframes.nim(18)     bar ("bar ",)
+
+"""
+
+main("off"): """
+mstackframes.nim(38)     mstackframes
+mstackframes.nim(29)     main
+mstackframes.nim(20)     main2
+mstackframes.nim(20)     main2
+mstackframes.nim(20)     main2
+mstackframes.nim(19)     main2
+mstackframes.nim(18)     bar
+
+"""
diff --git a/tests/stdlib/tstaticos.nim b/tests/stdlib/tstaticos.nim
new file mode 100644
index 000000000..41ab995dd
--- /dev/null
+++ b/tests/stdlib/tstaticos.nim
@@ -0,0 +1,8 @@
+import std/[assertions, staticos, os]
+
+block:
+  static:
+    doAssert staticDirExists("MISSINGFILE") == false
+    doAssert staticFileExists("MISSINGDIR") == false
+    doAssert staticDirExists(currentSourcePath().parentDir)
+    doAssert staticFileExists(currentSourcePath())
diff --git a/tests/stdlib/tstats.nim b/tests/stdlib/tstats.nim
new file mode 100644
index 000000000..728d93d09
--- /dev/null
+++ b/tests/stdlib/tstats.nim
@@ -0,0 +1,61 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[stats, assertions]
+import std/math
+
+
+func `~=`(x, y: float32): bool =
+  math.almostEqual(x, y)
+
+template main() =
+  var rs: RunningStat
+  rs.push(@[1.0, 2.0, 1.0, 4.0, 1.0, 4.0, 1.0, 2.0])
+  doAssert(rs.n == 8)
+  doAssert rs.mean ~= 2.0
+  doAssert rs.variance() ~= 1.5
+  doAssert rs.varianceS() ~= 1.71428571
+  doAssert rs.skewness() ~= 0.81649658
+  doAssert rs.skewnessS() ~= 1.01835015
+  doAssert rs.kurtosis() ~= -1.0
+  doAssert rs.kurtosisS() ~= -0.7000000000000001
+
+  var rs1, rs2: RunningStat
+  rs1.push(@[1.0, 2.0, 1.0, 4.0])
+  rs2.push(@[1.0, 4.0, 1.0, 2.0])
+  let rs3 = rs1 + rs2
+  doAssert rs3.variance ~= rs.variance
+  doAssert rs3.skewness ~= rs.skewness
+  doAssert rs3.kurtosis ~= rs.kurtosis
+  rs1 += rs2
+  doAssert rs1.variance ~= rs.variance
+  doAssert rs1.skewness ~= rs.skewness
+  doAssert rs1.kurtosis ~= rs.kurtosis
+  rs1.clear()
+  rs1.push(@[1.0, 2.2, 1.4, 4.9])
+  doAssert rs1.sum ~= 9.5
+  doAssert rs1.mean() ~= 2.375
+
+  when not defined(cpu32):
+    # XXX For some reason on 32bit CPUs these results differ
+    var rr: RunningRegress
+    rr.push(@[0.0, 1.0, 2.8, 3.0, 4.0], @[0.0, 1.0, 2.3, 3.0, 4.0])
+    doAssert rr.slope() ~= 0.9695585996955861
+    doAssert rr.intercept() ~= -0.03424657534246611
+    doAssert rr.correlation() ~= 0.9905100362239381
+    var rr1, rr2: RunningRegress
+    rr1.push(@[0.0, 1.0], @[0.0, 1.0])
+    rr2.push(@[2.8, 3.0, 4.0], @[2.3, 3.0, 4.0])
+    let rr3 = rr1 + rr2
+    doAssert rr3.correlation() ~= rr.correlation()
+    doAssert rr3.slope() ~= rr.slope()
+    doAssert rr3.intercept() ~= rr.intercept()
+
+  block: # bug #18718
+    var rs: RunningStat
+    rs.push(-1.0)
+    doAssert rs.max == -1.0
+
+static: main()
+main()
diff --git a/tests/stdlib/tstdlib_issues.nim b/tests/stdlib/tstdlib_issues.nim
new file mode 100644
index 000000000..b7b806db8
--- /dev/null
+++ b/tests/stdlib/tstdlib_issues.nim
@@ -0,0 +1,110 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+output: '''
+02
+1
+2
+3
+4
+5
+9
+b = true
+123456789
+Second readLine raised an exception
+123456789
+1
+2aaaaaaaa
+3bbbbbbb
+'''
+"""
+
+import std/[terminal, colors, re, encodings, strutils, os, assertions, syncio]
+
+
+block t9394:
+  let codeFg = ansiForegroundColorCode(colAliceBlue)
+  let codeBg = ansiBackgroundColorCode(colAliceBlue)
+
+  doAssert codeFg == "\27[38;2;240;248;255m"
+  doAssert codeBg == "\27[48;2;240;248;255m"
+
+
+
+block t5382:
+  let regexp = re"^\/([0-9]{2})\.html$"
+  var matches: array[1, string]
+  discard "/02.html".find(regexp, matches)
+  echo matches[0]
+
+
+
+block tcount:
+  # bug #1845, #2224
+  var arr = [3,2,1,5,4]
+
+  # bubble sort
+  for i in low(arr)..high(arr):
+    for j in i+1..high(arr): # Error: unhandled exception: value out of range: 5 [RangeDefect]
+      if arr[i] > arr[j]:
+        let tmp = arr[i]
+        arr[i] = arr[j]
+        arr[j] = tmp
+
+  for i in low(arr)..high(arr):
+    echo arr[i]
+
+  # check this terminates:
+  for x in countdown('\255', '\0'):
+    discard
+
+
+
+block t8468:
+  when defined(windows):
+    var utf16to8 = open(destEncoding = "utf-16", srcEncoding = "utf-8")
+    var s = "some string"
+    var c = utf16to8.convert(s)
+
+    var z = newStringOfCap(s.len * 2)
+    for x in s:
+      z.add x
+      z.add chr(0)
+
+    doAssert z == c
+
+
+
+block t5349:
+  const fn = "file9char.txt"
+  writeFile(fn, "123456789")
+
+  var f = syncio.open(fn)
+  echo getFileSize(f)
+
+  var line = newString(10)
+  try:
+    let b = readLine(f, line)
+    echo "b = ", b
+  except:
+    echo "First readLine raised an exception"
+  echo line
+
+  try:
+    line = readLine(f)
+    let b = readLine(f, line)
+    echo "b = ", b
+  except:
+    echo "Second readLine raised an exception"
+  echo line
+  f.close()
+
+  removeFile(fn)
+  # bug #8961
+  writeFile("test.txt", "1\C\L2aaaaaaaa\C\L3bbbbbbb")
+
+  for line in lines("test.txt"):
+    echo line
+
+block t9456:
+  var f: File
+  f.close()
diff --git a/tests/stdlib/tstdlib_various.nim b/tests/stdlib/tstdlib_various.nim
new file mode 100644
index 000000000..bac5018fa
--- /dev/null
+++ b/tests/stdlib/tstdlib_various.nim
@@ -0,0 +1,240 @@
+discard """
+matrix: "--mm:refc"
+output: '''
+abc
+def
+definition
+prefix
+xyz
+def
+definition
+Hi Andreas! How do you feel, Rumpf?
+
+@[0, 2, 1]
+@[1, 0, 2]
+@[1, 2, 0]
+@[2, 0, 1]
+@[2, 1, 0]
+@[2, 0, 1]
+@[1, 2, 0]
+@[1, 0, 2]
+@[0, 2, 1]
+@[0, 1, 2]
+055this should be the casehugh@["(", "+", " 1", " 2", ")"]
+[5]
+[4, 5]
+[3, 4, 5]
+[2, 3, 4, 5]
+[2, 3, 4, 5, 6]
+[1, 2, 3, 4, 5, 6]
+<h1><a href="http://force7.de/nim">Nim</a></h1>
+'''
+"""
+
+import
+  std/[critbits, sets, strutils, tables, random, algorithm, re, ropes,
+  segfaults, lists, parsesql, streams, os, htmlgen, xmltree, strtabs]
+import std/[syncio, assertions]
+
+block tcritbits:
+  var r: CritBitTree[void]
+  r.incl "abc"
+  r.incl "xyz"
+  r.incl "def"
+  r.incl "definition"
+  r.incl "prefix"
+  doAssert r.contains"def"
+  #r.del "def"
+
+  for w in r.items:
+    echo w
+  for w in r.itemsWithPrefix("de"):
+    echo w
+
+
+
+block testequivalence:
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3]), "equivalent or subset")
+  doAssert((not(toHashSet(@[1,2,3]) <= toHashSet(@[1,2]))), "equivalent or subset")
+  doAssert(toHashSet(@[1,2,3]) <= toHashSet(@[1,2,3,4]), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2,3]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) < toHashSet(@[1,2]))), "strict subset")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3,4]))), "==")
+  doAssert(toHashSet(@[1,2,3]) == toHashSet(@[1,2,3]), "==")
+  doAssert((not(toHashSet(@[1,2,3]) == toHashSet(@[1,2]))), "==")
+
+
+
+block tformat:
+  echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])
+
+
+
+block tnilecho:
+  var x = @["1", "", "3"]
+  doAssert $x == """@["1", "", "3"]"""
+
+
+
+block torderedtable:
+  var t = initOrderedTable[int,string]()
+
+  # this tests issue #5917
+  var data = newSeq[int]()
+  for i in 0..<1000:
+    var x = rand(1000)
+    if x notin t: data.add(x)
+    t[x] = "meh"
+
+  # this checks that keys are re-inserted
+  # in order when table is enlarged.
+  var i = 0
+  for k, v in t:
+    doAssert(k == data[i])
+    doAssert(v == "meh")
+    inc(i)
+
+
+
+block tpermutations:
+  var v = @[0, 1, 2]
+  while v.nextPermutation():
+    echo v
+  while v.prevPermutation():
+    echo v
+
+
+
+block treguse:
+  proc main(a, b: int) =
+    var x = 0
+    write(stdout, x)
+    if x == 0:
+      var y = 55
+      write(stdout, y)
+      write(stdout, "this should be the case")
+      var input = "<no input>"
+      if input == "Andreas":
+        write(stdout, "wow")
+      else:
+        write(stdout, "hugh")
+    else:
+      var z = 66
+      write(stdout, z) # "bug!")
+
+  main(45, 1000)
+
+
+
+block treloop:
+  let str = "(+ 1 2)"
+  var tokenRE = re"""[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)"""
+  echo str.findAll(tokenRE)
+
+
+
+block tropes:
+  var
+    r1 = rope("")
+    r2 = rope("123")
+  doAssert r1.len == 0
+  doAssert r2.len == 3
+  doAssert $r1 == ""
+  doAssert $r2 == "123"
+
+  r1.add("123")
+  r2.add("456")
+  doAssert r1.len == 3
+  doAssert r2.len == 6
+  doAssert $r1 == "123"
+  doAssert $r2 == "123456"
+  doAssert $r1[1] == "2"
+  doAssert $r2[2] == "3"
+
+
+
+block tsegfaults:
+  when not defined(arm64):
+    var crashes = 0
+    proc main =
+      try:
+        var x: ptr int
+        echo x[]
+        try:
+          raise newException(ValueError, "not a crash")
+        except ValueError:
+          discard
+      except NilAccessDefect:
+        inc crashes
+    for i in 0..5:
+      main()
+    assert crashes == 6
+
+
+
+block tsinglylinkedring:
+  var r = initSinglyLinkedRing[int]()
+  r.prepend(5)
+  echo r
+  r.prepend(4)
+  echo r
+  r.prepend(3)
+  echo r
+  r.prepend(2)
+  echo r
+  r.append(6)
+  echo r
+  r.prepend(1)
+  echo r
+
+
+
+block tsplit:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert s == "##abc#xy#z"
+
+
+
+block tsplit2:
+  var s = ""
+  for w in split("|abc|xy|z", {'|'}):
+    s.add("#")
+    s.add(w)
+
+  doAssert "true".split("") == @["true"]
+
+
+
+block tsqlparser:
+  # Just check that we can parse 'somesql' and render it without crashes.
+  var tree = parseSql(newFileStream( parentDir(currentSourcePath) / "somesql.sql"), "somesql")
+  discard renderSql(tree)
+
+
+
+block txmlgen:
+  var nim = "Nim"
+  echo h1(a(href="http://force7.de/nim", nim))
+
+
+
+block txmltree:
+  var x = <>a(href="nim.de", newText("www.nim-test.de"))
+
+  doAssert($x == "<a href=\"nim.de\">www.nim-test.de</a>")
+  doAssert(newText("foo").innerText == "foo")
+  doAssert(newEntity("bar").innerText == "bar")
+  doAssert(newComment("baz").innerText == "")
+
+  let y = newXmlTree("x", [
+    newText("foo"),
+    newXmlTree("y", [
+      newText("bar")
+    ])
+  ])
+  doAssert(y.innerText == "foobar")
diff --git a/tests/stdlib/tstrbasics.nim b/tests/stdlib/tstrbasics.nim
new file mode 100644
index 000000000..a965ff15f
--- /dev/null
+++ b/tests/stdlib/tstrbasics.nim
@@ -0,0 +1,103 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[strbasics, sugar, assertions]
+
+template strip2(input: string, args: varargs[untyped]): untyped =
+  var a = input
+  when varargsLen(args) > 0:
+    strip(a, args)
+  else:
+    strip(a)
+  a
+
+proc main() =
+  block: # strip
+    block: # bug #17173
+      var a = "  vhellov   "
+      strip(a)
+      doAssert a == "vhellov"
+
+    doAssert strip2("  vhellov   ") == "vhellov"
+    doAssert strip2("  vhellov   ", leading = false) == "  vhellov"
+    doAssert strip2("  vhellov   ", trailing = false) == "vhellov   "
+    doAssert strip2("vhellov", chars = {'v'}) == "hello"
+    doAssert strip2("vhellov", leading = false, chars = {'v'}) == "vhello"
+    doAssert strip2("blaXbla", chars = {'b', 'a'}) == "laXbl"
+    doAssert strip2("blaXbla", chars = {'b', 'a', 'l'}) == "X"
+    doAssert strip2("xxxxxx", chars={'x'}) == ""
+    doAssert strip2("x", chars={'x'}) == ""
+    doAssert strip2("x", chars={'1'}) == "x"
+    doAssert strip2("", chars={'x'}) == ""
+    doAssert strip2("xxx xxx", chars={'x'}) == " "
+    doAssert strip2("xxx  wind", chars={'x'}) == "  wind"
+    doAssert strip2("xxx  iii", chars={'i'}) == "xxx  "
+
+    block:
+      var a = "xxx  iii"
+      doAssert a.dup(strip(chars = {'i'})) == "xxx  "
+      doAssert a.dup(strip(chars = {' '})) == "xxx  iii"
+      doAssert a.dup(strip(chars = {'x'})) == "  iii"
+      doAssert a.dup(strip(chars = {'x', ' '})) == "iii"
+      doAssert a.dup(strip(chars = {'x', 'i'})) == "  "
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+    block:
+      var a = "x  i"
+      doAssert a.dup(strip(chars = {'i'})) == "x  "
+      doAssert a.dup(strip(chars = {' '})) == "x  i"
+      doAssert a.dup(strip(chars = {'x'})) == "  i"
+      doAssert a.dup(strip(chars = {'x', ' '})) == "i"
+      doAssert a.dup(strip(chars = {'x', 'i'})) == "  "
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+    block:
+      var a = ""
+      doAssert a.dup(strip(chars = {'i'})).len == 0
+      doAssert a.dup(strip(chars = {' '})).len == 0
+      doAssert a.dup(strip(chars = {'x'})).len == 0
+      doAssert a.dup(strip(chars = {'x', ' '})).len == 0
+      doAssert a.dup(strip(chars = {'x', 'i'})).len == 0
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+    block:
+      var a = " "
+      doAssert a.dup(strip(chars = {'i'})) == " "
+      doAssert a.dup(strip(chars = {' '})).len == 0
+      doAssert a.dup(strip(chars = {'x'})) == " "
+      doAssert a.dup(strip(chars = {'x', ' '})).len == 0
+      doAssert a.dup(strip(chars = {'x', 'i'})) == " "
+      doAssert a.dup(strip(chars = {'x', 'i', ' '})).len == 0
+
+  block: # setSlice
+    var a = "Hello, Nim!"
+    doAssert a.dup(setSlice(7 .. 9)) == "Nim"
+    doAssert a.dup(setSlice(0 .. 0)) == "H"
+    doAssert a.dup(setSlice(0 .. 1)) == "He"
+    doAssert a.dup(setSlice(0 .. 10)) == a
+    doAssert a.dup(setSlice(1 .. 0)).len == 0
+    doAssert a.dup(setSlice(20 .. -1)).len == 0
+
+    doAssertRaises(AssertionDefect):
+      discard a.dup(setSlice(-1 .. 1))
+
+    doAssertRaises(AssertionDefect):
+      discard a.dup(setSlice(1 .. 11))
+
+  block: # add
+    var a0 = "hi"
+    var b0 = "foobar"
+    when nimvm:
+      discard # pending bug #15952
+    else:
+      a0.add b0.toOpenArray(1,3)
+      doAssert a0 == "hioob"
+    proc fn(c: openArray[char]): string =
+      result.add c
+    doAssert fn("def") == "def"
+    doAssert fn(['d','\0', 'f'])[2] == 'f'
+
+static: main()
+main()
diff --git a/tests/stdlib/tstreams.nim b/tests/stdlib/tstreams.nim
new file mode 100644
index 000000000..60c63b450
--- /dev/null
+++ b/tests/stdlib/tstreams.nim
@@ -0,0 +1,107 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  input: "Arne"
+  output: '''
+Hello! What is your name?
+Nice name: Arne
+fs is: nil
+threw exception
+_heh_
+'''
+  nimout: '''
+I
+AM
+GROOT
+'''
+"""
+
+
+import std/[syncio, streams, assertions]
+
+
+block tstreams:
+  var outp = newFileStream(stdout)
+  var inp = newFileStream(stdin)
+  writeLine(outp, "Hello! What is your name?")
+  var line = readLine(inp)
+  writeLine(outp, "Nice name: " & line)
+
+
+block tstreams2:
+  var
+    fs = newFileStream("amissingfile.txt")
+    line = ""
+  echo "fs is: ",repr(fs)
+  if not isNil(fs):
+    while fs.readLine(line):
+      echo line
+    fs.close()
+
+
+block tstreams3:
+  try:
+    var fs = openFileStream("shouldneverexist.txt")
+  except IOError:
+    echo "threw exception"
+
+  static:
+    var s = newStringStream("I\nAM\nGROOT")
+    for line in s.lines:
+      echo line
+    s.close
+
+
+block:
+  let fs = newFileStream("amissingfile.txt")
+  defer: fs.close()
+  doAssert isNil(fs)
+
+# bug #12410
+
+var a = newStringStream "hehohihahuhyh"
+a.readDataStrImpl = nil
+
+var buffer = "_ooo_"
+
+doAssert a.readDataStr(buffer, 1..3) == 3
+
+echo buffer
+
+
+block:
+  var ss = newStringStream("The quick brown fox jumped over the lazy dog.\nThe lazy dog ran")
+  doAssert(ss.getPosition == 0)
+  doAssert(ss.peekStr(5) == "The q")
+  doAssert(ss.getPosition == 0) # haven't moved
+  doAssert(ss.readStr(5) == "The q")
+  doAssert(ss.getPosition == 5) # did move
+  doAssert(ss.peekLine() == "uick brown fox jumped over the lazy dog.")
+  doAssert(ss.getPosition == 5) # haven't moved
+  var str = newString(100)
+  doAssert(ss.peekLine(str))
+  doAssert(str == "uick brown fox jumped over the lazy dog.")
+  doAssert(ss.getPosition == 5) # haven't moved
+  # bug #19707 - Ensure we dont error with writing over literals on arc/orc
+  ss.setPosition(0)
+  ss.write("hello")
+  ss.setPosition(0)
+  doAssert(ss.peekStr(5) == "hello")
+
+# bug #19716
+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"
+  doAssert strm.readDataStr(buffer, 0..3) == 4
+  doAssert buffer == "abcd5"
+  strm.close()
+
+static: main()
+main()
diff --git a/tests/stdlib/tstrformat.nim b/tests/stdlib/tstrformat.nim
new file mode 100644
index 000000000..ff406f898
--- /dev/null
+++ b/tests/stdlib/tstrformat.nim
@@ -0,0 +1,590 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import genericstrformat
+import std/[strformat, strutils, times, tables, json]
+
+import std/[assertions, formatfloat]
+import std/objectdollar
+
+proc main() =
+  block: # issue #7632
+    doAssert works(5) == "formatted  5"
+    doAssert fails0(6) == "formatted  6"
+    doAssert fails(7) == "formatted  7"
+    doAssert fails2[0](8) == "formatted  8"
+
+  block: # other tests
+    type Obj = object
+
+    proc `$`(o: Obj): string = "foobar"
+
+    # for custom types, formatValue needs to be overloaded.
+    template formatValue(result: var string; value: Obj; specifier: string) =
+      result.formatValue($value, specifier)
+
+    var o: Obj
+    doAssert fmt"{o}" == "foobar"
+    doAssert fmt"{o:10}" == "foobar    "
+
+    doAssert fmt"{o=}" == "o=foobar"
+    doAssert fmt"{o=:10}" == "o=foobar    "
+
+  block: # see issue #7933
+    var str = "abc"
+    doAssert fmt">7.1 :: {str:>7.1}" == ">7.1 ::       a"
+    doAssert fmt">7.2 :: {str:>7.2}" == ">7.2 ::      ab"
+    doAssert fmt">7.3 :: {str:>7.3}" == ">7.3 ::     abc"
+    doAssert fmt">7.9 :: {str:>7.9}" == ">7.9 ::     abc"
+    doAssert fmt">7.0 :: {str:>7.0}" == ">7.0 ::        "
+    doAssert fmt" 7.1 :: {str:7.1}" == " 7.1 :: a      "
+    doAssert fmt" 7.2 :: {str:7.2}" == " 7.2 :: ab     "
+    doAssert fmt" 7.3 :: {str:7.3}" == " 7.3 :: abc    "
+    doAssert fmt" 7.9 :: {str:7.9}" == " 7.9 :: abc    "
+    doAssert fmt" 7.0 :: {str:7.0}" == " 7.0 ::        "
+    doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 ::    a   "
+    doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 ::   ab   "
+    doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 ::   abc  "
+    doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 ::   abc  "
+    doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 ::        "
+
+    doAssert fmt">7.1 :: {str=:>7.1}" == ">7.1 :: str=      a"
+    doAssert fmt">7.2 :: {str=:>7.2}" == ">7.2 :: str=     ab"
+    doAssert fmt">7.3 :: {str=:>7.3}" == ">7.3 :: str=    abc"
+    doAssert fmt">7.9 :: {str=:>7.9}" == ">7.9 :: str=    abc"
+    doAssert fmt">7.0 :: {str=:>7.0}" == ">7.0 :: str=       "
+    doAssert fmt" 7.1 :: {str=:7.1}" == " 7.1 :: str=a      "
+    doAssert fmt" 7.2 :: {str=:7.2}" == " 7.2 :: str=ab     "
+    doAssert fmt" 7.3 :: {str=:7.3}" == " 7.3 :: str=abc    "
+    doAssert fmt" 7.9 :: {str=:7.9}" == " 7.9 :: str=abc    "
+    doAssert fmt" 7.0 :: {str=:7.0}" == " 7.0 :: str=       "
+    doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str=   a   "
+    doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str=  ab   "
+    doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str=  abc  "
+    doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=  abc  "
+    doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str=       "
+    str = "äöüe\u0309\u0319o\u0307\u0359"
+    doAssert fmt"^7.1 :: {str:^7.1}" == "^7.1 ::    ä   "
+    doAssert fmt"^7.2 :: {str:^7.2}" == "^7.2 ::   äö   "
+    doAssert fmt"^7.3 :: {str:^7.3}" == "^7.3 ::   äöü  "
+    doAssert fmt"^7.0 :: {str:^7.0}" == "^7.0 ::        "
+
+    doAssert fmt"^7.1 :: {str=:^7.1}" == "^7.1 :: str=   ä   "
+    doAssert fmt"^7.2 :: {str=:^7.2}" == "^7.2 :: str=  äö   "
+    doAssert fmt"^7.3 :: {str=:^7.3}" == "^7.3 :: str=  äöü  "
+    doAssert fmt"^7.0 :: {str=:^7.0}" == "^7.0 :: str=       "
+    # this is actually wrong, but the unicode module has no support for graphemes
+    doAssert fmt"^7.4 :: {str:^7.4}" == "^7.4 ::  äöüe  "
+    doAssert fmt"^7.9 :: {str:^7.9}" == "^7.9 :: äöüe\u0309\u0319o\u0307\u0359"
+
+    doAssert fmt"^7.4 :: {str=:^7.4}" == "^7.4 :: str= äöüe  "
+    doAssert fmt"^7.9 :: {str=:^7.9}" == "^7.9 :: str=äöüe\u0309\u0319o\u0307\u0359"
+
+  block: # see issue #7932
+    doAssert fmt"{15:08}" == "00000015" # int, works
+    doAssert fmt"{1.5:08}" == "000001.5" # float, works
+    doAssert fmt"{1.5:0>8}" == "000001.5" # workaround using fill char works for positive floats
+    doAssert fmt"{-1.5:0>8}" == "0000-1.5" # even that does not work for negative floats
+    doAssert fmt"{-1.5:08}" == "-00001.5" # works
+    doAssert fmt"{1.5:+08}" == "+00001.5" # works
+    doAssert fmt"{1.5: 08}" == " 00001.5" # works
+
+    doAssert fmt"{15=:08}" == "15=00000015" # int, works
+    doAssert fmt"{1.5=:08}" == "1.5=000001.5" # float, works
+    doAssert fmt"{1.5=:0>8}" == "1.5=000001.5" # workaround using fill char works for positive floats
+    doAssert fmt"{-1.5=:0>8}" == "-1.5=0000-1.5" # even that does not work for negative floats
+    doAssert fmt"{-1.5=:08}" == "-1.5=-00001.5" # works
+    doAssert fmt"{1.5=:+08}" == "1.5=+00001.5" # works
+    doAssert fmt"{1.5=: 08}" == "1.5= 00001.5" # works
+
+  block: # only add explicitly requested sign if value != -0.0 (neg zero)
+    doAssert fmt"{-0.0:g}" == "-0"
+    doAssert fmt"{-0.0:+g}" == "-0"
+    doAssert fmt"{-0.0: g}" == "-0"
+    doAssert fmt"{0.0:g}" == "0"
+    doAssert fmt"{0.0:+g}" == "+0"
+    doAssert fmt"{0.0: g}" == " 0"
+
+    doAssert fmt"{-0.0=:g}" == "-0.0=-0"
+    doAssert fmt"{-0.0=:+g}" == "-0.0=-0"
+    doAssert fmt"{-0.0=: g}" == "-0.0=-0"
+    doAssert fmt"{0.0=:g}" == "0.0=0"
+    doAssert fmt"{0.0=:+g}" == "0.0=+0"
+    doAssert fmt"{0.0=: g}" == "0.0= 0"
+
+  block: # seq format
+    let data1 = [1'i64, 10000'i64, 10000000'i64]
+    let data2 = [10000000'i64, 100'i64, 1'i64]
+
+    proc formatValue(result: var string; value: (array|seq|openArray); specifier: string) =
+      result.add "["
+      for i, it in value:
+        if i != 0:
+          result.add ", "
+        result.formatValue(it, specifier)
+      result.add "]"
+
+    doAssert fmt"data1: {data1:8} #" == "data1: [       1,    10000, 10000000] #"
+    doAssert fmt"data2: {data2:8} =" == "data2: [10000000,      100,        1] ="
+
+    doAssert fmt"data1: {data1=:8} #" == "data1: data1=[       1,    10000, 10000000] #"
+    doAssert fmt"data2: {data2=:8} =" == "data2: data2=[10000000,      100,        1] ="
+
+  block: # custom format Value
+    type
+      Vec2[T] = object
+        x,y: T
+
+    proc formatValue[T](result: var string; value: Vec2[T]; specifier: string) =
+      result.add '['
+      result.formatValue value.x, specifier
+      result.add ", "
+      result.formatValue value.y, specifier
+      result.add "]"
+
+    let v1 = Vec2[float32](x:1.0, y: 2.0)
+    let v2 = Vec2[int32](x:1, y: 1337)
+    doAssert fmt"v1: {v1:+08}  v2: {v2:>4}" == "v1: [+0000001, +0000002]  v2: [   1, 1337]"
+    doAssert fmt"v1: {v1=:+08}  v2: {v2=:>4}" == "v1: v1=[+0000001, +0000002]  v2: v2=[   1, 1337]"
+
+  block: # bug #11012
+    type
+      Animal = object
+        name, species: string
+      AnimalRef = ref Animal
+
+    proc print_object(animalAddr: AnimalRef): string =
+      fmt"Received {animalAddr[]}"
+
+    doAssert print_object(AnimalRef(name: "Foo", species: "Bar")) == """Received (name: "Foo", species: "Bar")"""
+
+  block: # bug #11723
+    let pos: Positive = 64
+    doAssert fmt"{pos:3}" == " 64"
+    doAssert fmt"{pos:3b}" == "1000000"
+    doAssert fmt"{pos:3d}" == " 64"
+    doAssert fmt"{pos:3o}" == "100"
+    doAssert fmt"{pos:3x}" == " 40"
+    doAssert fmt"{pos:3X}" == " 40"
+
+    doAssert fmt"{pos=:3}" == "pos= 64"
+    doAssert fmt"{pos=:3b}" == "pos=1000000"
+    doAssert fmt"{pos=:3d}" == "pos= 64"
+    doAssert fmt"{pos=:3o}" == "pos=100"
+    doAssert fmt"{pos=:3x}" == "pos= 40"
+    doAssert fmt"{pos=:3X}" == "pos= 40"
+
+    let nat: Natural = 64
+    doAssert fmt"{nat:3}" == " 64"
+    doAssert fmt"{nat:3b}" == "1000000"
+    doAssert fmt"{nat:3d}" == " 64"
+    doAssert fmt"{nat:3o}" == "100"
+    doAssert fmt"{nat:3x}" == " 40"
+    doAssert fmt"{nat:3X}" == " 40"
+
+    doAssert fmt"{nat=:3}" == "nat= 64"
+    doAssert fmt"{nat=:3b}" == "nat=1000000"
+    doAssert fmt"{nat=:3d}" == "nat= 64"
+    doAssert fmt"{nat=:3o}" == "nat=100"
+    doAssert fmt"{nat=:3x}" == "nat= 40"
+    doAssert fmt"{nat=:3X}" == "nat= 40"
+
+  block: # bug #12612
+    proc my_proc() =
+      const value = "value"
+      const a = &"{value}"
+      doAssert a == value
+
+      const b = &"{value=}"
+      doAssert b == "value=" & value
+
+    my_proc()
+
+  block:
+    template fmt(pattern: string; openCloseChar: char): untyped =
+      fmt(pattern, openCloseChar, openCloseChar)
+
+    let
+      testInt = 123
+      testStr = "foobar"
+      testFlt = 3.141592
+    doAssert ">><<".fmt('<', '>') == "><"
+    doAssert " >> << ".fmt('<', '>') == " > < "
+    doAssert "<<>>".fmt('<', '>') == "<>"
+    doAssert " << >> ".fmt('<', '>') == " < > "
+    doAssert "''".fmt('\'') == "'"
+    doAssert "''''".fmt('\'') == "''"
+    doAssert "'' ''".fmt('\'') == "' '"
+    doAssert "<testInt>".fmt('<', '>') == "123"
+    doAssert "<testInt>".fmt('<', '>') == "123"
+    doAssert "'testFlt:1.2f'".fmt('\'') == "3.14"
+    doAssert "<testInt><testStr>".fmt('<', '>') == "123foobar"
+    doAssert """ ""{"123+123"}"" """.fmt('"') == " \"{246}\" "
+    doAssert "(((testFlt:1.2f)))((111))".fmt('(', ')') == "(3.14)(111)"
+    doAssert """(()"foo" & "bar"())""".fmt(')', '(') == "(foobar)"
+    doAssert "{}abc`testStr' `testFlt:1.2f' `1+1' ``".fmt('`', '\'') == "{}abcfoobar 3.14 2 `"
+    doAssert """x = '"foo" & "bar"'
+                y = '123 + 111'
+                z = '3 in {2..7}'
+             """.fmt('\'') ==
+             """x = foobar
+                y = 234
+                z = true
+             """
+
+  block: # tests from the very own strformat documentation!
+    let msg = "hello"
+    doAssert fmt"{msg}\n" == "hello\\n"
+
+    doAssert &"{msg}\n" == "hello\n"
+
+    doAssert fmt"{msg}{'\n'}" == "hello\n"
+    doAssert fmt("{msg}\n") == "hello\n"
+    doAssert "{msg}\n".fmt == "hello\n"
+
+    doAssert fmt"{msg=}\n" == "msg=hello\\n"
+
+    doAssert &"{msg=}\n" == "msg=hello\n"
+
+    doAssert fmt"{msg=}{'\n'}" == "msg=hello\n"
+    doAssert fmt("{msg=}\n") == "msg=hello\n"
+    doAssert "{msg=}\n".fmt == "msg=hello\n"
+
+    doAssert &"""{"abc":>4}""" == " abc"
+    doAssert &"""{"abc":<4}""" == "abc "
+
+    doAssert fmt"{-12345:08}" == "-0012345"
+    doAssert fmt"{-1:3}" == " -1"
+    doAssert fmt"{-1:03}" == "-01"
+    doAssert fmt"{16:#X}" == "0x10"
+
+    doAssert fmt"{123.456}" == "123.456"
+    doAssert fmt"{123.456:>9.3f}" == "  123.456"
+    doAssert fmt"{123.456:9.3f}" == "  123.456"
+    doAssert fmt"{123.456:9.4f}" == " 123.4560"
+    doAssert fmt"{123.456:>9.0f}" == "     123."
+    doAssert fmt"{123.456:<9.4f}" == "123.4560 "
+
+    doAssert fmt"{123.456:e}" == "1.234560e+02"
+    doAssert fmt"{123.456:>13e}" == " 1.234560e+02"
+    doAssert fmt"{123.456:13e}" == " 1.234560e+02"
+
+    doAssert &"""{"abc"=:>4}""" == "\"abc\"= abc"
+    doAssert &"""{"abc"=:<4}""" == "\"abc\"=abc "
+
+    doAssert fmt"{-12345=:08}" == "-12345=-0012345"
+    doAssert fmt"{-1=:3}" == "-1= -1"
+    doAssert fmt"{-1=:03}" == "-1=-01"
+    doAssert fmt"{16=:#X}" == "16=0x10"
+
+    doAssert fmt"{123.456=}" == "123.456=123.456"
+    doAssert fmt"{123.456=:>9.3f}" == "123.456=  123.456"
+    doAssert fmt"{123.456=:9.3f}" == "123.456=  123.456"
+    doAssert fmt"{123.456=:9.4f}" == "123.456= 123.4560"
+    doAssert fmt"{123.456=:>9.0f}" == "123.456=     123."
+    doAssert fmt"{123.456=:<9.4f}" == "123.456=123.4560 "
+
+    doAssert fmt"{123.456=:e}" == "123.456=1.234560e+02"
+    doAssert fmt"{123.456=:>13e}" == "123.456= 1.234560e+02"
+    doAssert fmt"{123.456=:13e}" == "123.456= 1.234560e+02"
+
+    let x = 3.14
+    doAssert fmt"{(if x!=0: 1.0/x else: 0):.5}" == "0.31847"
+    doAssert fmt"""{(block:
+      var res: string
+      for i in 1..15:
+        res.add (if i mod 15 == 0: "FizzBuzz"
+          elif i mod 5 == 0: "Buzz"
+          elif i mod 3 == 0: "Fizz"
+          else: $i) & " "
+      res)}""" == "1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz "
+
+    doAssert fmt"""{ "\{(" & msg & ")\}" }""" == "{(hello)}"
+    doAssert fmt"""{{({ msg })}}""" == "{(hello)}"
+    doAssert fmt"""{ $(\{msg:1,"world":2\}) }""" == """[("hello", 1), ("world", 2)]"""
+  block: # tests for debug format string
+    var name = "hello"
+    let age = 21
+    const hobby = "swim"
+    doAssert fmt"{age*9 + 16=}" == "age*9 + 16=205"
+    doAssert &"name: {name    =}\nage: {  age  =: >7}\nhobby: {   hobby=  : 8}" ==
+          "name: name    =hello\nage:   age  =     21\nhobby:    hobby=  swim    "
+    doAssert fmt"{age  ==  12}" == "false"
+    doAssert fmt"{name.toUpperAscii() = }" == "name.toUpperAscii() = HELLO"
+    doAssert fmt"{name.toUpperAscii( ) =  }" == "name.toUpperAscii( ) =  HELLO"
+    doAssert fmt"{  toUpperAscii(  s  =  name  )  =   }" == "  toUpperAscii(  s  =  name  )  =   HELLO"
+    doAssert fmt"{  strutils.toUpperAscii(  s  =  name  )  =   }" == "  strutils.toUpperAscii(  s  =  name  )  =   HELLO"
+    doAssert fmt"{age==12}" == "false"
+    doAssert fmt"{age!= 12}" == "true"
+    doAssert fmt"{age  <=  12}" == "false"
+    for i in 1 .. 10:
+      doAssert fmt"{age.float =: .2f}" == "age.float = 21.00"
+    doAssert fmt"{age.float() =:.3f}" == "age.float() =21.000"
+    doAssert fmt"{float age=  :.3f}" == "float age=  21.000"
+    doAssert fmt"{12 == int(`!=`(age, 12))}" == "false"
+    doAssert fmt"{0==1}" == "false"
+
+  block: # It is space sensitive.
+    let x = "12"
+    doAssert fmt"{x=:}" == "x=12"
+    doAssert fmt"{x=}" == "x=12"
+    doAssert fmt"{x =:}" == "x =12"
+    doAssert fmt"{x =}" == "x =12"
+    doAssert fmt"{x= :}" == "x= 12"
+    doAssert fmt"{x= }" == "x= 12"
+    doAssert fmt"{x = :}" == "x = 12"
+    doAssert fmt"{x = }" == "x = 12"
+    doAssert fmt"{x   =  :}" == "x   =  12"
+    doAssert fmt"{x   =  }" == "x   =  12"
+
+  block:
+    let x = "hello"
+    doAssert fmt"{x=}" == "x=hello"
+    doAssert fmt"{x =}" == "x =hello"
+
+    let y = 3.1415926
+    doAssert fmt"{y=:.2f}" == fmt"y={y:.2f}"
+    doAssert fmt"{y=}" == fmt"y={y}"
+    doAssert fmt"{y = : <8}" == fmt"y = 3.14159 "
+
+    proc hello(a: string, b: float): int = 12
+    template foo(a: string, b: float): int = 18
+
+    doAssert fmt"{hello(x, y)=}" == "hello(x, y)=12"
+    doAssert fmt"{hello(x, y) =}" == "hello(x, y) =12"
+    doAssert fmt"{hello(x, y)= }" == "hello(x, y)= 12"
+    doAssert fmt"{hello(x, y) = }" == "hello(x, y) = 12"
+
+    doAssert fmt"{hello x, y=}" == "hello x, y=12"
+    doAssert fmt"{hello x, y =}" == "hello x, y =12"
+    doAssert fmt"{hello x, y= }" == "hello x, y= 12"
+    doAssert fmt"{hello x, y = }" == "hello x, y = 12"
+
+    doAssert fmt"{x.hello(y)=}" == "x.hello(y)=12"
+    doAssert fmt"{x.hello(y) =}" == "x.hello(y) =12"
+    doAssert fmt"{x.hello(y)= }" == "x.hello(y)= 12"
+    doAssert fmt"{x.hello(y) = }" == "x.hello(y) = 12"
+
+    doAssert fmt"{foo(x, y)=}" == "foo(x, y)=18"
+    doAssert fmt"{foo(x, y) =}" == "foo(x, y) =18"
+    doAssert fmt"{foo(x, y)= }" == "foo(x, y)= 18"
+    doAssert fmt"{foo(x, y) = }" == "foo(x, y) = 18"
+
+    doAssert fmt"{x.foo(y)=}" == "x.foo(y)=18"
+    doAssert fmt"{x.foo(y) =}" == "x.foo(y) =18"
+    doAssert fmt"{x.foo(y)= }" == "x.foo(y)= 18"
+    doAssert fmt"{x.foo(y) = }" == "x.foo(y) = 18"
+
+  block:
+    template check(actual, expected: string) =
+      doAssert actual == expected
+
+    # Basic tests
+    let s = "string"
+    check &"{0} {s}", "0 string"
+    check &"{s[0..2].toUpperAscii}", "STR"
+    check &"{-10:04}", "-010"
+    check &"{-10:<04}", "-010"
+    check &"{-10:>04}", "-010"
+    check &"0x{10:02X}", "0x0A"
+
+    check &"{10:#04X}", "0x0A"
+
+    check &"""{"test":#>5}""", "#test"
+    check &"""{"test":>5}""", " test"
+
+    check &"""{"test":#^7}""", "#test##"
+
+    check &"""{"test": <5}""", "test "
+    check &"""{"test":<5}""", "test "
+    check &"{1f:.3f}", "1.000"
+    check &"Hello, {s}!", "Hello, string!"
+
+    # Tests for identifiers without parenthesis
+    check &"{s} works{s}", "string worksstring"
+    check &"{s:>7}", " string"
+    doAssert(not compiles(&"{s_works}")) # parsed as identifier `s_works`
+
+    # Misc general tests
+    check &"{{}}", "{}"
+    check &"{0}%", "0%"
+    check &"{0}%asdf", "0%asdf"
+    check &("\n{\"\\n\"}\n"), "\n\n\n"
+    check &"""{"abc"}s""", "abcs"
+
+    # String tests
+    check &"""{"abc"}""", "abc"
+    check &"""{"abc":>4}""", " abc"
+    check &"""{"abc":<4}""", "abc "
+    check &"""{"":>4}""", "    "
+    check &"""{"":<4}""", "    "
+
+    # Int tests
+    check &"{12345}", "12345"
+    check &"{ - 12345}", "-12345"
+    check &"{12345:6}", " 12345"
+    check &"{12345:>6}", " 12345"
+    check &"{12345:4}", "12345"
+    check &"{12345:08}", "00012345"
+    check &"{-12345:08}", "-0012345"
+    check &"{0:0}", "0"
+    check &"{0:02}", "00"
+    check &"{-1:3}", " -1"
+    check &"{-1:03}", "-01"
+    check &"{10}", "10"
+    check &"{16:#X}", "0x10"
+    check &"{16:^#7X}", " 0x10  "
+    check &"{16:^+#7X}", " +0x10 "
+
+    # Hex tests
+    check &"{0:x}", "0"
+    check &"{-0:x}", "0"
+    check &"{255:x}", "ff"
+    check &"{255:X}", "FF"
+    check &"{-255:x}", "-ff"
+    check &"{-255:X}", "-FF"
+    check &"{255:x} uNaffeCteD CaSe", "ff uNaffeCteD CaSe"
+    check &"{255:X} uNaffeCteD CaSe", "FF uNaffeCteD CaSe"
+    check &"{255:4x}", "  ff"
+    check &"{255:04x}", "00ff"
+    check &"{-255:4x}", " -ff"
+    check &"{-255:04x}", "-0ff"
+
+    # Float tests
+    check &"{123.456}", "123.456"
+    check &"{-123.456}", "-123.456"
+    check &"{123.456:.3f}", "123.456"
+    check &"{123.456:+.3f}", "+123.456"
+    check &"{-123.456:+.3f}", "-123.456"
+    check &"{-123.456:.3f}", "-123.456"
+    check &"{123.456:1g}", "123.456"
+    check &"{123.456:.1f}", "123.5"
+    check &"{123.456:.0f}", "123."
+    check &"{123.456:>9.3f}", "  123.456"
+    check &"{123.456:9.3f}", "  123.456"
+    check &"{123.456:>9.4f}", " 123.4560"
+    check &"{123.456:>9.0f}", "     123."
+    check &"{123.456:<9.4f}", "123.4560 "
+
+    # Float (scientific) tests
+    check &"{123.456:e}", "1.234560e+02"
+    check &"{123.456:>13e}", " 1.234560e+02"
+    check &"{123.456:<13e}", "1.234560e+02 "
+    check &"{123.456:.1e}", "1.2e+02"
+    check &"{123.456:.2e}", "1.23e+02"
+    check &"{123.456:.3e}", "1.235e+02"
+
+    # Note: times.format adheres to the format protocol. Test that this
+    # works:
+    when nimvm:
+      discard
+    else:
+      var dt = dateTime(2000, mJan, 01, 00, 00, 00)
+      check &"{dt:yyyy-MM-dd}", "2000-01-01"
+
+      var tm = fromUnix(0)
+      discard &"{tm}"
+
+      var noww = now()
+      check &"{noww}", $noww
+
+    # Unicode string tests
+    check &"""{"αβγ"}""", "αβγ"
+    check &"""{"αβγ":>5}""", "  αβγ"
+    check &"""{"αβγ":<5}""", "αβγ  "
+    check &"""a{"a"}α{"α"}€{"€"}ðˆ{"ðˆ"}""", "aaαα€€ðˆðˆ"
+    check &"""a{"a":2}α{"α":2}€{"€":2}ðˆ{"ðˆ":2}""", "aa αα €€ ðˆðˆ "
+    # Invalid unicode sequences should be handled as plain strings.
+    # Invalid examples taken from: https://stackoverflow.com/a/3886015/1804173
+    let invalidUtf8 = [
+      "\xc3\x28", "\xa0\xa1",
+      "\xe2\x28\xa1", "\xe2\x82\x28",
+      "\xf0\x28\x8c\xbc", "\xf0\x90\x28\xbc", "\xf0\x28\x8c\x28"
+    ]
+    for s in invalidUtf8:
+      check &"{s:>5}", repeat(" ", 5-s.len) & s
+
+    # bug #11089
+    let flfoo: float = 1.0
+    check &"{flfoo}", "1.0"
+
+    # bug #11092
+    check &"{high(int64)}", "9223372036854775807"
+    check &"{low(int64)}", "-9223372036854775808"
+
+    doAssert fmt"{'a'} {'b'}" == "a b"
+
+  block: # test low(int64)
+    doAssert &"{low(int64):-}" == "-9223372036854775808"
+  block: #expressions plus formatting
+    doAssert fmt"{if true\: 123.456 else\: 0=:>9.3f}" == "if true: 123.456 else: 0=  123.456"
+    doAssert fmt"{(if true: 123.456 else: 0)=}" == "(if true: 123.456 else: 0)=123.456"
+    doAssert fmt"{if true\: 123.456 else\: 0=:9.3f}" == "if true: 123.456 else: 0=  123.456"
+    doAssert fmt"{(if true: 123.456 else: 0)=:9.4f}" == "(if true: 123.456 else: 0)= 123.4560"
+    doAssert fmt"{(if true: 123.456 else: 0)=:>9.0f}" == "(if true: 123.456 else: 0)=     123."
+    doAssert fmt"{if true\: 123.456 else\: 0=:<9.4f}" == "if true: 123.456 else: 0=123.4560 "
+
+    doAssert fmt"""{(case true
+      of false: 0.0
+      of true: 123.456)=:e}""" == """(case true
+      of false: 0.0
+      of true: 123.456)=1.234560e+02"""
+
+    doAssert fmt"""{block\:
+      var res = 0.000123456
+      for _ in 0..5\:
+        res *= 10
+      res=:>13e}""" == """block:
+      var res = 0.000123456
+      for _ in 0..5:
+        res *= 10
+      res= 1.234560e+02"""
+    #side effects
+    var x = 5
+    doAssert fmt"{(x=7;123.456)=:13e}" == "(x=7;123.456)= 1.234560e+02"
+    doAssert x==7
+  block: #curly bracket expressions and tuples
+    proc formatValue(result: var string; value:Table|bool|JsonNode; specifier:string) = result.add $value
+
+    doAssert fmt"""{\{"a"\:1,"b"\:2\}.toTable() = }""" == """{"a":1,"b":2}.toTable() = {"a": 1, "b": 2}"""
+    doAssert fmt"""{(\{3: (1,"hi",0.9),4: (4,"lo",1.1)\}).toTable()}""" == """{3: (1, "hi", 0.9), 4: (4, "lo", 1.1)}"""
+    doAssert fmt"""{ (%* \{"name": "Isaac", "books": ["Robot Dreams"]\}) }""" == """{"name":"Isaac","books":["Robot Dreams"]}"""
+    doAssert """%( \%\* {"name": "Isaac"})*""".fmt('%','*') == """{"name":"Isaac"}"""
+  block: #parens in quotes that fool my syntax highlighter
+    doAssert fmt"{(if true: ')' else: '(')}" == ")"
+    doAssert fmt"{(if true: ']' else: ')')}" == "]"
+    doAssert fmt"""{(if true: "\")\"" else: "\"(")}""" == """")""""
+    doAssert &"""{(if true: "\")" else: "")}""" == "\")"
+    doAssert &"{(if true: \"\\\")\" else: \"\")}" == "\")"
+    doAssert fmt"""{(if true: "')" else: "")}""" == "')"
+    doAssert fmt"""{(if true: "'" & "'" & ')' else: "")}""" == "'')"
+    doAssert &"""{(if true: "'" & "'" & ')' else: "")}""" == "'')"
+    doAssert &"{(if true: \"\'\" & \"'\" & ')' else: \"\")}" == "'')"
+    doAssert fmt"""{(if true: "'" & ')' else: "")}""" == "')"
+
+  block: # issue #20381
+    var ss: seq[string]
+    template myTemplate(s: string) =
+      ss.add s
+      ss.add s
+    proc foo() =
+      myTemplate fmt"hello"
+    foo()
+    doAssert ss == @["hello", "hello"]
+
+  block:
+    proc noraises() {.raises: [].} =
+      const
+        flt = 0.0
+        str = "str"
+
+      doAssert fmt"{flt} {str}" == "0.0 str"
+
+    noraises()
+
+  block:
+    doAssert not compiles(fmt"{formatting errors detected at compile time")
+
+static: main()
+main()
diff --git a/tests/stdlib/tstrformatlineinfo.nim b/tests/stdlib/tstrformatlineinfo.nim
new file mode 100644
index 000000000..3a7bf0d33
--- /dev/null
+++ b/tests/stdlib/tstrformatlineinfo.nim
@@ -0,0 +1,8 @@
+# issue #21759
+
+{.hint[ConvFromXToItselfNotNeeded]: on.}
+
+import std/strformat
+
+echo fmt"{string ""abc""}" #[tt.Hint
+        ^ conversion from string to itself is pointless]#
diff --git a/tests/stdlib/tstrimpl.nim b/tests/stdlib/tstrimpl.nim
new file mode 100644
index 000000000..a8933e53f
--- /dev/null
+++ b/tests/stdlib/tstrimpl.nim
@@ -0,0 +1,12 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/private/strimpl
+
+import std/assertions
+
+doAssert find(cstring"Hello Nim", cstring"Nim") == 6
+doAssert find(cstring"Hello Nim", cstring"N") == 6
+doAssert find(cstring"Hello Nim", cstring"I") == -1
+doAssert find(cstring"Hello Nim", cstring"O") == -1
diff --git a/tests/stdlib/tstring.nim b/tests/stdlib/tstring.nim
new file mode 100644
index 000000000..b9b3c78a3
--- /dev/null
+++ b/tests/stdlib/tstring.nim
@@ -0,0 +1,124 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+from std/sequtils import toSeq, map
+from std/sugar import `=>`
+import std/assertions
+
+proc tester[T](x: T) =
+  let test = toSeq(0..4).map(i => newSeq[int]())
+  doAssert $test == "@[@[], @[], @[], @[], @[]]"
+
+func reverse*(a: string): string =
+  result = a
+  for i in 0 ..< a.len div 2:
+    swap(result[i], result[^(i + 1)])
+
+proc main() =
+  block: # ..
+    const
+      characters = "abcdefghijklmnopqrstuvwxyz"
+      numbers = "1234567890"
+
+    # test "slice of length == len(characters)":
+    # replace characters completely by numbers
+    var s: string
+    s = characters
+    s[0..^1] = numbers
+    doAssert s == numbers
+
+    # test "slice of length > len(numbers)":
+    # replace characters by slice of same length
+    s = characters
+    s[1..16] = numbers
+    doAssert s == "a1234567890rstuvwxyz"
+
+    # test "slice of length == len(numbers)":
+    # replace characters by slice of same length
+    s = characters
+    s[1..10] = numbers
+    doAssert s == "a1234567890lmnopqrstuvwxyz"
+
+    # test "slice of length < len(numbers)":
+    # replace slice of length. and insert remaining chars
+    s = characters
+    s[1..4] = numbers
+    doAssert s == "a1234567890fghijklmnopqrstuvwxyz"
+
+    # test "slice of length == 1":
+    # replace first character. and insert remaining 9 chars
+    s = characters
+    s[1..1] = numbers
+    doAssert s == "a1234567890cdefghijklmnopqrstuvwxyz"
+
+    # test "slice of length == 0":
+    # insert chars at slice start index
+    s = characters
+    s[2..1] = numbers
+    doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
+
+    # test "slice of negative length":
+    # same as slice of zero length
+    s = characters
+    s[2..0] = numbers
+    doAssert s == "ab1234567890cdefghijklmnopqrstuvwxyz"
+
+    when nimvm:
+      discard
+    else:
+      # bug #6223
+      doAssertRaises(IndexDefect):
+        discard s[0..999]
+
+  block: # ==, cmp
+    let world = "hello\0world"
+    let earth = "hello\0earth"
+    let short = "hello\0"
+    let hello = "hello"
+    let goodbye = "goodbye"
+
+    doAssert world == world
+    doAssert world != earth
+    doAssert world != short
+    doAssert world != hello
+    doAssert world != goodbye
+
+    doAssert cmp(world, world) == 0
+    doAssert cmp(world, earth) > 0
+    doAssert cmp(world, short) > 0
+    doAssert cmp(world, hello) > 0
+    doAssert cmp(world, goodbye) > 0
+
+  block: # bug #7816
+    tester(1)
+
+  block: # bug #14497, reverse
+    doAssert reverse("hello") == "olleh"
+
+  block: # len, high
+    var a = "ab\0cd"
+    var b = a.cstring
+    doAssert a.len == 5
+    block: # bug #16405
+      when defined(js):
+        when nimvm: doAssert b.len == 2
+        else: doAssert b.len == 5
+      else: doAssert b.len == 2
+
+    doAssert a.high == a.len - 1
+    doAssert b.high == b.len - 1
+
+    doAssert "".len == 0
+    doAssert "".high == -1
+    doAssert "".cstring.len == 0
+    doAssert "".cstring.high == -1
+
+    block: # bug #16674
+      var c: cstring = nil
+      doAssert c.len == 0
+      doAssert c.high == -1
+
+static: main()
+main()
diff --git a/tests/stdlib/tstrmiscs.nim b/tests/stdlib/tstrmiscs.nim
new file mode 100644
index 000000000..b42f2e1fe
--- /dev/null
+++ b/tests/stdlib/tstrmiscs.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/strmisc
+import std/assertions
+
+
+doAssert expandTabs("\t", 4) == "    "
+doAssert expandTabs("\tfoo\t", 4) == "    foo "
+doAssert expandTabs("\tfoo\tbar", 4) == "    foo bar"
+doAssert expandTabs("\tfoo\tbar\t", 4) == "    foo bar "
+doAssert expandTabs("", 4) == ""
+doAssert expandTabs("", 0) == ""
+doAssert expandTabs("\t\t\t", 0) == ""
+
+doAssert partition("foo:bar", ":") == ("foo", ":", "bar")
+doAssert partition("foobarbar", "bar") == ("foo", "bar", "bar")
+doAssert partition("foobarbar", "bank") == ("foobarbar", "", "")
+doAssert partition("foobarbar", "foo") == ("", "foo", "barbar")
+doAssert partition("foofoobar", "bar") == ("foofoo", "bar", "")
+
+doAssert rpartition("foo:bar", ":") == ("foo", ":", "bar")
+doAssert rpartition("foobarbar", "bar") == ("foobar", "bar", "")
+doAssert rpartition("foobarbar", "bank") == ("", "", "foobarbar")
+doAssert rpartition("foobarbar", "foo") == ("", "foo", "barbar")
+doAssert rpartition("foofoobar", "bar") == ("foofoo", "bar", "")
diff --git a/tests/stdlib/tstrscans.nim b/tests/stdlib/tstrscans.nim
new file mode 100644
index 000000000..ae7fd98ca
--- /dev/null
+++ b/tests/stdlib/tstrscans.nim
@@ -0,0 +1,288 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[strscans, strutils, assertions]
+
+block ParsePasswd:
+  proc parsePasswd(content: string): seq[string] =
+    result = @[]
+    var idx = 0
+    while true:
+      var entry = ""
+      if scanp(content, idx, +(~{'\L', '\0'} -> entry.add($_)), '\L'):
+        result.add entry
+      else:
+        break
+
+  const etcPasswd = """root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+bin:x:2:2:bin:/bin:/bin/sh
+sys:x:3:3:sys:/dev:/bin/sh
+nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
+messagebus:x:103:107::/var/run/dbus:/bin/false
+"""
+
+  const parsedEtcPasswd = @[
+    "root:x:0:0:root:/root:/bin/bash",
+    "daemon:x:1:1:daemon:/usr/sbin:/bin/sh",
+    "bin:x:2:2:bin:/bin:/bin/sh",
+    "sys:x:3:3:sys:/dev:/bin/sh",
+    "nobody:x:65534:65534:nobody:/nonexistent:/bin/sh",
+    "messagebus:x:103:107::/var/run/dbus:/bin/false",
+    ]
+  doAssert etcPasswd.parsePasswd == parsedEtcPasswd
+
+block LastNot:
+  var idx : int
+
+  idx = 0
+  doAssert scanp("foo", idx,  'f', 'o', ~'a')
+
+  idx = 0
+  doAssert scanp("foo", idx,  'f', 'o', ~'o') == false
+
+  idx = 0
+  doAssert scanp("foox", idx,  'f', 'o', ~'o') == false
+
+  idx = 0
+  doAssert scanp("foox", idx,  'f', 'o', ~'a')
+
+block LastOptional:
+  var idx = 0
+  doAssert scanp("foo", idx, 'f', 'o', 'o', ?'o')
+
+block Tuple:
+  var idx = 0
+  doAssert scanp("foo", idx,  ('f', 'o', 'o'))
+
+block NotWithOptional:
+  var idx : int
+
+  idx = 0
+  doAssert scanp("bc", idx, ~(?'b', 'c')) == false
+
+  idx = 0
+  doAssert scanp("c", idx, ~(?'b', 'c')) == false
+
+  idx = 0
+  doAssert scanp("b", idx, ~(?'b', 'c'))
+
+block NotEmpty:
+  var idx = 0
+  doAssert scanp("", idx, ~()) == false
+
+block EmptyTuple:
+  var idx = 0
+  doAssert scanp("ab", idx, 'a', (), 'b')
+
+block Arrow:
+  let text = "foo;bar;baz;"
+  var idx = 0
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';')
+  doAssert scanp(text, idx, +(~{';','\0'} -> (discard $_)), ';') == false
+
+
+block issue15064:
+  var nick1, msg1: string
+  doAssert scanf("<abcd> a", "<$+> $+", nick1, msg1)
+  doAssert nick1 == "abcd"
+  doAssert msg1 == "a"
+
+  var nick2, msg2: string
+  doAssert(not scanf("<abcd> ", "<$+> $+", nick2, msg2))
+
+  var nick3, msg3: string
+  doAssert scanf("<abcd> ", "<$+> $*", nick3, msg3)
+  doAssert nick3 == "abcd"
+  doAssert msg3 == ""
+
+
+block:
+  proc twoDigits(input: string; x: var int; start: int): int =
+    if start+1 < input.len and input[start] == '0' and input[start+1] == '0':
+      result = 2
+      x = 13
+    else:
+      result = 0
+
+  proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int =
+    result = 0
+    while start+result < input.len and input[start+result] in seps: inc result
+
+  proc demangle(s: string; res: var string; start: int): int =
+    while result+start < s.len and s[result+start] in {'_', '@'}: inc result
+    res = ""
+    while result+start < s.len and s[result+start] > ' ' and s[result+start] != '_':
+      res.add s[result+start]
+      inc result
+    while result+start < s.len and s[result+start] > ' ':
+      inc result
+
+  proc parseGDB(resp: string): seq[string] =
+    const
+      digits = {'0'..'9'}
+      hexdigits = digits + {'a'..'f', 'A'..'F'}
+      whites = {' ', '\t', '\C', '\L'}
+    result = @[]
+    var idx = 0
+    while true:
+      var prc = ""
+      var info = ""
+      if scanp(resp, idx, *`whites`, '#', *`digits`, +`whites`, ?("0x", *`hexdigits`, " in "),
+               demangle($input, prc, $index), *`whites`, '(', * ~ ')', ')',
+                *`whites`, "at ", +(~{'\C', '\L'} -> info.add($_))):
+        result.add prc & " " & info
+      else:
+        break
+
+  var key, val: string
+  var intVal: int
+  var floatVal: float
+  doAssert scanf("abc:: xyz 89  33.25", "$w$s::$s$w$s$i  $f", key, val, intVal, floatVal)
+  doAssert key == "abc"
+  doAssert val == "xyz"
+  doAssert intVal == 89
+  doAssert floatVal == 33.25
+
+  var binVal: int
+  var octVal: int
+  var hexVal: int
+  doAssert scanf("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal)
+  doAssert binVal == 0b0101
+  doAssert octVal == 0o1234
+  doAssert hexVal == 0xabcd
+
+  let xx = scanf("$abc", "$$$i", intVal)
+  doAssert xx == false
+
+
+  let xx2 = scanf("$1234", "$$$i", intVal)
+  doAssert xx2
+
+  let yy = scanf(";.--Breakpoint00 [output]",
+      "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.",
+      intVal, key)
+  doAssert yy
+  doAssert key == "output"
+  doAssert intVal == 13
+
+  var ident = ""
+  var idx = 0
+  let zz = scanp("foobar x x  x   xWZ", idx, +{'a'..'z'} -> add(ident, $_), *(*{
+      ' ', '\t'}, "x"), ~'U', "Z")
+  doAssert zz
+  doAssert ident == "foobar"
+
+  const digits = {'0'..'9'}
+  var year = 0
+  var idx2 = 0
+  if scanp("201655-8-9", idx2, `digits`{4, 6} -> (year = year * 10 + ord($_) -
+      ord('0')), "-8", "-9"):
+    doAssert year == 201655
+
+  const gdbOut = """
+      #0  @foo_96013_1208911747@8 (x0=...)
+          at c:/users/anwender/projects/nim/temp.nim:11
+      #1  0x00417754 in tempInit000 () at c:/users/anwender/projects/nim/temp.nim:13
+      #2  0x0041768d in NimMainInner ()
+          at c:/users/anwender/projects/nim/lib/system.nim:2605
+      #3  0x004176b1 in NimMain ()
+          at c:/users/anwender/projects/nim/lib/system.nim:2613
+      #4  0x004176db in main (argc=1, args=0x712cc8, env=0x711ca8)
+          at c:/users/anwender/projects/nim/lib/system.nim:2620"""
+  const result = @["foo c:/users/anwender/projects/nim/temp.nim:11",
+          "tempInit000 c:/users/anwender/projects/nim/temp.nim:13",
+          "NimMainInner c:/users/anwender/projects/nim/lib/system.nim:2605",
+          "NimMain c:/users/anwender/projects/nim/lib/system.nim:2613",
+          "main c:/users/anwender/projects/nim/lib/system.nim:2620"]
+  doAssert parseGDB(gdbOut) == result
+
+  # bug #6487
+  var count = 0
+
+  proc test(): string =
+    inc count
+    result = ",123123"
+
+  var a: int
+  discard scanf(test(), ",$i", a)
+  doAssert count == 1
+
+
+block:
+  let input = """1-3 s: abc
+15-18 9: def
+15-18 A: ghi
+15-18 _: jkl
+"""
+  var
+    lo, hi: int
+    w: string
+    c: char
+    res: int
+  for line in input.splitLines:
+    if line.scanf("$i-$i $c: $w", lo, hi, c, w):
+      inc res
+  doAssert res == 4
+
+block:
+  #whenscanf testing
+  let input = """1-3 s: abc
+15-18 9: def
+15-18 A: ghi
+15-18 _: jkl
+"""
+  proc twoDigits(input: string; x: var int; start: int): int =
+    if start+1 < input.len and input[start] == '0' and input[start+1] == '0':
+      result = 2
+      x = 13
+    else:
+      result = 0
+
+  proc someSep(input: string; start: int; seps: set[char] = {';', ',', '-', '.'}): int =
+    result = 0
+    while start+result < input.len and input[start+result] in seps: inc result
+
+  type
+    ScanRetType = tuple
+      success: bool
+      lo: int
+      hi: int
+      ch: char
+      word: string
+
+  var res = 0
+  for line in input.splitLines:
+    let ret: ScanRetType = scanTuple(line, "$i-$i $c: $w")
+    if ret.success:
+      inc res
+  doAssert res == 4
+
+  let (_, key, val, intVal, floatVal) = scanTuple("abc:: xyz 89  33.25", "$w$s::$s$w$s$i  $f")
+  doAssert key == "abc"
+  doAssert val == "xyz"
+  doAssert intVal == 89
+  doAssert floatVal == 33.25
+
+
+  let (_, binVal, octVal, hexVal) = scanTuple("0b0101 0o1234 0xabcd", "$b$s$o$s$h", binVal, octVal, hexVal)
+  doAssert binVal == 0b0101
+  doAssert octVal == 0o1234
+  doAssert hexVal == 0xabcd
+
+  var (xx,_) = scanTuple("$abc", "$$$i")
+  doAssert xx == false
+
+
+  let (xx2, _) = block: scanTuple("$1234", "$$$i")
+  doAssert xx2
+
+  var (yy, intVal2, key2) = scanTuple(";.--Breakpoint00 [output]",
+      "$[someSep]Breakpoint${twoDigits}$[someSep({';','.','-'})] [$+]$.",
+      int)
+  doAssert yy
+  doAssert key2 == "output"
+  doAssert intVal2 == 13
diff --git a/tests/tstrset.nim b/tests/stdlib/tstrset.nim
index e19ccee4d..bbb6c2677 100755..100644
--- a/tests/tstrset.nim
+++ b/tests/stdlib/tstrset.nim
@@ -1,22 +1,26 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
 # test a simple yet highly efficient set of strings
 
 type
   TRadixNodeKind = enum rnLinear, rnFull, rnLeaf
   PRadixNode = ref TRadixNode
-  TRadixNode = object
+  TRadixNode {.inheritable.} = object
     kind: TRadixNodeKind
   TRadixNodeLinear = object of TRadixNode
-    len: byte
-    keys: array [0..31, char]
-    vals: array [0..31, PRadixNode]  
+    len: uint8
+    keys: array[0..31, char]
+    vals: array[0..31, PRadixNode]
   TRadixNodeFull = object of TRadixNode
-    b: array [char, PRadixNode]
+    b: array[char, PRadixNode]
   TRadixNodeLeaf = object of TRadixNode
     s: string
   PRadixNodeLinear = ref TRadixNodeLinear
   PRadixNodeFull = ref TRadixNodeFull
   PRadixNodeLeaf = ref TRadixNodeLeaf
-    
+
 proc search(r: PRadixNode, s: string): PRadixNode =
   var r = r
   var i = 0
@@ -24,7 +28,7 @@ proc search(r: PRadixNode, s: string): PRadixNode =
     case r.kind
     of rnLinear:
       var x = PRadixNodeLinear(r)
-      for j in 0..ze(x.len)-1:
+      for j in 0..int(x.len)-1:
         if x.keys[j] == s[i]:
           if s[i] == '\0': return r
           r = x.vals[j]
@@ -47,12 +51,12 @@ proc search(r: PRadixNode, s: string): PRadixNode =
         inc(j)
         inc(i)
 
-proc in_Operator*(r: PRadixNode, s: string): bool =
+proc contains*(r: PRadixNode, s: string): bool =
   return search(r, s) != nil
 
-proc testOrincl*(r: var PRadixNode, s: string): bool =
+proc testOrIncl*(r: var PRadixNode, s: string): bool =
   nil
-    
+
 proc incl*(r: var PRadixNode, s: string) = discard testOrIncl(r, s)
 
 proc excl*(r: var PRadixNode, s: string) =
@@ -63,9 +67,9 @@ proc excl*(r: var PRadixNode, s: string) =
   of rnFull: PRadixNodeFull(x).b['\0'] = nil
   of rnLinear:
     var x = PRadixNodeLinear(x)
-    for i in 0..ze(x.len)-1:
+    for i in 0..int(x.len)-1:
       if x.keys[i] == '\0':
-        swap(x.keys[i], x.keys[ze(x.len)-1])
+        swap(x.keys[i], x.keys[int(x.len)-1])
         dec(x.len)
         break
 
diff --git a/tests/stdlib/tstrtabs.nim b/tests/stdlib/tstrtabs.nim
new file mode 100644
index 000000000..d261abe76
--- /dev/null
+++ b/tests/stdlib/tstrtabs.nim
@@ -0,0 +1,117 @@
+discard """
+matrix: "--mm:refc; --mm:orc"
+sortoutput: true
+output: '''
+key1: value1
+key2: value2
+key_0: value0
+key_10: value10
+key_11: value11
+key_12: value12
+key_13: value13
+key_14: value14
+key_15: value15
+key_16: value16
+key_17: value17
+key_18: value18
+key_19: value19
+key_20: value20
+key_21: value21
+key_22: value22
+key_23: value23
+key_24: value24
+key_25: value25
+key_26: value26
+key_27: value27
+key_28: value28
+key_29: value29
+key_30: value30
+key_31: value31
+key_32: value32
+key_33: value33
+key_34: value34
+key_35: value35
+key_36: value36
+key_37: value37
+key_38: value38
+key_39: value39
+key_3: value3
+key_40: value40
+key_41: value41
+key_42: value42
+key_43: value43
+key_44: value44
+key_45: value45
+key_46: value46
+key_47: value47
+key_48: value48
+key_49: value49
+key_4: value4
+key_50: value50
+key_51: value51
+key_52: value52
+key_53: value53
+key_54: value54
+key_55: value55
+key_56: value56
+key_57: value57
+key_58: value58
+key_59: value59
+key_5: value5
+key_60: value60
+key_61: value61
+key_62: value62
+key_63: value63
+key_64: value64
+key_65: value65
+key_66: value66
+key_67: value67
+key_68: value68
+key_69: value69
+key_6: value6
+key_70: value70
+key_71: value71
+key_72: value72
+key_73: value73
+key_74: value74
+key_75: value75
+key_76: value76
+key_77: value77
+key_78: value78
+key_79: value79
+key_7: value7
+key_80: value80
+key_8: value8
+key_9: value9
+length of table 0
+length of table 81
+value1 = value2
+'''
+"""
+
+import std/[strtabs, assertions, syncio]
+
+var tab = newStringTable({"key1": "val1", "key2": "val2"},
+                         modeStyleInsensitive)
+for i in 0..80:
+  tab["key_" & $i] = "value" & $i
+
+for key, val in pairs(tab):
+  writeLine(stdout, key, ": ", val)
+writeLine(stdout, "length of table ", $tab.len)
+
+writeLine(stdout, `%`("$key1 = $key2", tab, {useEnvironment}))
+tab.clear
+writeLine(stdout, "length of table ", $tab.len)
+
+block:
+  var x = {"k": "v", "11": "22", "565": "67"}.newStringTable
+  doAssert x["k"] == "v"
+  doAssert x["11"] == "22"
+  doAssert x["565"] == "67"
+  x["11"] = "23"
+  doAssert x["11"] == "23"
+
+  x.clear(modeCaseInsensitive)
+  x["11"] = "22"
+  doAssert x["11"] == "22"
diff --git a/tests/stdlib/tstrtabs.nims b/tests/stdlib/tstrtabs.nims
new file mode 100644
index 000000000..3563ad0ad
--- /dev/null
+++ b/tests/stdlib/tstrtabs.nims
@@ -0,0 +1,5 @@
+import std/[strtabs, assertions]
+
+static:
+  let t = {"name": "John", "city": "Monaco"}.newStringTable
+  doAssert "${name} lives in ${city}" % t == "John lives in Monaco"
diff --git a/tests/stdlib/tstrtabs2.nim b/tests/stdlib/tstrtabs2.nim
new file mode 100644
index 000000000..a4030ec77
--- /dev/null
+++ b/tests/stdlib/tstrtabs2.nim
@@ -0,0 +1,32 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/strtabs
+import std/assertions
+
+macro m =
+  var t = {"name": "John"}.newStringTable
+  doAssert t["name"] == "John"
+
+block:
+  var t = {"name": "John"}.newStringTable
+  doAssert t["name"] == "John"
+
+m()
+
+proc fun()=
+  let ret = newStringTable(modeCaseSensitive)
+  ret["foo"] = "bar"
+
+  doAssert $ret == "{foo: bar}"
+
+  let b = ret["foo"]
+  doAssert b == "bar"
+
+proc main()=
+  static: fun()
+  fun()
+
+main()
diff --git a/tests/stdlib/tstrutils.nim b/tests/stdlib/tstrutils.nim
new file mode 100644
index 000000000..35f6bc669
--- /dev/null
+++ b/tests/stdlib/tstrutils.nim
@@ -0,0 +1,913 @@
+discard """
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+"""
+
+import std/strutils
+from stdtest/testutils import disableVm
+import std/assertions
+import std/private/jsutils
+# xxx each instance of `disableVm` and `when not defined js:` should eventually be fixed
+
+template rejectParse(e) =
+  try:
+    discard e
+    raise newException(AssertionDefect, "This was supposed to fail: $#!" % astToStr(e))
+  except ValueError: discard
+
+template main() =
+  block: # strip
+    doAssert strip("  ha  ") == "ha"
+    doAssert strip("  foofoofoo  ") == "foofoofoo"
+    doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
+    doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
+    doAssert strip("stripme but don't strip this stripme",
+                   chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) ==
+                   " but don't strip this "
+    doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
+    doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
+
+    block:
+      let a = "xxxxxx"
+      doAssert a.strip(chars={'x'}).len == 0
+
+    doAssert "".strip(chars={'x'}).len == 0
+    doAssert "         ".strip(chars={'x'}) == "         "
+    doAssert "xxx xxx".strip(chars={'x'}) == " "
+    doAssert "xxx  wind".strip(chars={'x'}) == "  wind"
+    doAssert "xxx  iii".strip(chars={'i'}) == "xxx  "
+    doAssert "x".strip(leading = false, chars={'x'}).len == 0
+    doAssert "x".strip(trailing = false, chars={'x'}).len == 0
+    doAssert "x".strip(leading = false, trailing = false, chars={'x'}) == "x"
+
+  block: # split
+    var ret: seq[string] # or use `toSeq` or `collect`
+    for p in split("/home/a1:xyz:/usr/bin", {':'}): ret.add p
+    doAssert ret == @["/home/a1", "xyz", "/usr/bin"]
+
+    let s = " this is an example  "
+    let s2 = ":this;is;an:example;;"
+
+    doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
+    doAssert s2.split(seps = {':', ';'}) == @["", "this", "is", "an", "example",
+        "", ""]
+    doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example  "]
+    doAssert s.split(' ', maxsplit = 1) == @["", "this is an example  "]
+    doAssert s.split(" ", maxsplit = 4) == @["", "this", "is", "an", "example  "]
+    # Empty string:
+    doAssert "".split() == @[""]
+    doAssert "".split(" ") == @[""]
+    doAssert "".split({' '}) == @[""]
+    # Empty separators:
+    doAssert "".split({}) == @[""]
+    doAssert "".split("") == @[""]
+    doAssert s.split({}) == @[s]
+    doAssert s.split("") == @[s]
+
+  block: # splitLines
+    let fixture = "a\nb\rc\r\nd"
+    doAssert len(fixture.splitLines) == 4
+    doAssert splitLines(fixture) == @["a", "b", "c", "d"]
+    doAssert splitLines(fixture, keepEol=true) == @["a\n", "b\r", "c\r\n", "d"]
+
+  block: # rsplit
+    doAssert rsplit("foo bar", seps = Whitespace) == @["foo", "bar"]
+    doAssert rsplit(" foo bar", seps = Whitespace, maxsplit = 1) == @[" foo", "bar"]
+    doAssert rsplit(" foo bar ", seps = Whitespace, maxsplit = 1) == @[" foo bar", ""]
+    doAssert rsplit(":foo:bar", sep = ':') == @["", "foo", "bar"]
+    doAssert rsplit(":foo:bar", sep = ':', maxsplit = 2) == @["", "foo", "bar"]
+    doAssert rsplit(":foo:bar", sep = ':', maxsplit = 3) == @["", "foo", "bar"]
+    doAssert rsplit("foothebar", sep = "the") == @["foo", "bar"]
+    # Empty string:
+    doAssert "".rsplit() == @[""]
+    doAssert "".rsplit(" ") == @[""]
+    doAssert "".rsplit({' '}) == @[""]
+    # Empty separators:
+    let s = " this is an example  "
+    doAssert "".rsplit({}) == @[""]
+    doAssert "".rsplit("") == @[""]
+    doAssert s.rsplit({}) == @[s]
+    doAssert s.rsplit("") == @[s]
+
+  block: # splitWhitespace
+    let s = " this is an example  "
+    doAssert s.splitWhitespace() == @["this", "is", "an", "example"]
+    doAssert s.splitWhitespace(maxsplit = 1) == @["this", "is an example  "]
+    doAssert s.splitWhitespace(maxsplit = 2) == @["this", "is", "an example  "]
+    doAssert s.splitWhitespace(maxsplit = 3) == @["this", "is", "an", "example  "]
+    doAssert s.splitWhitespace(maxsplit = 4) == @["this", "is", "an", "example"]
+
+  block: # removeSuffix
+    var s = "hello\n\r"
+    s.removeSuffix
+    doAssert s == "hello"
+    s.removeSuffix
+    doAssert s == "hello"
+
+    s = "hello\n\n"
+    s.removeSuffix
+    doAssert s == "hello"
+
+    s = "hello\r"
+    s.removeSuffix
+    doAssert s == "hello"
+
+    s = "hello \n there"
+    s.removeSuffix
+    doAssert s == "hello \n there"
+
+    s = "hello"
+    s.removeSuffix("llo")
+    doAssert s == "he"
+    s.removeSuffix('e')
+    doAssert s == "h"
+
+    s = "hellos"
+    s.removeSuffix({'s','z'})
+    doAssert s == "hello"
+    s.removeSuffix({'l','o'})
+    doAssert s == "he"
+
+    s = "aeiou"
+    s.removeSuffix("")
+    doAssert s == "aeiou"
+
+    s = ""
+    s.removeSuffix("")
+    doAssert s == ""
+
+    s = "  "
+    s.removeSuffix
+    doAssert s == "  "
+
+    s = "  "
+    s.removeSuffix("")
+    doAssert s == "  "
+
+    s = "    "
+    s.removeSuffix(" ")
+    doAssert s == "   "
+
+    s = "    "
+    s.removeSuffix(' ')
+    doAssert s == ""
+
+    # Contrary to Chomp in other languages
+    # empty string does not change behaviour
+    s = "hello\r\n\r\n"
+    s.removeSuffix("")
+    doAssert s == "hello\r\n\r\n"
+
+  block: # removePrefix
+    var s = "\n\rhello"
+    s.removePrefix
+    doAssert s == "hello"
+    s.removePrefix
+    doAssert s == "hello"
+
+    s = "\n\nhello"
+    s.removePrefix
+    doAssert s == "hello"
+
+    s = "\rhello"
+    s.removePrefix
+    doAssert s == "hello"
+
+    s = "hello \n there"
+    s.removePrefix
+    doAssert s == "hello \n there"
+
+    s = "hello"
+    s.removePrefix("hel")
+    doAssert s == "lo"
+    s.removePrefix('l')
+    doAssert s == "o"
+
+    s = "hellos"
+    s.removePrefix({'h','e'})
+    doAssert s == "llos"
+    s.removePrefix({'l','o'})
+    doAssert s == "s"
+
+    s = "aeiou"
+    s.removePrefix("")
+    doAssert s == "aeiou"
+
+    s = ""
+    s.removePrefix("")
+    doAssert s == ""
+
+    s = "  "
+    s.removePrefix
+    doAssert s == "  "
+
+    s = "  "
+    s.removePrefix("")
+    doAssert s == "  "
+
+    s = "    "
+    s.removePrefix(" ")
+    doAssert s == "   "
+
+    s = "    "
+    s.removePrefix(' ')
+    doAssert s == ""
+
+    # Contrary to Chomp in other languages
+    # empty string does not change behaviour
+    s = "\r\n\r\nhello"
+    s.removePrefix("")
+    doAssert s == "\r\n\r\nhello"
+
+  block: # delete(slice)
+    var s = "0123456789ABCDEFGH"
+    delete(s, 4 .. 5)
+    doAssert s == "01236789ABCDEFGH"
+    delete(s, s.len-1 .. s.len-1)
+    doAssert s == "01236789ABCDEFG"
+    delete(s, 0..0)
+    doAssert s == "1236789ABCDEFG"
+    s = ""
+    doAssertRaises(IndexDefect): delete(s, 0..0)
+    doAssert s == ""
+    s = "abc"
+    doAssertRaises(IndexDefect): delete(s, -1 .. -2)
+    doAssertRaises(IndexDefect): delete(s, 2..3)
+    doAssertRaises(IndexDefect): delete(s, 3..2)
+    delete(s, 2..2)
+    doAssert s == "ab"
+    delete(s, 1..0)
+    doAssert s == "ab"
+    delete(s, 0..0)
+    doAssert s == "b"
+
+  block: # delete(first, last)
+    {.push warning[deprecated]:off.}
+    var s = "0123456789ABCDEFGH"
+    delete(s, 4, 5)
+    doAssert s == "01236789ABCDEFGH"
+    delete(s, s.len-1, s.len-1)
+    doAssert s == "01236789ABCDEFG"
+    delete(s, 0, 0)
+    doAssert s == "1236789ABCDEFG"
+    {.pop.}
+
+  block: # find
+    const haystack: string = "0123456789ABCDEFGH"
+    doAssert haystack.find('A') == 10
+    doAssert haystack.find('A', 5) == 10
+    doAssert haystack.find('A', 5, 10) == 10
+    doAssert haystack.find('A', 5, 9) == -1
+    doAssert haystack.find("A") == 10
+    doAssert haystack.find("A", 5) == 10
+    doAssert haystack.find("A", 5, 10) == 10
+    doAssert haystack.find("A", 5, 9) == -1
+    doAssert haystack.find({'A'..'C'}) == 10
+    doAssert haystack.find({'A'..'C'}, 5) == 10
+    doAssert haystack.find({'A'..'C'}, 5, 10) == 10
+    doAssert haystack.find({'A'..'C'}, 5, 9) == -1
+    doAssert haystack.find('A', 0, 0) == -1 # search limited to the first char
+    doAssert haystack.find('A', 5, 0) == -1 # last < start
+    doAssert haystack.find('A', 5, 4) == -1 # last < start
+
+    block:
+      const haystack: string = "ABCABABABABCAB"
+      doAssert haystack.len == 14
+
+      # only last argument
+      doAssert haystack.find("ABC") == 0
+      doAssert haystack.find("ABC", last=13) == 0 # after the second ABC
+      doAssert haystack.find("ABC", last=5) == 0 # before the second ABC
+
+      # only start argument
+      doAssert haystack.find("ABC", start=0) == 0
+      doAssert haystack.find("ABC", start=1) == 9
+      doAssert haystack.find("ABC", start=9) == 9
+      doAssert haystack.find("ABC", start=10) == -1
+
+      # both start and last arguments
+      doAssert haystack.find("ABC", start=0, last=14) == 0
+      doAssert haystack.find("ABC", start=0, last=13) == 0
+      doAssert haystack.find("ABC", start=0, last=12) == 0
+      doAssert haystack.find("ABC", start=1, last=13) == 9
+      doAssert haystack.find("ABC", start=1, last=12) == 9
+      doAssert haystack.find("ABC", start=1, last=11) == 9
+      doAssert haystack.find("ABC", start=1, last=10) == -1
+
+    doAssert "".find("/") == -1
+    doAssert "/".find("/") == 0
+    doAssert "/".find("//") == -1
+    doAssert "///".find("//", start=3) == -1
+
+    # searching for empty string
+    doAssert "".find("") == 0
+    doAssert "abc".find("") == 0
+    doAssert "abc".find("", start=1) == 1
+    doAssert "abc".find("", start=2) == 2
+    doAssert "abc".find("", start=3) == 3
+    doAssert "abc".find("", start=4) == -1
+    doAssert "abc".find("", start=400) == -1
+    doAssert "abc".find("", start=1, last=3) == 1
+    doAssert "abc".find("", start=1, last=2) == 1
+    doAssert "abc".find("", start=1, last=1) == 1
+    doAssert "abc".find("", start=1, last=0) == 1
+    doAssert "abc".find("", start=1, last = -1) == 1
+
+    # when last <= start, searching for non-empty string
+    block:
+      let last: int = -1 # searching through whole line
+      doAssert "abcd".find("ab", start=0, last=last) == 0
+      doAssert "abcd".find("ab", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=1, last=last) == 1
+      doAssert "abcd".find("bc", start=2, last=last) == -1
+    block:
+      let last: int = 0
+      doAssert "abcd".find("ab", start=0, last=last) == -1
+      doAssert "abcd".find("ab", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=2, last=last) == -1
+    block:
+      let last: int = 1
+      doAssert "abcd".find("ab", start=0, last=last) == 0
+      doAssert "abcd".find("ab", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=1, last=last) == -1
+      doAssert "abcd".find("bc", start=2, last=last) == -1
+
+  block: # rfind
+    doAssert "0123456789ABCDEFGAH".rfind('A') == 17
+    doAssert "0123456789ABCDEFGAH".rfind('A', last=13) == 10
+    doAssert "0123456789ABCDEFGAH".rfind('H', last=13) == -1
+    doAssert "0123456789ABCDEFGAH".rfind("A") == 17
+    doAssert "0123456789ABCDEFGAH".rfind("A", last=13) == 10
+    doAssert "0123456789ABCDEFGAH".rfind("H", last=13) == -1
+    doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}) == 17
+    doAssert "0123456789ABCDEFGAH".rfind({'A'..'C'}, last=13) == 12
+    doAssert "0123456789ABCDEFGAH".rfind({'G'..'H'}, last=13) == -1
+    doAssert "0123456789ABCDEFGAH".rfind('A', start=18) == -1
+    doAssert "0123456789ABCDEFGAH".rfind('A', start=11, last=17) == 17
+    doAssert "0123456789ABCDEFGAH".rfind("0", start=0) == 0
+    doAssert "0123456789ABCDEFGAH".rfind("0", start=1) == -1
+    doAssert "0123456789ABCDEFGAH".rfind("H", start=11) == 18
+    doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=5) == 9
+    doAssert "0123456789ABCDEFGAH".rfind({'0'..'9'}, start=10) == -1
+
+    doAssert "/1/2/3".rfind('/') == 4
+    doAssert "/1/2/3".rfind('/', last=1) == 0
+    doAssert "/1/2/3".rfind('0') == -1
+
+    block:
+      const haystack: string = "ABCABABABABCAB"
+      doAssert haystack.len == 14
+      doAssert haystack.rfind("ABC") == 9
+      doAssert haystack.rfind("ABC", last=13) == 9
+      doAssert haystack.rfind("ABC", last=12) == 9
+      doAssert haystack.rfind("ABC", last=11) == 9
+      doAssert haystack.rfind("ABC", last=10) == 0
+
+      doAssert haystack.rfind("ABC", start=0) == 9
+      doAssert haystack.rfind("ABC", start=1) == 9
+      doAssert haystack.rfind("ABC", start=9) == 9
+      doAssert haystack.rfind("ABC", start=10) == -1
+
+      doAssert haystack.rfind("ABC", start=0, last=13) == 9
+      doAssert haystack.rfind("ABC", start=0, last=12) == 9
+      doAssert haystack.rfind("ABC", start=0, last=11) == 9
+      doAssert haystack.rfind("ABC", start=0, last=10) == 0
+      doAssert haystack.rfind("ABC", start=1, last=10) == -1
+
+    doAssert "".rfind("/") == -1
+    doAssert "/".rfind("/") == 0
+    doAssert "/".rfind("//") == -1
+    doAssert "///".rfind("//", start=3) == -1
+
+    # searching for empty string
+    doAssert "".rfind("") == 0
+    doAssert "abc".rfind("") == 3
+    doAssert "abc".rfind("", start=1) == 3
+    doAssert "abc".rfind("", start=2) == 3
+    doAssert "abc".rfind("", start=3) == 3
+    doAssert "abc".rfind("", start=4) == 4
+    doAssert "abc".rfind("", start=400) == 400
+
+    doAssert "abc".rfind("", start=1, last=3) == 3
+    doAssert "abc".rfind("", start=1, last=2) == 2
+    doAssert "abc".rfind("", start=1, last=1) == 1
+    # This returns the start index instead of the last index
+    # because start > last
+    doAssert "abc".rfind("", start=1, last=0) == 1
+    doAssert "abc".rfind("", start=1, last = -1) == 3
+    
+    doAssert "abc".rfind("", start=0, last=0) == 0
+
+    # when last <= start, searching for non-empty string
+    block:
+      let last: int = -1
+      doAssert "abcd".rfind("ab", start=0, last=last) == 0
+      doAssert "abcd".rfind("ab", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=1, last=last) == 1
+      doAssert "abcd".rfind("bc", start=2, last=last) == -1
+    block:
+      let last: int = 0
+      doAssert "abcd".rfind("ab", start=0, last=last) == -1
+      doAssert "abcd".rfind("ab", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=2, last=last) == -1
+    block:
+      let last: int = 1
+      doAssert "abcd".rfind("ab", start=0, last=last) == 0
+      doAssert "abcd".rfind("ab", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=1, last=last) == -1
+      doAssert "abcd".rfind("bc", start=2, last=last) == -1
+
+  block: # trimZeros
+    var x = "1200"
+    x.trimZeros()
+    doAssert x == "1200"
+    x = "120.0"
+    x.trimZeros()
+    doAssert x == "120"
+    x = "0."
+    x.trimZeros()
+    doAssert x == "0"
+    x = "1.0e2"
+    x.trimZeros()
+    doAssert x == "1e2"
+    x = "78.90"
+    x.trimZeros()
+    doAssert x == "78.9"
+    x = "1.23e4"
+    x.trimZeros()
+    doAssert x == "1.23e4"
+    x = "1.01"
+    x.trimZeros()
+    doAssert x == "1.01"
+    x = "1.1001"
+    x.trimZeros()
+    doAssert x == "1.1001"
+    x = "0.0"
+    x.trimZeros()
+    doAssert x == "0"
+    x = "0.01"
+    x.trimZeros()
+    doAssert x == "0.01"
+    x = "1e0"
+    x.trimZeros()
+    doAssert x == "1e0"
+    x = "1.23"
+    x.trimZeros()
+    doAssert x == "1.23"
+
+  block: # countLines
+    proc assertCountLines(s: string) = doAssert s.countLines == s.splitLines.len
+    assertCountLines("")
+    assertCountLines("\n")
+    assertCountLines("\n\n")
+    assertCountLines("abc")
+    assertCountLines("abc\n123")
+    assertCountLines("abc\n123\n")
+    assertCountLines("\nabc\n123")
+    assertCountLines("\nabc\n123\n")
+
+  block: # parseBinInt, parseHexInt, parseOctInt
+    # binary
+    doAssert "0b1111".parseBinInt == 15
+    doAssert "0B1111".parseBinInt == 15
+    doAssert "1111".parseBinInt == 15
+    doAssert "1110".parseBinInt == 14
+    doAssert "1_1_1_1".parseBinInt == 15
+    doAssert "0b1_1_1_1".parseBinInt == 15
+    rejectParse "".parseBinInt
+    rejectParse "_".parseBinInt
+    rejectParse "0b".parseBinInt
+    rejectParse "0b1234".parseBinInt
+    # hex
+    doAssert "0x72".parseHexInt == 114
+    doAssert "0X72".parseHexInt == 114
+    doAssert "#72".parseHexInt == 114
+    doAssert "72".parseHexInt == 114
+    doAssert "FF".parseHexInt == 255
+    doAssert "ff".parseHexInt == 255
+    doAssert "fF".parseHexInt == 255
+    doAssert "0x7_2".parseHexInt == 114
+    rejectParse "".parseHexInt
+    rejectParse "_".parseHexInt
+    rejectParse "0x".parseHexInt
+    rejectParse "0xFFG".parseHexInt
+    rejectParse "reject".parseHexInt
+    # octal
+    doAssert "0o17".parseOctInt == 15
+    doAssert "0O17".parseOctInt == 15
+    doAssert "17".parseOctInt == 15
+    doAssert "10".parseOctInt == 8
+    doAssert "0o1_0_0".parseOctInt == 64
+    rejectParse "".parseOctInt
+    rejectParse "_".parseOctInt
+    rejectParse "0o".parseOctInt
+    rejectParse "9".parseOctInt
+    rejectParse "0o9".parseOctInt
+    rejectParse "reject".parseOctInt
+
+  block: # parseHexStr
+    doAssert "".parseHexStr == ""
+    doAssert "00Ff80".parseHexStr == "\0\xFF\x80"
+    try:
+      discard "00Ff8".parseHexStr
+      doAssert false, "Should raise ValueError"
+    except ValueError:
+      discard
+
+    try:
+      discard "0k".parseHexStr
+      doAssert false, "Should raise ValueError"
+    except ValueError:
+      discard
+
+    doAssert "".toHex == ""
+    doAssert "\x00\xFF\x80".toHex == "00FF80"
+    doAssert "0123456789abcdef".parseHexStr.toHex == "0123456789ABCDEF"
+
+  block: # toHex
+    doAssert(toHex(100i16, 32) == "00000000000000000000000000000064")
+    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")
+
+  block: # insertSep
+    doAssert(insertSep($1000_000) == "1_000_000")
+    doAssert(insertSep($232) == "232")
+    doAssert(insertSep($12345, ',') == "12,345")
+    doAssert(insertSep($0) == "0")
+
+  block: # repeat, spaces
+    doAssert(' '.repeat(8) == "        ")
+    doAssert(" ".repeat(8) == "        ")
+    doAssert(spaces(8) == "        ")
+
+    doAssert(' '.repeat(0) == "")
+    doAssert(" ".repeat(0) == "")
+    doAssert(spaces(0) == "")
+
+  block: # toBin, toOct
+    whenJsNoBigInt64: # bug #11369
+      discard
+    do:
+      var num: int64 = -1
+      doAssert num.toBin(64) == "1111111111111111111111111111111111111111111111111111111111111111"
+      doAssert num.toOct(24) == "001777777777777777777777"
+
+  block: # replace
+    doAssert "oo".replace("", "abc") == "oo"
+    # bug #8911
+    static:
+      let a = ""
+      let a2 = a.replace("\n", "\\n")
+
+    static:
+      let b = "b"
+      let b2 = b.replace("\n", "\\n")
+
+    block:
+      let c = ""
+      let c2 = c.replace("\n", "\\n")
+
+  block: # replaceWord
+    doAssert "-ld a-ldz -ld".replaceWord("-ld") == " a-ldz "
+    doAssert "-lda-ldz -ld abc".replaceWord("-ld") == "-lda-ldz  abc"
+    doAssert "-lda-ldz -ld abc".replaceWord("") == "-lda-ldz -ld abc"
+
+  block: # multiReplace
+    doAssert "abba".multiReplace(("a", "b"), ("b", "a")) == "baab"
+    doAssert "Hello World.".multiReplace(("ello", "ELLO"), ("World.",
+        "PEOPLE!")) == "HELLO PEOPLE!"
+    doAssert "aaaa".multiReplace(("a", "aa"), ("aa", "bb")) == "aaaaaaaa"
+
+  # `parseEnum`, ref issue #14030
+  # check enum defined at top level # xxx this is probably irrelevant, and pollutes scope
+  # for remaining tests
+  type
+    Foo = enum
+      A = -10
+      B = "bb"
+      C = (-5, "ccc")
+      D = 15
+      E = "ee" # check that we count enum fields correctly
+
+  block: # parseEnum
+    block:
+      let a = parseEnum[Foo]("A")
+      let b = parseEnum[Foo]("bb")
+      let c = parseEnum[Foo]("ccc")
+      let d = parseEnum[Foo]("D")
+      let e = parseEnum[Foo]("ee")
+      doAssert a == A
+      doAssert b == B
+      doAssert c == C
+      doAssert d == D
+      doAssert e == E
+      try:
+        let f = parseEnum[Foo]("Bar")
+        doAssert false
+      except ValueError:
+        discard
+
+      # finally using default
+      let g = parseEnum[Foo]("Bar", A)
+      doAssert g == A
+
+    block: # bug #19463
+      const CAMPAIGN_TABLE = "wikientries_campaign"
+      const CHARACTER_TABLE = "wikientries_character"
+
+      type Tables = enum
+        a = CAMPAIGN_TABLE,
+        b = CHARACTER_TABLE,
+
+      let myA = CAMPAIGN_TABLE
+      doAssert $parseEnum[Tables](myA) == "wikientries_campaign"
+
+    block: # check enum defined in block
+      type
+        Bar = enum
+          V
+          W = "ww"
+          X = (3, "xx")
+          Y = 10
+          Z = "zz" # check that we count enum fields correctly
+
+      let a = parseEnum[Bar]("V")
+      let b = parseEnum[Bar]("ww")
+      let c = parseEnum[Bar]("xx")
+      let d = parseEnum[Bar]("Y")
+      let e = parseEnum[Bar]("zz")
+      doAssert a == V
+      doAssert b == W
+      doAssert c == X
+      doAssert d == Y
+      doAssert e == Z
+      try:
+        let f = parseEnum[Bar]("Baz")
+        doAssert false
+      except ValueError:
+        discard
+
+      # finally using default
+      let g = parseEnum[Bar]("Baz", V)
+      doAssert g == V
+
+    block: # check ambiguous enum fails to parse
+      type
+        Ambig = enum
+          f1 = "A"
+          f2 = "B"
+          f3 = "A"
+
+      doAssert not compiles((let a = parseEnum[Ambig]("A")))
+
+    block: # check almost ambiguous enum
+      type
+        AlmostAmbig = enum
+          f1 = "someA"
+          f2 = "someB"
+          f3 = "SomeA"
+
+      let a = parseEnum[AlmostAmbig]("someA")
+      let b = parseEnum[AlmostAmbig]("someB")
+      let c = parseEnum[AlmostAmbig]("SomeA")
+      doAssert a == f1
+      doAssert b == f2
+      doAssert c == f3
+
+    block:
+      type MyEnum = enum enA, enB, enC, enuD, enE
+      doAssert parseEnum[MyEnum]("enu_D") == enuD
+
+      doAssert parseEnum("invalid enum value", enC) == enC
+    
+    block: # issue #22726
+      type SomeEnum = enum A, B, C
+
+      proc assignEnum(dest: var enum, s: string) =
+        type ty = typeof(dest)
+        dest = parseEnum[ty](s)
+      
+      var v: SomeEnum
+      v.assignEnum("A")
+      doAssert v == A
+
+  block: # indentation
+    doAssert 0 == indentation """
+hey
+  low
+    there
+"""
+    doAssert 2 == indentation """
+  hey
+    low
+      there
+"""
+    doAssert 2 == indentation """  hey
+    low
+      there
+"""
+    doAssert 2 == indentation """  hey
+    low
+      there"""
+    doAssert 0 == indentation ""
+    doAssert 0 == indentation "  \n  \n"
+    doAssert 0 == indentation "    "
+
+  block: # indent
+    doAssert "  foo\n  bar".indent(4, "Q") == "QQQQ  foo\nQQQQ  bar"
+
+  block: # unindent
+    doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!") == "foo\nbar\nbaz"
+
+    doAssert """~~!!foo
+~~!!bar
+~~!!baz""".unindent(2, "~~!!aa") == "~~!!foo\n~~!!bar\n~~!!baz"
+    doAssert """~~foo
+~~  bar
+~~  baz""".unindent(4, "~") == "foo\n  bar\n  baz"
+    doAssert """foo
+bar
+    baz
+  """.unindent(4) == "foo\nbar\nbaz\n"
+    doAssert """foo
+    bar
+    baz
+  """.unindent(2) == "foo\n  bar\n  baz\n"
+    doAssert """foo
+    bar
+    baz
+  """.unindent(100) == "foo\nbar\nbaz\n"
+
+    doAssert """foo
+    foo
+    bar
+  """.unindent() == "foo\nfoo\nbar\n"
+
+  block: # formatBiggestFloat
+    disableVm:
+      doAssert formatBiggestFloat(1234.567, ffDecimal, -1) == "1234.567000"
+      when not defined(js):
+        doAssert formatBiggestFloat(1234.567, ffDecimal, 0) == "1235." # bugs 8242, 12586
+      doAssert formatBiggestFloat(1234.567, ffDecimal, 1) == "1234.6"
+      doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
+      doAssert formatBiggestFloat(0.00000000001, ffScientific, 1, ',') in
+                                                      ["1,0e-11", "1,0e-011"]
+  block: # formatFloat
+    disableVm:
+      # bug #6589
+      when not defined(js):
+        doAssert formatFloat(123.456, ffScientific, precision = -1) == "1.234560e+02"
+
+  block: # `%`
+    doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
+    doAssert "${1}12 ${-1}$2" % ["a", "b"] == "a12 bb"
+    doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
+             "The cat eats fish."
+
+  block: # formatSize
+    disableVm:
+      whenJsNoBigInt64: discard
+      do:
+        doAssert formatSize((1'i64 shl 31) + (300'i64 shl 20)) == "2.293GiB" # <=== bug #8231
+      doAssert formatSize((2.234*1024*1024).int) == "2.234MiB"
+      doAssert formatSize(4096) == "4KiB"
+      doAssert formatSize(4096, prefix = bpColloquial, includeSpace = true) == "4 kB"
+      doAssert formatSize(4096, includeSpace = true) == "4 KiB"
+      doAssert formatSize(5_378_934, prefix = bpColloquial, decimalSep = ',') == "5,13MB"
+
+  block: # formatEng
+    disableVm:
+      doAssert formatEng(0, 2, trim = false) == "0.00"
+      doAssert formatEng(0, 2) == "0"
+      doAssert formatEng(53, 2, trim = false) == "53.00"
+      doAssert formatEng(0.053, 2, trim = false) == "53.00e-3"
+      doAssert formatEng(0.053, 4, trim = false) == "53.0000e-3"
+      doAssert formatEng(0.053, 4, trim = true) == "53e-3"
+      doAssert formatEng(0.053, 0) == "53e-3"
+      doAssert formatEng(52731234) == "52.731234e6"
+      doAssert formatEng(-52731234) == "-52.731234e6"
+      doAssert formatEng(52731234, 1) == "52.7e6"
+      doAssert formatEng(-52731234, 1) == "-52.7e6"
+      doAssert formatEng(52731234, 1, decimalSep = ',') == "52,7e6"
+      doAssert formatEng(-52731234, 1, decimalSep = ',') == "-52,7e6"
+
+      doAssert formatEng(4100, siPrefix = true, unit = "V") == "4.1 kV"
+      doAssert formatEng(4.1, siPrefix = true, unit = "V",
+          useUnitSpace = true) == "4.1 V"
+      doAssert formatEng(4.1, siPrefix = true) == "4.1" # Note lack of space
+      doAssert formatEng(4100, siPrefix = true) == "4.1 k"
+      doAssert formatEng(4.1, siPrefix = true, unit = "",
+          useUnitSpace = true) == "4.1 " # Includes space
+      doAssert formatEng(4100, siPrefix = true, unit = "") == "4.1 k"
+      doAssert formatEng(4100) == "4.1e3"
+      doAssert formatEng(4100, unit = "V", useUnitSpace = true) == "4.1e3 V"
+      doAssert formatEng(4100, unit = "", useUnitSpace = true) == "4.1e3 "
+      # Don't use SI prefix as number is too big
+      doAssert formatEng(3.1e22, siPrefix = true, unit = "a",
+          useUnitSpace = true) == "31e21 a"
+      # Don't use SI prefix as number is too small
+      doAssert formatEng(3.1e-25, siPrefix = true, unit = "A",
+          useUnitSpace = true) == "310e-27 A"
+
+  block: # align
+    doAssert align("abc", 4) == " abc"
+    doAssert align("a", 0) == "a"
+    doAssert align("1232", 6) == "  1232"
+    doAssert align("1232", 6, '#') == "##1232"
+
+  block: # alignLeft
+    doAssert alignLeft("abc", 4) == "abc "
+    doAssert alignLeft("a", 0) == "a"
+    doAssert alignLeft("1232", 6) == "1232  "
+    doAssert alignLeft("1232", 6, '#') == "1232##"
+
+  block: # center
+    doAssert center("foo", 13) == "     foo     "
+    doAssert center("foo", 0) == "foo"
+    doAssert center("foo", 3, fillChar = 'a') == "foo"
+    doAssert center("foo", 10, fillChar = '\t') == "\t\t\tfoo\t\t\t\t"
+
+  block: # count
+    doAssert count("foofoofoo", "foofoo") == 1
+    doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
+    doAssert count("foofoofoo", 'f') == 3
+    doAssert count("foofoofoobar", {'f', 'b'}) == 4
+
+  block: # isAlphaAscii
+    doAssert isAlphaAscii('r')
+    doAssert isAlphaAscii('A')
+    doAssert(not isAlphaAscii('$'))
+
+  block: # isAlphaNumeric
+    doAssert isAlphaNumeric('3')
+    doAssert isAlphaNumeric('R')
+    doAssert(not isAlphaNumeric('!'))
+
+  block: # isDigit
+    doAssert isDigit('3')
+    doAssert(not isDigit('a'))
+    doAssert(not isDigit('%'))
+
+  block: # isSpaceAscii
+    doAssert isSpaceAscii('\t')
+    doAssert isSpaceAscii('\l')
+    doAssert(not isSpaceAscii('A'))
+
+  block: # isEmptyOrWhitespace
+    doAssert(isEmptyOrWhitespace(""))
+    doAssert(isEmptyOrWhitespace("       "))
+    doAssert(isEmptyOrWhitespace("\t\l \v\r\f"))
+    doAssert(not isEmptyOrWhitespace("ABc   \td"))
+
+  block: # isLowerAscii
+    doAssert isLowerAscii('a')
+    doAssert isLowerAscii('z')
+    doAssert(not isLowerAscii('A'))
+    doAssert(not isLowerAscii('5'))
+    doAssert(not isLowerAscii('&'))
+    doAssert(not isLowerAscii(' '))
+
+  block: # isUpperAscii
+    doAssert isUpperAscii('A')
+    doAssert(not isUpperAscii('b'))
+    doAssert(not isUpperAscii('5'))
+    doAssert(not isUpperAscii('%'))
+
+  block: # unescape
+    doAssert(unescape(r"\x013", "", "") == "\x013")
+
+  block: # join
+    doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
+    doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
+    doAssert join([1, 2, 3]) == "123"
+    doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
+
+  block: # startsWith / endsWith
+    var s = "abcdef"
+    doAssert s.startsWith('a')
+    doAssert s.startsWith('b') == false
+    doAssert s.endsWith('f')
+    doAssert s.endsWith('a') == false
+    doAssert s.endsWith('\0') == false
+
+  block: # nimIdentNormalize
+    doAssert nimIdentNormalize("") == ""
+    doAssert nimIdentNormalize("foo") == "foo"
+    doAssert nimIdentNormalize("foo_bar") == "foobar"
+    doAssert nimIdentNormalize("Foo_bar") == "Foobar"
+    doAssert nimIdentNormalize("_Foo_bar") == "_foobar"
+
+  block: # bug #19500
+    doAssert "abc \0 def".find("def") == 6
+    doAssert "abc \0 def".find('d') == 6
+
+
+static: main()
+main()
diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim
new file mode 100644
index 000000000..2ea96cfbb
--- /dev/null
+++ b/tests/stdlib/tsugar.nim
@@ -0,0 +1,310 @@
+discard """
+  targets: "c js"
+  matrix: "--mm:refc; --mm:orc"
+  output: '''
+x + y = 30
+'''
+"""
+import std/[sugar, algorithm, random, sets, tables, strutils, sequtils]
+import std/[syncio, assertions]
+
+type # for capture test, ref #20679
+  FooCapture = ref object
+    x: int
+
+proc mainProc() =
+  block: # bug #16967
+    var s = newSeq[proc (): int](5)
+    {.push exportc.}
+    proc bar() =
+      for i in 0 ..< s.len:
+        let foo = i + 1
+        capture foo:
+          s[i] = proc(): int = foo
+    {.pop.}
+
+    bar()
+
+    for i, p in s.pairs:
+      let foo = i + 1
+      doAssert p() == foo
+
+template main() =
+  block: # `=>`
+    block:
+      let f1 = () => 42
+      doAssert f1() == 42
+
+      let f2 = (x: int) => x + 1
+      doAssert f2(42) == 43
+
+      let f3 = (x, y: int) => x + y
+      doAssert f3(1, 2) == 3
+
+      var x = 0
+      let f4 = () => (x = 12)
+      f4()
+      doAssert x == 12
+
+      let f5 = () => (discard) # simplest proc that returns void
+      f5()
+
+    block:
+      proc call1(f: () -> int): int = f()
+      doAssert call1(() => 12) == 12
+
+      proc call2(f: int -> int): int = f(42)
+      doAssert call2(x => x) == 42
+      doAssert call2((x) => x) == 42
+      doAssert call2((x: int) => x) == 42
+
+      proc call3(f: (int, int) -> int): int = f(1, 2)
+      doAssert call3((x, y) => x + y) == 3
+      doAssert call3((x, y: int) => x + y) == 3
+      doAssert call3((x: int, y: int) => x + y) == 3
+
+      var a = 0
+      proc call4(f: int -> void) = f(42)
+      call4((x: int) => (a = x))
+      doAssert a == 42
+
+      proc call5(f: (int {.noSideEffect.} -> int)): int = f(42)
+      doAssert call5(x {.noSideEffect.} => x + 1) == 43
+
+  block: # `->`
+    doAssert $(() -> int) == "proc (): int{.closure.}"
+    doAssert $(float -> int) == "proc (i0: float): int{.closure.}"
+    doAssert $((float) -> int) == "proc (i0: float): int{.closure.}"
+    doAssert $((float, bool) -> int) == "proc (i0: float, i1: bool): int{.closure.}"
+
+    doAssert $(() -> void) == "proc (){.closure.}"
+    doAssert $(float -> void) == "proc (i0: float){.closure.}"
+    doAssert $((float) -> void) == "proc (i0: float){.closure.}"
+    doAssert $((float, bool) -> void) == "proc (i0: float, i1: bool){.closure.}"
+
+    doAssert $(() {.inline.} -> int) == "proc (): int{.inline.}"
+    doAssert $(float {.inline.} -> int) == "proc (i0: float): int{.inline.}"
+    doAssert $((float) {.inline.} -> int) == "proc (i0: float): int{.inline.}"
+    doAssert $((float, bool) {.inline.} -> int) == "proc (i0: float, i1: bool): int{.inline.}"
+
+  block: # capture
+    var closure1: () -> int
+    for i in 0 .. 10:
+      if i == 5:
+        capture i:
+          closure1 = () => i
+    doAssert closure1() == 5
+
+    var closure2: () -> (int, int)
+    for i in 0 .. 10:
+      for j in 0 .. 10:
+        if i == 5 and j == 3:
+          capture i, j:
+            closure2 = () => (i, j)
+    doAssert closure2() == (5, 3)
+
+    block: # issue #20679
+      # this should compile. Previously was broken as `var int` is an `nnkHiddenDeref`
+      # which was not handled correctly
+
+      block:
+        var x = 5
+        var s1 = newSeq[proc (): int](2)
+        proc function(data: var int) =
+          for i in 0 ..< 2:
+            data = (i+1) * data
+            capture data:
+              s1[i] = proc(): int = data
+        function(x)
+        doAssert s1[0]() == 5
+        doAssert s1[1]() == 10
+
+
+      block:
+        var y = @[5, 10]
+        var s2 = newSeq[proc (): seq[int]](2)
+        proc functionS(data: var seq[int]) =
+          for i in 0 ..< 2:
+            data.add (i+1) * 5
+            capture data:
+              s2[i] = proc(): seq[int] = data
+        functionS(y)
+        doAssert s2[0]() == @[5, 10, 5]
+        doAssert s2[1]() == @[5, 10, 5, 10]
+
+
+      template typeT(typ, val: untyped): untyped =
+        var x = val
+        var s = newSeq[proc (): typ](2)
+
+        proc functionT[T](data: var T) =
+          for i in 0 ..< 2:
+            if i == 1:
+              data = default(T)
+            capture data:
+              s[i] = proc (): T = data
+
+        functionT(x)
+        doAssert s[0]() == val
+        doAssert s[1]() == x # == default
+        doAssert s[1]() == default(typ)
+
+      block:
+        var x = 1.1
+        typeT(float, x)
+      block:
+        var x = "hello"
+        typeT(string, x)
+      block:
+        var f = FooCapture(x: 5)
+        typeT(FooCapture, f)
+
+  block: # dup
+    block dup_with_field:
+      type
+        Foo = object
+          col, pos: int
+          name: string
+
+      proc inc_col(foo: var Foo) = inc(foo.col)
+      proc inc_pos(foo: var Foo) = inc(foo.pos)
+      proc name_append(foo: var Foo, s: string) = foo.name &= s
+
+      let a = Foo(col: 1, pos: 2, name: "foo")
+      block:
+        let b = a.dup(inc_col, inc_pos):
+          _.pos = 3
+          name_append("bar")
+          inc_pos
+
+        doAssert(b == Foo(col: 2, pos: 4, name: "foobar"))
+
+      block:
+        let b = a.dup(inc_col, pos = 3, name = "bar"):
+          name_append("bar")
+          inc_pos
+
+        doAssert(b == Foo(col: 2, pos: 4, name: "barbar"))
+
+    block:
+      var a = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
+      doAssert dup(a, sort(_)) == sorted(a)
+      doAssert a.dup(sort) == sorted(a)
+      # Chaining:
+      var aCopy = a
+      aCopy.insert(10)
+      doAssert a.dup(insert(10)).dup(sort()) == sorted(aCopy)
+
+    block:
+      when nimvm: discard
+      else:
+        const b = @[0, 1, 2]
+        discard b.dup shuffle()
+        doAssert b[0] == 0
+        doAssert b[1] == 1
+
+  block: # collect
+    let data = @["bird", "word"] # if this gets stuck in your head, its not my fault
+
+    doAssert collect(newSeq, for (i, d) in data.pairs: (if i mod 2 == 0: d)) == @["bird"]
+    doAssert collect(initTable(2), for (i, d) in data.pairs: {i: d}) ==
+      {0: "bird", 1: "word"}.toTable
+    doAssert collect(initHashSet(), for d in data.items: {d}) == data.toHashSet
+
+    block:
+      let x = collect(newSeqOfCap(4)):
+          for (i, d) in data.pairs:
+            if i mod 2 == 0: d
+      doAssert x == @["bird"]
+
+    block: # bug #12874
+      let bug = collect(
+          newSeq,
+          for (i, d) in data.pairs:(
+            block:
+              if i mod 2 == 0:
+                d
+              else:
+                d & d
+            )
+      )
+      doAssert bug == @["bird", "wordword"]
+
+    block:
+      let y = collect(newSeq):
+        for (i, d) in data.pairs:
+          try: parseInt(d) except: 0
+      doAssert y == @[0, 0]
+
+    block:
+      let z = collect(newSeq):
+        for (i, d) in data.pairs:
+          case d
+          of "bird": "word"
+          else: d
+      doAssert z == @["word", "word"]
+
+    block:
+      proc tforum(): seq[int] =
+        collect(newSeq):
+          for y in 0..10:
+            if y mod 5 == 2:
+              for x in 0..y:
+                x
+      doAssert tforum() == @[0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7]
+
+    block:
+      let x = collect:
+        for d in data.items:
+          when d is int: "word"
+          else: d
+      doAssert x == @["bird", "word"]
+
+    block:
+      doAssert collect(for (i, d) in pairs(data): (i, d)) == @[(0, "bird"), (1, "word")]
+      doAssert collect(for d in data.items: (try: parseInt(d) except: 0)) == @[0, 0]
+      doAssert collect(for (i, d) in pairs(data): {i: d}) ==
+        {1: "word", 0: "bird"}.toTable
+      doAssert collect(for d in data.items: {d}) == data.toHashSet
+
+    block: # bug #14332
+      template foo =
+        discard collect(newSeq, for i in 1..3: i)
+      foo()
+
+  block: # dump
+    # symbols in templates are gensym'd
+    let
+      x {.inject.} = 10
+      y {.inject.} = 20
+    dump(x + y) # x + y = 30
+
+  block: # dumpToString
+    template square(x): untyped = x * x
+    let x {.inject.} = 10
+    doAssert dumpToString(square(x)) == "square(x): x * x = 100"
+    let s = dumpToString(doAssert 1+1 == 2)
+    doAssert "failedAssertImpl" in s
+    let s2 = dumpToString:
+      doAssertRaises(AssertionDefect): doAssert false
+    doAssert "except AssertionDefect" in s2
+
+  block: # bug #20704
+    proc test() =
+      var xs, ys: seq[int]
+      for i in 0..5:
+        xs.add(i)
+
+      xs.apply(proc (d: auto) = ys.add(d))
+      # ^ can be turned into d => ys.add(d) when we can infer void return type, #16906
+      doAssert ys == @[0, 1, 2, 3, 4, 5]
+
+    test()
+
+  mainProc()
+
+when not defined(js): # TODO fixme JS VM
+  static:
+    main()
+
+main()
diff --git a/tests/stdlib/tsums.nim b/tests/stdlib/tsums.nim
new file mode 100644
index 000000000..cf410cddf
--- /dev/null
+++ b/tests/stdlib/tsums.nim
@@ -0,0 +1,27 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/sums
+from math import pow
+import std/assertions
+
+var epsilon = 1.0
+while 1.0 + epsilon != 1.0:
+  epsilon /= 2.0
+let data = @[1.0, epsilon, -epsilon]
+doAssert sumKbn(data) == 1.0
+# doAssert sumPairs(data) != 1.0 # known to fail in 64 bits
+doAssert (1.0 + epsilon) - epsilon != 1.0
+
+var tc1: seq[float]
+for n in 1 .. 1000:
+  tc1.add 1.0 / n.float
+doAssert sumKbn(tc1) == 7.485470860550345
+doAssert sumPairs(tc1) == 7.485470860550345
+
+var tc2: seq[float]
+for n in 1 .. 1000:
+  tc2.add pow(-1.0, n.float) / n.float
+doAssert sumKbn(tc2) == -0.6926474305598203
+doAssert sumPairs(tc2) == -0.6926474305598204
diff --git a/tests/stdlib/tsysrand.nim b/tests/stdlib/tsysrand.nim
new file mode 100644
index 000000000..7b7a0fc34
--- /dev/null
+++ b/tests/stdlib/tsysrand.nim
@@ -0,0 +1,34 @@
+discard """
+  targets: "c cpp js"
+  matrix: "--experimental:vmopsDanger; --experimental:vmopsDanger --mm:refc"
+"""
+
+import std/sysrand
+import std/assertions
+
+template main() =
+  block:
+    var x = array[5, byte].default
+    doAssert urandom(x)
+
+  block:
+    var x = newSeq[byte](5)
+    doAssert urandom(x)
+
+  block:
+    var x = @[byte(0), 0, 0, 0, 0]
+    doAssert urandom(x)
+
+  block:
+    var x = @[byte(1), 2, 3, 4, 5]
+    doAssert urandom(x)
+
+  block:
+    doAssert urandom(0).len == 0
+    doAssert urandom(10).len == 10
+    doAssert urandom(20).len == 20
+    doAssert urandom(120).len == 120
+    doAssert urandom(113).len == 113
+    doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice
+
+main()
diff --git a/tests/stdlib/tsystem.nim b/tests/stdlib/tsystem.nim
new file mode 100644
index 000000000..f634ce0c2
--- /dev/null
+++ b/tests/stdlib/tsystem.nim
@@ -0,0 +1,200 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import stdtest/testutils
+import std/[assertions, formatfloat]
+
+# TODO: in future work move existing `system` tests here, where they belong
+
+
+template main =
+  block: # closure
+    proc outer() =
+      var a = 0
+      proc inner1 = a.inc
+      proc inner2 = discard
+      doAssert inner1 is "closure"
+      doAssert inner2 isnot "closure"
+      doAssert inner1 is (proc)
+      doAssert inner2 is (proc)
+      let inner1b = inner1
+      doAssert inner1b is "closure"
+      doAssert inner1b == inner1
+    outer()
+
+  block: # rawProc, rawProc, bug #17911
+    proc outer() =
+      var a = 0
+      var b = 0
+      proc inner1() = a.inc
+      proc inner2() = a += 2
+      proc inner3() = b.inc
+      let inner1b = inner1
+      doAssert inner2 != inner1
+      doAssert inner3 != inner1
+      whenVMorJs: discard
+      do:
+        doAssert rawProc(inner1b) == rawProc(inner1)
+        doAssert rawProc(inner2) != rawProc(inner1)
+        doAssert rawProc(inner3) != rawProc(inner1)
+
+        doAssert rawEnv(inner1b) == rawEnv(inner1)
+        doAssert rawEnv(inner2) == rawEnv(inner1) # because both use `a`
+        # doAssert rawEnv(inner3) != rawEnv(inner1) # because `a` vs `b` # this doesn't hold
+    outer()
+
+  block: # system.delete
+    block:
+      var s = @[1]
+      s.delete(0)
+      doAssert s == @[]
+
+    block:
+      var s = @["foo", "bar"]
+      s.delete(1)
+      doAssert s == @["foo"]
+
+    when false:
+      var s: seq[string]
+      doAssertRaises(IndexDefect):
+        s.delete(0)
+
+    block:
+      doAssert not compiles(@["foo"].delete(-1))
+
+    block: # bug #6710
+      var s = @["foo"]
+      s.delete(0)
+      doAssert s == @[]
+
+    when false: # bug #16544: deleting out of bounds index should raise
+      var s = @["foo"]
+      doAssertRaises(IndexDefect):
+        s.delete(1)
+
+static: main()
+main()
+
+# bug #19967
+block:
+  type
+    X = object
+      a: string
+      b: set[char]
+      c: int
+      d: float
+      e: int64
+
+
+  var x = X(b: {'a'}, e: 10)
+
+  var y = move x
+
+  doAssert x.a == ""
+  doAssert x.b == {}
+  doAssert x.c == 0
+  doAssert x.d == 0.0
+  doAssert x.e == 0
+
+  reset(y)
+
+  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
+    X = object
+      a: string
+      b: float
+
+  var y = X(b: 1314.521)
+
+  reset(y)
+
+  doAssert y.b == 0.0
+
+block:
+  type
+    X = object
+      a: string
+      b: string
+
+  var y = X(b: "1314")
+
+  reset(y)
+
+  doAssert y.b == ""
+
+block:
+  type
+    X = object
+      a: string
+      b: seq[int]
+
+  var y = X(b: @[1, 3])
+
+  reset(y)
+
+  doAssert y.b == @[]
+
+block:
+  type
+    X = object
+      a: string
+      b: tuple[a: int, b: string]
+
+  var y = X(b: (1, "cc"))
+
+  reset(y)
+
+  doAssert y.b == (0, "")
+
+block:
+  type
+    Color = enum
+      Red, Blue, Yellow
+    X = object
+      a: string
+      b: set[Color]
+
+  var y = X(b: {Red, Blue})
+
+  reset(y)
+  doAssert y.b == {}
+
+block: # bug #20516
+  type Foo = object
+    x {.bitsize:4.}: uint
+    y {.bitsize:4.}: uint
+
+  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/ttables.nim b/tests/stdlib/ttables.nim
new file mode 100644
index 000000000..c529aff9f
--- /dev/null
+++ b/tests/stdlib/ttables.nim
@@ -0,0 +1,316 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import tables, hashes
+import std/assertions
+
+type
+  Person = object
+    firstName, lastName: string
+
+proc hash(x: Person): Hash =
+  ## Piggyback on the already available string hash proc.
+  ##
+  ## Without this proc nothing works!
+  result = x.firstName.hash !& x.lastName.hash
+  result = !$result
+
+var
+  salaries = initTable[Person, int]()
+  p1, p2: Person
+p1.firstName = "Jon"
+p1.lastName = "Ross"
+salaries[p1] = 30_000
+p2.firstName = "소진"
+p2.lastName = "ë°•"
+salaries[p2] = 45_000
+var
+  s2 = initOrderedTable[Person, int]()
+  s3 = initCountTable[Person]()
+s2[p1] = 30_000
+s2[p2] = 45_000
+s3[p1] = 30_000
+s3[p2] = 45_000
+
+block: # Ordered table should preserve order after deletion
+  var
+    s4 = initOrderedTable[int, int]()
+  s4[1] = 1
+  s4[2] = 2
+  s4[3] = 3
+
+  var prev = 0
+  for i in s4.values:
+    doAssert(prev < i)
+    prev = i
+
+  s4.del(2)
+  doAssert(2 notin s4)
+  doAssert(s4.len == 2)
+  prev = 0
+  for i in s4.values:
+    doAssert(prev < i)
+    prev = i
+
+block: # Deletion from OrderedTable should account for collision groups. See issue #5057.
+  # The bug is reproducible only with exact keys
+  const key1 = "boy_jackpot.inGamma"
+  const key2 = "boy_jackpot.outBlack"
+
+  var t = {
+      key1: 0,
+      key2: 0
+  }.toOrderedTable()
+
+  t.del(key1)
+  doAssert(t.len == 1)
+  doAssert(key2 in t)
+
+var
+  t1 = initCountTable[string]()
+  t2 = initCountTable[string]()
+t1.inc("foo")
+t1.inc("bar", 2)
+t1.inc("baz", 3)
+t2.inc("foo", 4)
+t2.inc("bar")
+t2.inc("baz", 11)
+merge(t1, t2)
+doAssert(t1["foo"] == 5)
+doAssert(t1["bar"] == 3)
+doAssert(t1["baz"] == 14)
+
+let
+  t1r = newCountTable[string]()
+  t2r = newCountTable[string]()
+t1r.inc("foo")
+t1r.inc("bar", 2)
+t1r.inc("baz", 3)
+t2r.inc("foo", 4)
+t2r.inc("bar")
+t2r.inc("baz", 11)
+merge(t1r, t2r)
+doAssert(t1r["foo"] == 5)
+doAssert(t1r["bar"] == 3)
+doAssert(t1r["baz"] == 14)
+
+var
+  t1l = initCountTable[string]()
+  t2l = initCountTable[string]()
+t1l.inc("foo")
+t1l.inc("bar", 2)
+t1l.inc("baz", 3)
+t2l.inc("foo", 4)
+t2l.inc("bar")
+t2l.inc("baz", 11)
+
+block:
+  const testKey = "TESTKEY"
+  let t: CountTableRef[string] = newCountTable[string]()
+
+  # Before, does not compile with error message:
+  #test_counttable.nim(7, 43) template/generic instantiation from here
+  #lib/pure/collections/tables.nim(117, 21) template/generic instantiation from here
+  #lib/pure/collections/tableimpl.nim(32, 27) Error: undeclared field: 'hcode
+  doAssert 0 == t[testKey]
+  t.inc(testKey, 3)
+  doAssert 3 == t[testKey]
+
+block:
+  # Clear tests
+  var clearTable = newTable[int, string]()
+  clearTable[42] = "asd"
+  clearTable[123123] = "piuyqwb "
+  doAssert clearTable[42] == "asd"
+  clearTable.clear()
+  doAssert(not clearTable.hasKey(123123))
+  doAssert clearTable.getOrDefault(42) == ""
+
+block: #5482
+  var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
+  var b = newOrderedTable[string, string](initialSize = 2)
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block: #5482
+  var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
+  var b = newOrderedTable[string, string](initialSize = 2)
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block: #5487
+  var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
+  var b = newOrderedTable[string, string]()         # notice, default size!
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block: #5487
+  var a = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
+  var b = newOrderedTable[string, string]()         # notice, default size!
+  b["wrong?"] = "foo"
+  b["wrong?"] = "foo2"
+  doAssert a == b
+
+block:
+  var a = {"wrong?": "foo", "wrong?": "foo2"}.newOrderedTable()
+  var b = [("wrong?", "foo"), ("wrong?", "foo2")].newOrderedTable()
+  var c = newOrderedTable[string, string]()         # notice, default size!
+  c["wrong?"] = "foo"
+  c["wrong?"] = "foo2"
+  doAssert a == b
+  doAssert a == c
+
+block: #6250
+  let
+    a = {3: 1}.toOrderedTable
+    b = {3: 2}.toOrderedTable
+  doAssert((a == b) == false)
+  doAssert((b == a) == false)
+
+block: #6250
+  let
+    a = {3: 2}.toOrderedTable
+    b = {3: 2}.toOrderedTable
+  doAssert((a == b) == true)
+  doAssert((b == a) == true)
+
+block: # CountTable.smallest
+  let t = toCountTable([0, 0, 5, 5, 5])
+  doAssert t.smallest == (0, 2)
+
+block: #10065
+  let t = toCountTable("abracadabra")
+  doAssert t['z'] == 0
+
+  var t_mut = toCountTable("abracadabra")
+  doAssert t_mut['z'] == 0
+  # the previous read may not have modified the table.
+  doAssert t_mut.hasKey('z') == false
+  t_mut['z'] = 1
+  doAssert t_mut['z'] == 1
+  doAssert t_mut.hasKey('z') == true
+
+block: #12813 #13079
+  var t = toCountTable("abracadabra")
+  doAssert len(t) == 5
+
+  t['a'] = 0 # remove a key
+  doAssert len(t) == 4
+
+block:
+  var tp: Table[string, string] = initTable[string, string]()
+  doAssert "test1" == tp.getOrDefault("test1", "test1")
+  tp["test2"] = "test2"
+  doAssert "test2" == tp.getOrDefault("test2", "test1")
+  var tr: TableRef[string, string] = newTable[string, string]()
+  doAssert "test1" == tr.getOrDefault("test1", "test1")
+  tr["test2"] = "test2"
+  doAssert "test2" == tr.getOrDefault("test2", "test1")
+  var op: OrderedTable[string, string] = initOrderedTable[string, string]()
+  doAssert "test1" == op.getOrDefault("test1", "test1")
+  op["test2"] = "test2"
+  doAssert "test2" == op.getOrDefault("test2", "test1")
+  var orf: OrderedTableRef[string, string] = newOrderedTable[string, string]()
+  doAssert "test1" == orf.getOrDefault("test1", "test1")
+  orf["test2"] = "test2"
+  doAssert "test2" == orf.getOrDefault("test2", "test1")
+
+block tableWithoutInit:
+  var
+    a: Table[string, int]
+    b: Table[string, int]
+    c: Table[string, int]
+    d: Table[string, int]
+    e: Table[string, int]
+
+  a["a"] = 7
+  doAssert a.hasKey("a")
+  doAssert a.len == 1
+  doAssert a["a"] == 7
+  a["a"] = 9
+  doAssert a.len == 1
+  doAssert a["a"] == 9
+
+  doAssert b.hasKeyOrPut("b", 5) == false
+  doAssert b.hasKey("b")
+  doAssert b.hasKeyOrPut("b", 8)
+  doAssert b["b"] == 5
+
+  doAssert c.getOrDefault("a") == 0
+  doAssert c.getOrDefault("a", 3) == 3
+  c["a"] = 6
+  doAssert c.getOrDefault("a", 3) == 6
+
+  doAssert d.mgetOrPut("a", 3) == 3
+  doAssert d.mgetOrPut("a", 6) == 3
+
+  var x = 99
+  doAssert e.pop("a", x) == false
+  doAssert x == 99
+  e["a"] = 77
+  doAssert e.pop("a", x)
+  doAssert x == 77
+
+block orderedTableWithoutInit:
+  var
+    a: OrderedTable[string, int]
+    b: OrderedTable[string, int]
+    c: OrderedTable[string, int]
+    d: OrderedTable[string, int]
+
+  a["a"] = 7
+  doAssert a.hasKey("a")
+  doAssert a.len == 1
+  doAssert a["a"] == 7
+  a["a"] = 9
+  doAssert a.len == 1
+  doAssert a["a"] == 9
+
+  doAssert b.hasKeyOrPut("b", 5) == false
+  doAssert b.hasKey("b")
+  doAssert b.hasKeyOrPut("b", 8)
+  doAssert b["b"] == 5
+
+  doAssert c.getOrDefault("a") == 0
+  doAssert c.getOrDefault("a", 3) == 3
+  c["a"] = 6
+  doAssert c.getOrDefault("a", 3) == 6
+
+  doAssert d.mgetOrPut("a", 3) == 3
+  doAssert d.mgetOrPut("a", 6) == 3
+
+block countTableWithoutInit:
+  var
+    a: CountTable[string]
+    b: CountTable[string]
+    c: CountTable[string]
+    d: CountTable[string]
+    e: CountTable[string]
+
+  a["a"] = 7
+  doAssert a.hasKey("a")
+  doAssert a.len == 1
+  doAssert a["a"] == 7
+  a["a"] = 9
+  doAssert a.len == 1
+  doAssert a["a"] == 9
+
+  doAssert b["b"] == 0
+  b.inc("b")
+  doAssert b["b"] == 1
+
+  doAssert c.getOrDefault("a") == 0
+  doAssert c.getOrDefault("a", 3) == 3
+  c["a"] = 6
+  doAssert c.getOrDefault("a", 3) == 6
+
+  e["f"] = 3
+  merge(d, e)
+  doAssert d.hasKey("f")
+  d.inc("f")
+  merge(d, e)
+  doAssert d["f"] == 7
diff --git a/tests/stdlib/ttasks.nim b/tests/stdlib/ttasks.nim
new file mode 100644
index 000000000..ba65590d9
--- /dev/null
+++ b/tests/stdlib/ttasks.nim
@@ -0,0 +1,561 @@
+discard """
+  targets: "c cpp"
+  matrix: "--gc:orc --threads:off"
+"""
+
+import std/[tasks, strformat]
+import std/assertions
+
+block:
+  var s = ""
+  proc `+`(x: int, y: string) =
+    s.add $x & y
+
+  let literal = "Nim"
+  let t = toTask(521 + literal)
+  t.invoke()
+
+  doAssert s == "521Nim"
+
+block:
+  var s = ""
+  proc `!`(x: int) =
+    s.add $x
+
+  let t = toTask !12
+  t.invoke()
+
+  doAssert s == "12"
+
+
+block:
+  block:
+    var called = 0
+    proc hello(x: static range[1 .. 5]) =
+      called += x
+
+    let b = toTask hello(3)
+    b.invoke()
+    doAssert called == 3
+    b.invoke()
+    doAssert called == 6
+
+  block:
+    var called = 0
+    proc hello(x: range[1 .. 5]) =
+      called += x
+
+    let b = toTask hello(3)
+    b.invoke()
+    doAssert called == 3
+    b.invoke()
+    doAssert called == 6
+
+  block:
+    var called = 0
+    proc hello(x: 1 .. 5) =
+      called += x
+
+    let b = toTask hello(3)
+    b.invoke()
+    doAssert called == 3
+    b.invoke()
+    doAssert called == 6
+
+  block:
+    var temp = ""
+    proc hello(a: int or seq[string]) =
+      when a is seq[string]:
+        for s in a:
+          temp.add s
+      else:
+        temp.addInt a
+
+    let x = @["1", "2", "3", "4"]
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == "1234"
+    b.invoke()
+    doAssert temp == "12341234"
+
+
+  block:
+    var temp = ""
+
+    proc hello(a: int or string) =
+      when a is string:
+        temp.add a
+
+    let x = "!2"
+
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == x
+
+  block:
+    var temp = ""
+    proc hello(a: int or string) =
+      when a is string:
+        temp.add a
+
+    let x = "!2"
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == x
+
+  block:
+    var x = 0
+    proc hello(typ: typedesc) =
+      x += typ(12)
+
+    let b = toTask hello(int)
+    b.invoke()
+    doAssert x == 12
+
+  block:
+    var temp = ""
+    proc hello(a: int or seq[string]) =
+      when a is seq[string]:
+        for s in a:
+          temp.add s
+
+    let x = @["1", "2", "3", "4"]
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == "1234"
+
+  block:
+    var temp = ""
+    proc hello(a: int | string) =
+      when a is string:
+        temp.add a
+
+    let x = "!2"
+    let b = toTask hello(x)
+    b.invoke()
+    doAssert temp == x
+
+  block:
+    var x = 0
+    proc hello(a: int | string) =
+      when a is int:
+        x = a
+
+    let b = toTask hello(12)
+    b.invoke()
+    doAssert x == 12
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(c: seq[int], a: int) =
+      a1 = c
+      a2 = a
+
+    let x = 12
+    var y = @[1, 3, 1, 4, 5, x, 1]
+    let b = toTask hello(y, 12)
+    b.invoke()
+
+    doAssert a1 == y
+    doAssert a2 == x
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(c: seq[int], a: int) =
+      a1 = c
+      a2 = a
+    var x = 2
+    let b = toTask hello(@[1, 3, 1, 4, 5, x, 1], 12)
+    b.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, x, 1]
+    doAssert a2 == 12
+
+  block:
+    var a1: array[7, int]
+    var a2 = 0
+    proc hello(c: array[7, int], a: int) =
+      a1 = c
+      a2 = a
+
+    let b = toTask hello([1, 3, 1, 4, 5, 2, 1], 12)
+    b.invoke()
+
+    doAssert a1 == [1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 12
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(c: seq[int], a: int) =
+      a1 = c
+      a2 = a
+
+    let b = toTask hello(@[1, 3, 1, 4, 5, 2, 1], 12)
+    b.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 12
+
+  block:
+    var a1: seq[int]
+    var a2 = 0
+    proc hello(a: int, c: seq[int]) =
+      a1 = c
+      a2 = a
+
+    let b = toTask hello(8, @[1, 3, 1, 4, 5, 2, 1])
+    b.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 8
+
+    let c = toTask 8.hello(@[1, 3, 1, 4, 5, 2, 1])
+    c.invoke()
+
+    doAssert a1 == @[1, 3, 1, 4, 5, 2, 1]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[seq[int]]
+    var a2: int
+    proc hello(a: int, c: openArray[seq[int]]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, @[@[3], @[4], @[5], @[6], @[12], @[7]])
+    b.invoke()
+
+    doAssert a1 ==  @[@[3], @[4], @[5], @[6], @[12], @[7]]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: openArray[int]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, @[3, 4, 5, 6, 12, 7])
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: static varargs[int]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, @[3, 4, 5, 6, 12, 7])
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: static varargs[int]) =
+      a1 = @c
+      a2 = a
+
+    let b = toTask hello(8, [3, 4, 5, 6, 12, 7])
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var a1: seq[int]
+    var a2: int
+    proc hello(a: int, c: varargs[int]) =
+      a1 = @c
+      a2 = a
+
+    let x = 12
+    let b = toTask hello(8, 3, 4, 5, 6, x, 7)
+    b.invoke()
+
+    doAssert a1 == @[3, 4, 5, 6, 12, 7]
+    doAssert a2 == 8
+
+  block:
+    var x = 12
+
+    proc hello(x: ptr int) =
+      x[] += 12
+
+    let b = toTask hello(addr x)
+    b.invoke()
+
+    doAssert x == 24
+
+    let c = toTask x.addr.hello
+    invoke(c)
+
+    doAssert x == 36
+  block:
+    type
+      Test = ref object
+        id: int
+
+    var x = 0
+    proc hello(a: int, c: static Test) =
+      x += a
+      x += c.id
+
+    let b = toTask hello(8, Test(id: 12))
+    b.invoke()
+
+    doAssert x == 20
+
+  block:
+    type
+      Test = object
+        id: int
+
+    var x = 0
+    proc hello(a: int, c: static Test) =
+      x += a
+      x += c.id
+
+    let b = toTask hello(8, Test(id: 12))
+    b.invoke()
+    doAssert x == 20
+
+  block:
+    var x = 0
+    proc hello(a: int, c: static seq[int]) =
+      x += a
+      for i in c:
+        x += i
+
+    let b = toTask hello(8, @[3, 4, 5, 6, 12, 7])
+    b.invoke()
+    doAssert x == 45
+
+  block:
+    var x = 0
+    proc hello(a: int, c: static array[5, int]) =
+      x += a
+      for i in c:
+        x += i
+
+    let b = toTask hello(8, [3, 4, 5, 6, 12])
+    b.invoke()
+    doAssert x == 38
+
+  block:
+    var aVal = 0
+    var cVal = ""
+
+    proc hello(a: int, c: static string) =
+      aVal += a
+      cVal.add c
+
+    var x = 1314
+    let b = toTask hello(x, "hello")
+    b.invoke()
+
+    doAssert aVal == x
+    doAssert cVal == "hello"
+
+  block:
+    var aVal = ""
+
+    proc hello(a: static string) =
+      aVal.add a
+    let b = toTask hello("hello")
+    b.invoke()
+
+    doAssert aVal == "hello"
+
+  block:
+    var aVal = 0
+    var cVal = ""
+
+    proc hello(a: static int, c: static string) =
+      aVal += a
+      cVal.add c
+    let b = toTask hello(8, "hello")
+    b.invoke()
+
+    doAssert aVal == 8
+    doAssert cVal == "hello"
+
+  block:
+    var aVal = 0
+    var cVal = 0
+
+    proc hello(a: static int, c: int) =
+      aVal += a
+      cVal += c
+
+    let b = toTask hello(c = 0, a = 8)
+    b.invoke()
+
+    doAssert aVal == 8
+    doAssert cVal == 0
+
+  block:
+    var aVal = 0
+    var cVal = 0
+
+    proc hello(a: int, c: static int) =
+      aVal += a
+      cVal += c
+
+    let b = toTask hello(c = 0, a = 8)
+    b.invoke()
+
+    doAssert aVal == 8
+    doAssert cVal == 0
+
+  block:
+    var aVal = 0
+    var cVal = 0
+
+    proc hello(a: static int, c: static int) =
+      aVal += a
+      cVal += c
+
+    let b = toTask hello(0, 8)
+    b.invoke()
+
+    doAssert aVal == 0
+    doAssert cVal == 8
+
+  block:
+    var temp = ""
+    proc hello(x: int, y: seq[string], d = 134) =
+      temp = fmt"{x=} {y=} {d=}"
+
+
+    proc main() =
+      var x = @["23456"]
+      let t = toTask hello(2233, x)
+      t.invoke()
+
+      doAssert temp == """x=2233 y=@["23456"] d=134"""
+
+    main()
+
+
+  block:
+    var temp = ""
+    proc hello(x: int, y: seq[string], d = 134) =
+      temp.add fmt"{x=} {y=} {d=}"
+
+    proc ok() =
+      temp = "ok"
+
+    proc main() =
+      var x = @["23456"]
+      let t = toTask hello(2233, x)
+      t.invoke()
+      t.invoke()
+
+      doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134"""
+
+    main()
+
+    var x = @["4"]
+    let m = toTask hello(2233, x, 7)
+    m.invoke()
+
+    doAssert temp == """x=2233 y=@["23456"] d=134x=2233 y=@["23456"] d=134x=2233 y=@["4"] d=7"""
+
+    let n = toTask ok()
+    n.invoke()
+
+    doAssert temp == "ok"
+
+  block:
+    var called = 0
+    block:
+      proc hello() =
+        inc called
+
+      let a = toTask hello()
+      invoke(a)
+
+    doAssert called == 1
+
+    block:
+      proc hello(a: int) =
+        inc called, a
+
+      let b = toTask hello(13)
+      let c = toTask hello(a = 14)
+      b.invoke()
+      c.invoke()
+
+    doAssert called == 28
+
+    block:
+      proc hello(a: int, c: int) =
+        inc called, a
+
+      let b = toTask hello(c = 0, a = 8)
+      b.invoke()
+
+    doAssert called == 36
+
+  block:
+    proc returnsSomething(a, b: int): int = a + b
+
+    proc noArgsButReturnsSomething(): string = "abcdef"
+
+    proc testReturnValues() =
+      let t = toTask returnsSomething(2233, 11)
+      var res: int
+      t.invoke(addr res)
+      doAssert res == 2233+11
+
+      let tb = toTask noArgsButReturnsSomething()
+      var resB: string
+      tb.invoke(addr resB)
+      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/ttempfiles.nim b/tests/stdlib/ttempfiles.nim
new file mode 100644
index 000000000..352788c42
--- /dev/null
+++ b/tests/stdlib/ttempfiles.nim
@@ -0,0 +1,51 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false # not strictly necessary
+"""
+
+import std/tempfiles
+import std/[os, nre]
+import std/[assertions, syncio]
+
+const
+  prefix = "D20210502T100442" # safety precaution to only affect files/dirs with this prefix
+  suffix = ".tmp"
+
+block:
+  var t1 = createTempFile(prefix, suffix)
+  var t2 = createTempFile(prefix, suffix)
+  defer:
+    close(t1.cfile)
+    close(t2.cfile)
+    removeFile(t1.path)
+    removeFile(t2.path)
+
+  doAssert t1.path != t2.path
+
+  let s = "1234"
+  write(t1.cfile, s)
+  doAssert readAll(t2.cfile) == ""
+  doAssert readAll(t1.cfile) == ""
+  t1.cfile.setFilePos 0
+  doAssert readAll(t1.cfile) == s
+
+block: # createTempDir
+  doAssertRaises(OSError): discard createTempDir(prefix, suffix, "nonexistent")
+
+  block:
+    let dir1 = createTempDir(prefix, suffix)
+    let dir2 = createTempDir(prefix, suffix)
+    defer:
+      removeDir(dir1)
+      removeDir(dir2)
+    doAssert dir1 != dir2
+
+    doAssert dirExists(dir1)
+    doAssert dir1.lastPathPart.contains(re"^D20210502T100442(\w+).tmp$")
+    doAssert dir1.parentDir == getTempDir().normalizePathEnd()
+
+  block:
+    let dir3 = createTempDir(prefix, "_mytmp", ".")
+    doAssert dir3.lastPathPart.contains(re"^D20210502T100442(\w+)_mytmp$")
+    doAssert dir3.parentDir == "." # not getCurrentDir(): we honor the absolute/relative state of input `dir`
+    removeDir(dir3)
diff --git a/tests/stdlib/tterminal.nim b/tests/stdlib/tterminal.nim
new file mode 100644
index 000000000..16365e71c
--- /dev/null
+++ b/tests/stdlib/tterminal.nim
@@ -0,0 +1,7 @@
+discard """
+  action: compile
+"""
+import terminal, colors
+
+styledEcho fgColor, colRed, "Test"
+styledEcho bgColor, colBlue, "Test"
diff --git a/tests/stdlib/tterminal_12759.nim b/tests/stdlib/tterminal_12759.nim
new file mode 100644
index 000000000..e9ea3127c
--- /dev/null
+++ b/tests/stdlib/tterminal_12759.nim
@@ -0,0 +1,11 @@
+discard """
+  action: "compile"
+"""
+
+import terminal
+import std/syncio
+
+proc test() {.raises:[IOError, ValueError].} =
+  setBackgroundColor(stdout, bgRed)
+
+test()
diff --git a/tests/stdlib/tterminal_15874.nim b/tests/stdlib/tterminal_15874.nim
new file mode 100644
index 000000000..c3455c350
--- /dev/null
+++ b/tests/stdlib/tterminal_15874.nim
@@ -0,0 +1,8 @@
+discard """
+  cmd: "nim c --app:console $file"
+  action: "compile"
+"""
+
+import terminal
+
+writeStyled("hello", {styleBright})
diff --git a/tests/stdlib/ttestutils.nim b/tests/stdlib/ttestutils.nim
new file mode 100644
index 000000000..0f8bf16cf
--- /dev/null
+++ b/tests/stdlib/ttestutils.nim
@@ -0,0 +1,40 @@
+import stdtest/testutils
+import std/assertions
+
+block: # assertAll
+  assertAll:
+    1+1 == 2
+    var a = 3
+    a == 3
+
+  doAssertRaises(AssertionDefect):
+    assertAll:
+      1+1 == 2
+      var a = 3
+      a == 4
+
+block: # greedyOrderedSubsetLines
+  assertAll:
+    greedyOrderedSubsetLines("a1\na3", "a0\na1\na2\na3\na4")
+    not greedyOrderedSubsetLines("a3\na1", "a0\na1\na2\na3\na4") # out of order
+    not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs
+
+    not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5")
+    not greedyOrderedSubsetLines("a1\na5", "a0\na1\na2\na3\na4\na5:suffix")
+    not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\nprefix:a5")
+    not greedyOrderedSubsetLines("a5", "a0\na1\na2\na3\na4\na5:suffix")
+
+block: # greedyOrderedSubsetLines with allowPrefixMatch = true
+  template fn(a, b): bool =
+    greedyOrderedSubsetLines(a, b, allowPrefixMatch = true)
+  assertAll:
+    fn("a1\na3", "a0\na1\na2\na3_suffix\na4")
+    not fn("a1\na3", "a0\na1\na2\nprefix_a3\na4")
+    # these are same as above, could be refactored
+    not fn("a3\na1", "a0\na1\na2\na3\na4") # out of order
+    not fn("a1\na5", "a0\na1\na2\na3\na4") # a5 not in lhs
+
+    not fn("a1\na5", "a0\na1\na2\na3\na4\nprefix:a5")
+    fn("a1\na5", "a0\na1\na2\na3\na4\na5:suffix")
+    not fn("a5", "a0\na1\na2\na3\na4\nprefix:a5")
+    fn("a5", "a0\na1\na2\na3\na4\na5:suffix")
diff --git a/tests/stdlib/tthreadpool.nim b/tests/stdlib/tthreadpool.nim
new file mode 100644
index 000000000..1947074be
--- /dev/null
+++ b/tests/stdlib/tthreadpool.nim
@@ -0,0 +1,14 @@
+discard """
+  matrix: "--mm:arc; --mm:refc"
+  disabled: "freebsd"
+  output: "42"
+"""
+import std/assertions
+from std/threadpool import spawn, `^`, sync
+block: # bug #12005
+  proc doworkok(i: int) {.thread.} = echo i
+  spawn(doworkok(42))
+  sync() # this works when returning void!
+
+  proc doworkbad(i: int): int {.thread.} = i
+  doAssert ^spawn(doworkbad(42)) == 42 # bug was here
diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim
new file mode 100644
index 000000000..0f04168dc
--- /dev/null
+++ b/tests/stdlib/ttimes.nim
@@ -0,0 +1,784 @@
+discard """
+  matrix: "--mm:refc; --mm:orc; --backend:js --jsbigint64:on; --backend:js --jsbigint64:off -d:nimStringHash2"
+"""
+
+import times, strutils, unittest
+import std/assertions
+
+when not defined(js):
+  import os
+
+proc staticTz(hours, minutes, seconds: int = 0): Timezone {.noSideEffect.} =
+  let offset = hours * 3600 + minutes * 60 + seconds
+
+  proc zonedTimeFromAdjTime(adjTime: Time): ZonedTime =
+    result.isDst = false
+    result.utcOffset = offset
+    result.time = adjTime + initDuration(seconds = offset)
+
+  proc zonedTimeFromTime(time: Time): ZonedTime =
+    result.isDst = false
+    result.utcOffset = offset
+    result.time = time
+
+  newTimezone("", zonedTimeFromTime, zonedTimeFromAdjTime)
+
+template parseTest(s, f, sExpected: string, ydExpected: int) =
+  let
+    parsed = s.parse(f, utc())
+    parsedStr = $parsed
+  check parsedStr == sExpected
+  check parsed.yearday == ydExpected
+
+template parseTestExcp(s, f: string) =
+  expect ValueError:
+    let parsed = s.parse(f)
+
+template parseTestTimeOnly(s, f, sExpected: string) =
+  check sExpected in $s.parse(f, utc())
+
+# because setting a specific timezone for testing is platform-specific, we use
+# explicit timezone offsets in all tests.
+template runTimezoneTests() =
+  parseTest("Tuesday at 09:04am on Dec 15, 2015 +0",
+      "dddd 'at' hh:mmtt 'on' MMM d, yyyy z", "2015-12-15T09:04:00Z", 348)
+  # ANSIC       = "Mon Jan _2 15:04:05 2006"
+  parseTest("Thu Jan 12 15:04:05 2006 +0", "ddd MMM dd HH:mm:ss yyyy z",
+      "2006-01-12T15:04:05Z", 11)
+  # UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
+  parseTest("Thu Jan 12 15:04:05 2006 +0", "ddd MMM dd HH:mm:ss yyyy z",
+      "2006-01-12T15:04:05Z", 11)
+  # RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
+  parseTest("Mon Feb 29 15:04:05 -07:00 2016 +0", "ddd MMM dd HH:mm:ss zzz yyyy z",
+      "2016-02-29T15:04:05Z", 59) # leap day
+  # RFC822      = "02 Jan 06 15:04 MST"
+  parseTest("12 Jan 16 15:04 +0", "dd MMM yy HH:mm z",
+      "2016-01-12T15:04:00Z", 11)
+  # RFC822Z     = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
+  parseTest("01 Mar 16 15:04 -07:00", "dd MMM yy HH:mm zzz",
+      "2016-03-01T22:04:00Z", 60) # day after february in leap year
+  # RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
+  parseTest("Monday, 12-Jan-06 15:04:05 +0", "dddd, dd-MMM-yy HH:mm:ss z",
+      "2006-01-12T15:04:05Z", 11)
+  # RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
+  parseTest("Sun, 01 Mar 2015 15:04:05 +0", "ddd, dd MMM yyyy HH:mm:ss z",
+      "2015-03-01T15:04:05Z", 59) # day after february in non-leap year
+  # RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
+  parseTest("Thu, 12 Jan 2006 15:04:05 -07:00", "ddd, dd MMM yyyy HH:mm:ss zzz",
+      "2006-01-12T22:04:05Z", 11)
+  # RFC3339     = "2006-01-02T15:04:05Z07:00"
+  parseTest("2006-01-12T15:04:05Z-07:00", "yyyy-MM-dd'T'HH:mm:ss'Z'zzz",
+      "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)
+  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,
+        "2001-01-12T22:04:05Z", 11)
+  # timezone offset formats
+  parseTest("2001-01-12T15:04:05 +7", "yyyy-MM-dd'T'HH:mm:ss z",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07", "yyyy-MM-dd'T'HH:mm:ss zz",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07:00", "yyyy-MM-dd'T'HH:mm:ss zzz",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +07:30:59", "yyyy-MM-dd'T'HH:mm:ss zzzz",
+      "2001-01-12T07:33:06Z", 11)
+  parseTest("2001-01-12T15:04:05 +0700", "yyyy-MM-dd'T'HH:mm:ss ZZZ",
+      "2001-01-12T08:04:05Z", 11)
+  parseTest("2001-01-12T15:04:05 +073059", "yyyy-MM-dd'T'HH:mm:ss ZZZZ",
+      "2001-01-12T07:33:06Z", 11)
+  # Kitchen     = "3:04PM"
+  parseTestTimeOnly("3:04PM", "h:mmtt", "15:04:00")
+
+  # Bug with parse not setting DST properly if the current local DST differs from
+  # the date being parsed. Need to test parse dates both in and out of DST. We
+  # are testing that be relying on the fact that transforming a TimeInfo to a Time
+  # and back again will correctly set the DST value. With the incorrect parse
+  # behavior this will introduce a one hour offset from the named time and the
+  # parsed time if the DST value differs between the current time and the date we
+  # are parsing.
+  let dstT1 = parse("2016-01-01 00:00:00", "yyyy-MM-dd HH:mm:ss")
+  let dstT2 = parse("2016-06-01 00:00:00", "yyyy-MM-dd HH:mm:ss")
+  check dstT1 == toTime(dstT1).local
+  check dstT2 == toTime(dstT2).local
+
+  block dstTest:
+    # parsing will set isDST in relation to the local time. We take a date in
+    # January and one in July to maximize the probability to hit one date with DST
+    # and one without on the local machine. However, this is not guaranteed.
+    let
+      parsedJan = parse("2016-01-05 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz")
+      parsedJul = parse("2016-07-01 04:00:00+01:00", "yyyy-MM-dd HH:mm:sszzz")
+    check toTime(parsedJan).toUnix == 1451962800
+    check toTime(parsedJul).toUnix == 1467342000
+
+template usingTimezone(tz: string, body: untyped) =
+  when defined(linux) or defined(macosx):
+    let oldZone = getEnv("TZ")
+    putEnv("TZ", tz)
+    body
+    putEnv("TZ", oldZone)
+
+block: # ttimes
+
+  # Generate tests for multiple timezone files where available
+  # Set the TZ env var for each test
+  when defined(linux) or defined(macosx):
+    let tz_dir = getEnv("TZDIR", "/usr/share/zoneinfo")
+    const f = "yyyy-MM-dd HH:mm zzz"
+
+    var tz_cnt = 0
+    for timezone in walkFiles(tz_dir & "/**/*"):
+      if symlinkExists(timezone) or timezone.endsWith(".tab") or
+          timezone.endsWith(".list"):
+        continue
+
+      usingTimezone(timezone):
+        test "test for " & timezone:
+          tz_cnt.inc
+          runTimezoneTests()
+
+    test "enough timezone files tested":
+      check tz_cnt > 10
+
+  else:
+    # not on Linux or macosx: run in the local timezone only
+    test "parseTest":
+      runTimezoneTests()
+
+  block: # dst handling
+    usingTimezone("Europe/Stockholm"):
+      # In case of an impossible time, the time is moved to after the
+      # impossible time period
+      check initDateTime(26, mMar, 2017, 02, 30, 00).format(f) ==
+        "2017-03-26 03:30 +02:00"
+      # In case of an ambiguous time, the earlier time is chosen
+      check initDateTime(29, mOct, 2017, 02, 00, 00).format(f) ==
+        "2017-10-29 02:00 +02:00"
+      # These are just dates on either side of the dst switch
+      check initDateTime(29, mOct, 2017, 01, 00, 00).format(f) ==
+        "2017-10-29 01:00 +02:00"
+      check initDateTime(29, mOct, 2017, 01, 00, 00).isDst
+      check initDateTime(29, mOct, 2017, 03, 01, 00).format(f) ==
+        "2017-10-29 03:01 +01:00"
+      check (not initDateTime(29, mOct, 2017, 03, 01, 00).isDst)
+
+      check initDateTime(21, mOct, 2017, 01, 00, 00).format(f) ==
+        "2017-10-21 01:00 +02:00"
+
+  block: # issue #6520
+    usingTimezone("Europe/Stockholm"):
+      var local = fromUnix(1469275200).local
+      var utc = fromUnix(1469275200).utc
+
+      let claimedOffset = initDuration(seconds = local.utcOffset)
+      local.utcOffset = 0
+      check claimedOffset == utc.toTime - local.toTime
+
+  block: # issue #5704
+    usingTimezone("Asia/Seoul"):
+      let diff = parse("19700101-000000", "yyyyMMdd-hhmmss").toTime -
+        parse("19000101-000000", "yyyyMMdd-hhmmss").toTime
+      check diff == initDuration(seconds = 2208986872)
+
+  block: # issue #6465
+    usingTimezone("Europe/Stockholm"):
+      let dt = parse("2017-03-25 12:00", "yyyy-MM-dd hh:mm")
+      check $(dt + initTimeInterval(days = 1)) == "2017-03-26T12:00:00+02:00"
+      check $(dt + initDuration(days = 1)) == "2017-03-26T13:00:00+02:00"
+
+  block: # adding/subtracting time across dst
+    usingTimezone("Europe/Stockholm"):
+      let dt1 = initDateTime(26, mMar, 2017, 03, 00, 00)
+      check $(dt1 - 1.seconds) == "2017-03-26T01:59:59+01:00"
+
+      var dt2 = initDateTime(29, mOct, 2017, 02, 59, 59)
+      check  $(dt2 + 1.seconds) == "2017-10-29T02:00:00+01:00"
+
+  block: # datetime before epoch
+    check $fromUnix(-2147483648).utc == "1901-12-13T20:45:52Z"
+
+  block: # incorrect inputs: empty string
+    parseTestExcp("", "yyyy-MM-dd")
+
+  block: # incorrect inputs: year
+    parseTestExcp("20-02-19", "yyyy-MM-dd")
+
+  block: # incorrect inputs: month number
+    parseTestExcp("2018-2-19", "yyyy-MM-dd")
+
+  block: # incorrect inputs: month name
+    parseTestExcp("2018-Fe", "yyyy-MMM-dd")
+
+  block: # incorrect inputs: day
+    parseTestExcp("2018-02-1", "yyyy-MM-dd")
+
+  block: # incorrect inputs: day of week
+    parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd")
+
+  block: # incorrect inputs: hour
+    parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm")
+
+  block: # incorrect inputs: minute
+    parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm")
+
+  block: # incorrect inputs: second
+    parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss")
+
+  block: # incorrect inputs: timezone (z)
+    parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z")
+
+  block: # incorrect inputs: timezone (zz) 1
+    parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz")
+
+  block: # incorrect inputs: timezone (zz) 2
+    parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz")
+
+  block: # incorrect inputs: timezone (zzz) 1
+    parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz")
+
+  block: # incorrect inputs: timezone (zzz) 2
+    parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz")
+
+  block: # incorrect inputs: timezone (zzz) 3
+    parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz")
+
+  block: # incorrect inputs: year (yyyy/uuuu)
+    parseTestExcp("-0001", "yyyy")
+    parseTestExcp("-0001", "YYYY")
+    parseTestExcp("1", "yyyy")
+    parseTestExcp("12345", "yyyy")
+    parseTestExcp("1", "uuuu")
+    parseTestExcp("12345", "uuuu")
+    parseTestExcp("-1 BC", "UUUU g")
+
+  block: # incorrect inputs: invalid sign
+    parseTestExcp("+1", "YYYY")
+    parseTestExcp("+1", "dd")
+    parseTestExcp("+1", "MM")
+    parseTestExcp("+1", "hh")
+    parseTestExcp("+1", "mm")
+    parseTestExcp("+1", "ss")
+
+  block: # _ as a separator
+    discard parse("2000_01_01", "YYYY'_'MM'_'dd")
+
+  block: # dynamic timezone
+    let tz = staticTz(seconds = -9000)
+    let dt = initDateTime(1, mJan, 2000, 12, 00, 00, tz)
+    check dt.utcOffset == -9000
+    check dt.isDst == false
+    check $dt == "2000-01-01T12:00:00+02:30"
+    check $dt.utc == "2000-01-01T09:30:00Z"
+    check $dt.utc.inZone(tz) == $dt
+
+  block: # isLeapYear
+    check isLeapYear(2016)
+    check (not isLeapYear(2015))
+    check isLeapYear(2000)
+    check (not isLeapYear(1900))
+
+  block: # TimeInterval
+    let t = fromUnix(876124714).utc # Mon 6 Oct 08:58:34 BST 1997
+    # Interval tests
+    let t2 = t - 2.years
+    check t2.year == 1995
+    let t3 = (t - 7.years - 34.minutes - 24.seconds)
+    check t3.year == 1990
+    check t3.minute == 24
+    check t3.second == 10
+    check (t + 1.hours).toTime.toUnix == t.toTime.toUnix + 60 * 60
+    check (t - 1.hours).toTime.toUnix == t.toTime.toUnix - 60 * 60
+
+  block: # TimeInterval - months
+    var dt = initDateTime(1, mFeb, 2017, 00, 00, 00, utc())
+    check $(dt - initTimeInterval(months = 1)) == "2017-01-01T00:00:00Z"
+    dt = initDateTime(15, mMar, 2017, 00, 00, 00, utc())
+    check $(dt - initTimeInterval(months = 1)) == "2017-02-15T00:00:00Z"
+    dt = initDateTime(31, mMar, 2017, 00, 00, 00, utc())
+    # This happens due to monthday overflow. It's consistent with Phobos.
+    check $(dt - initTimeInterval(months = 1)) == "2017-03-03T00:00:00Z"
+
+  block: # duration
+    let d = initDuration
+    check d(hours = 48) + d(days = 5) == d(weeks = 1)
+    let dt = initDateTime(01, mFeb, 2000, 00, 00, 00, 0, utc()) + d(milliseconds = 1)
+    check dt.nanosecond == convert(Milliseconds, Nanoseconds, 1)
+    check d(seconds = 1, milliseconds = 500) * 2 == d(seconds = 3)
+    check d(seconds = 3) div 2 == d(seconds = 1, milliseconds = 500)
+    check d(milliseconds = 1001).inSeconds == 1
+    check d(seconds = 1, milliseconds = 500) - d(milliseconds = 1250) ==
+      d(milliseconds = 250)
+    check d(seconds = 1, milliseconds = 1) < d(seconds = 1, milliseconds = 2)
+    check d(seconds = 1) <= d(seconds = 1)
+    check d(seconds = 0) - d(milliseconds = 1500) == d(milliseconds = -1500)
+    check d(milliseconds = -1500) == d(seconds = -1, milliseconds = -500)
+    check d(seconds = -1, milliseconds = 500) == d(milliseconds = -500)
+    check initDuration(seconds = 1, nanoseconds = 2) <=
+      initDuration(seconds = 1, nanoseconds = 3)
+    check (initDuration(seconds = 1, nanoseconds = 3) <=
+      initDuration(seconds = 1, nanoseconds = 1)).not
+
+  block: # large/small dates
+    discard initDateTime(1, mJan, -35_000, 12, 00, 00, utc())
+    # with local tz
+    discard initDateTime(1, mJan, -35_000, 12, 00, 00)
+    discard initDateTime(1, mJan,  35_000, 12, 00, 00)
+    # with duration/timeinterval
+    let dt = initDateTime(1, mJan, -35_000, 12, 00, 00, utc()) +
+      initDuration(seconds = 1)
+    check dt.second == 1
+    let dt2 = dt + 35_001.years
+    check $dt2 == "0001-01-01T12:00:01Z"
+
+  block: # compare datetimes
+    var dt1 = now()
+    var dt2 = dt1
+    check dt1 == dt2
+    check dt1 <= dt2
+    dt2 = dt2 + 1.seconds
+    check dt1 < dt2
+
+  block: # adding/subtracting TimeInterval
+    # add/subtract TimeIntervals and Time/TimeInfo
+    let now = getTime().utc
+    let isSpecial = now.isLeapDay
+    check now + convert(Seconds, Nanoseconds, 1).nanoseconds == now + 1.seconds
+    check now + 1.weeks == now + 7.days
+    check now - 1.seconds == now - 3.seconds + 2.seconds
+    check now + 65.seconds == now + 1.minutes + 5.seconds
+    check now + 60.minutes == now + 1.hours
+    check now + 24.hours == now + 1.days
+    if not isSpecial:
+      check now + 13.months == now + 1.years + 1.months
+    check toUnix(fromUnix(0) + 2.seconds) == 2
+    check toUnix(fromUnix(0) - 2.seconds) == -2
+    var ti1 = now + 1.years
+    ti1 = ti1 - 1.years
+    if not isSpecial:
+      check ti1 == now
+    ti1 = ti1 + 1.days
+    if not isSpecial:
+      check ti1 == now + 1.days
+
+    # Bug with adding a day to a Time
+    let day = 24.hours
+    let tomorrow = now + day
+    check tomorrow - now == initDuration(days = 1)
+
+  # Disabled for JS because it fails due to precision errors
+  # (The JS target uses float64 for int64).
+  when not defined(js):
+    test "fromWinTime/toWinTime":
+      check 0.fromUnix.toWinTime.fromWinTime.toUnix == 0
+      check (-1).fromWinTime.nanosecond == convert(Seconds, Nanoseconds, 1) - 100
+      check (-1).fromWinTime.toWinTime == -1
+      # One nanosecond is discarded due to differences in time resolution
+      check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
+      check initTime(0, 101).toWinTime.fromWinTime.nanosecond == 100
+
+  block: # issue 7620
+    let layout = "M/d/yyyy' 'h:mm:ss' 'tt' 'z"
+    let t7620_am = parse("4/15/2017 12:01:02 AM +0", layout, utc())
+    check t7620_am.format(layout) == "4/15/2017 12:01:02 AM Z"
+    let t7620_pm = parse("4/15/2017 12:01:02 PM +0", layout, utc())
+    check t7620_pm.format(layout) == "4/15/2017 12:01:02 PM Z"
+
+  block: # format
+    var dt = initDateTime(1, mJan, -0001,
+                          17, 01, 02, 123_456_789,
+                          staticTz(hours = 1, minutes = 2, seconds = 3))
+    check dt.format("d") == "1"
+    check dt.format("dd") == "01"
+    check dt.format("ddd") == "Fri"
+    check dt.format("dddd") == "Friday"
+    check dt.format("h") == "5"
+    check dt.format("hh") == "05"
+    check dt.format("H") == "17"
+    check dt.format("HH") == "17"
+    check dt.format("m") == "1"
+    check dt.format("mm") == "01"
+    check dt.format("M") == "1"
+    check dt.format("MM") == "01"
+    check dt.format("MMM") == "Jan"
+    check dt.format("MMMM") == "January"
+    check dt.format("s") == "2"
+    check dt.format("ss") == "02"
+    check dt.format("t") == "P"
+    check dt.format("tt") == "PM"
+    check dt.format("yy") == "02"
+    check dt.format("yyyy") == "0002"
+    check dt.format("YYYY") == "2"
+    check dt.format("uuuu") == "-0001"
+    check dt.format("UUUU") == "-1"
+    check dt.format("z") == "-1"
+    check dt.format("zz") == "-01"
+    check dt.format("zzz") == "-01:02"
+    check dt.format("zzzz") == "-01:02:03"
+    check dt.format("g") == "BC"
+
+    check dt.format("fff") == "123"
+    check dt.format("ffffff") == "123456"
+    check dt.format("fffffffff") == "123456789"
+    dt.nanosecond = 1
+    check dt.format("fff") == "000"
+    check dt.format("ffffff") == "000000"
+    check dt.format("fffffffff") == "000000001"
+
+    dt.year = 12345
+    check dt.format("yyyy") == "+12345"
+    check dt.format("uuuu") == "+12345"
+    dt.year = -12345
+    check dt.format("yyyy") == "+12346"
+    check dt.format("uuuu") == "-12345"
+
+    expect ValueError:
+      discard initTimeFormat("'")
+
+    expect ValueError:
+      discard initTimeFormat("'foo")
+
+    expect ValueError:
+      discard initTimeFormat("foo'")
+
+    for tz in [
+        (staticTz(seconds = 0), "+0", "+00", "+00:00"), # UTC
+        (staticTz(seconds = -3600), "+1", "+01", "+01:00"), # CET
+        (staticTz(seconds = -39600), "+11", "+11", "+11:00"), # two digits
+        (staticTz(seconds = -1800), "+0", "+00", "+00:30"), # half an hour
+        (staticTz(seconds = 7200), "-2", "-02", "-02:00"), # positive
+        (staticTz(seconds = 38700), "-10", "-10", "-10:45")]: # positive with three quaters hour
+      let dt = initDateTime(1, mJan, 2000, 00, 00, 00, tz[0])
+      doAssert dt.format("z") == tz[1]
+      doAssert dt.format("zz") == tz[2]
+      doAssert dt.format("zzz") == tz[3]
+
+  block: # format locale
+    let loc = DateTimeLocale(
+      MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"],
+      MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"],
+      ddd: ["Red", "Ora.", "Yel.", "Gre.", "Blu.", "Vio.", "Whi."],
+      dddd: ["Red", "Orange", "Yellow", "Green", "Blue", "Violet", "White"],
+    )
+    var dt = initDateTime(5, mJan, 2010, 17, 01, 02, utc())
+    check dt.format("d", loc) == "5"
+    check dt.format("dd", loc) == "05"
+    check dt.format("ddd", loc) == "Ora."
+    check dt.format("dddd", loc) == "Orange"
+    check dt.format("M", loc) == "1"
+    check dt.format("MM", loc) == "01"
+    check dt.format("MMM", loc) == "Fir"
+    check dt.format("MMMM", loc) == "Firsty"
+
+  block: # parse
+    check $parse("20180101", "yyyyMMdd", utc()) == "2018-01-01T00:00:00Z"
+    parseTestExcp("+120180101", "yyyyMMdd")
+
+    check parse("1", "YYYY", utc()).year == 1
+    check parse("1 BC", "YYYY g", utc()).year == 0
+    check parse("0001 BC", "yyyy g", utc()).year == 0
+    check parse("+12345 BC", "yyyy g", utc()).year == -12344
+    check parse("1 AD", "YYYY g", utc()).year == 1
+    check parse("0001 AD", "yyyy g", utc()).year == 1
+    check parse("+12345 AD", "yyyy g", utc()).year == 12345
+
+    check parse("-1", "UUUU", utc()).year == -1
+    check parse("-0001", "uuuu", utc()).year == -1
+
+    discard parse("foobar", "'foobar'")
+    discard parse("foo'bar", "'foo''''bar'")
+    discard parse("'", "''")
+
+    parseTestExcp("2000 A", "yyyy g")
+
+  block: # parse locale
+    let loc = DateTimeLocale(
+      MMM: ["Fir","Sec","Thi","Fou","Fif","Six","Sev","Eig","Nin","Ten","Ele","Twe"],
+      MMMM: ["Firsty", "Secondy", "Thirdy", "Fourthy", "Fifthy", "Sixthy", "Seventhy", "Eighthy", "Ninthy", "Tenthy", "Eleventhy", "Twelfthy"],
+      ddd: ["Red", "Ora.", "Yel.", "Gre.", "Blu.", "Vio.", "Whi."],
+      dddd: ["Red", "Orange", "Yellow", "Green", "Blue", "Violet", "White"],
+    )
+    check $parse("02 Fir 2019", "dd MMM yyyy", utc(), loc) == "2019-01-02T00:00:00Z"
+    check $parse("Fourthy 6, 2017", "MMMM d, yyyy", utc(), loc) == "2017-04-06T00:00:00Z"
+
+  block: # timezoneConversion
+    var l = now()
+    let u = l.utc
+    l = u.local
+
+    check l.timezone == local()
+    check u.timezone == utc()
+
+  block: # getDayOfWeek
+    check getDayOfWeek(01, mJan, 0000) == dSat
+    check getDayOfWeek(01, mJan, -0023) == dSat
+    check getDayOfWeek(21, mSep, 1900) == dFri
+    check getDayOfWeek(01, mJan, 1970) == dThu
+    check getDayOfWeek(21, mSep, 1970) == dMon
+    check getDayOfWeek(01, mJan, 2000) == dSat
+    check getDayOfWeek(01, mJan, 2021) == dFri
+
+  block: # between - simple
+    let x = initDateTime(10, mJan, 2018, 13, 00, 00)
+    let y = initDateTime(11, mJan, 2018, 12, 00, 00)
+    doAssert x + between(x, y) == y
+
+  block: # between - dst start
+    usingTimezone("Europe/Stockholm"):
+      let x = initDateTime(25, mMar, 2018, 00, 00, 00)
+      let y = initDateTime(25, mMar, 2018, 04, 00, 00)
+      doAssert x + between(x, y) == y
+
+  block: # between - empty interval
+    let x = now()
+    let y = x
+    doAssert x + between(x, y) == y
+
+  block: # between - dst end
+    usingTimezone("Europe/Stockholm"):
+      let x = initDateTime(27, mOct, 2018, 02, 00, 00)
+      let y = initDateTime(28, mOct, 2018, 01, 00, 00)
+      doAssert x + between(x, y) == y
+
+  block: # between - long day
+    usingTimezone("Europe/Stockholm"):
+      # This day is 25 hours long in Europe/Stockholm
+      let x = initDateTime(28, mOct, 2018, 00, 30, 00)
+      let y = initDateTime(29, mOct, 2018, 00, 00, 00)
+      doAssert between(x, y) == 24.hours + 30.minutes
+      doAssert x + between(x, y) == y
+
+  block: # between - offset change edge case
+    # This test case is important because in this case
+    # `x + between(x.utc, y.utc) == y` is not true, which is very rare.
+    usingTimezone("America/Belem"):
+      let x = initDateTime(24, mOct, 1987, 00, 00, 00)
+      let y = initDateTime(26, mOct, 1987, 23, 00, 00)
+      doAssert x + between(x, y) == y
+      doAssert y + between(y, x) == x
+
+  block: # between - all units
+    let x = initDateTime(1, mJan, 2000, 00, 00, 00, utc())
+    let ti = initTimeInterval(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
+    let y = x + ti
+    doAssert between(x, y) == ti
+    doAssert between(y, x) == -ti
+
+  block: # between - monthday overflow
+      let x = initDateTime(31, mJan, 2001, 00, 00, 00, utc())
+      let y = initDateTime(1, mMar, 2001, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+  block: # between - misc
+    block:
+      let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc())
+      let y = initDateTime(01, mJan, 2001, 00, 00, 00, utc())
+      doAssert between(x, y) == 12.hours
+
+    block:
+      let x = initDateTime(31, mDec, 2000, 12, 00, 00, utc())
+      let y = initDateTime(02, mJan, 2001, 00, 00, 00, utc())
+      doAssert between(x, y) == 1.days + 12.hours
+
+    block:
+      let x = initDateTime(31, mDec, 1995, 00, 00, 00, utc())
+      let y = initDateTime(01, mFeb, 2000, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(01, mDec, 1995, 00, 00, 00, utc())
+      let y = initDateTime(31, mJan, 2000, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(31, mJan, 2000, 00, 00, 00, utc())
+      let y = initDateTime(01, mFeb, 2000, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(01, mJan, 1995, 12, 00, 00, utc())
+      let y = initDateTime(01, mFeb, 1995, 00, 00, 00, utc())
+      doAssert between(x, y) == 4.weeks + 2.days + 12.hours
+
+    block:
+      let x = initDateTime(31, mJan, 1995, 00, 00, 00, utc())
+      let y = initDateTime(10, mFeb, 1995, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+
+    block:
+      let x = initDateTime(31, mJan, 1995, 00, 00, 00, utc())
+      let y = initDateTime(10, mMar, 1995, 00, 00, 00, utc())
+      doAssert x + between(x, y) == y
+      doAssert between(x, y) == 1.months + 1.weeks
+
+  block: # default DateTime https://github.com/nim-lang/RFCs/issues/211
+    var num = 0
+    for ai in Month: num.inc
+    check num == 12
+
+    var a: DateTime
+    check a == DateTime.default
+    check not a.isInitialized
+    check $a == "Uninitialized DateTime"
+
+    expect(AssertionDefect): discard getDayOfWeek(a.monthday, a.month, a.year)
+    expect(AssertionDefect): discard a.toTime
+    expect(AssertionDefect): discard a.utc()
+    expect(AssertionDefect): discard a.local()
+    expect(AssertionDefect): discard a.inZone(utc())
+    expect(AssertionDefect): discard a + initDuration(seconds = 1)
+    expect(AssertionDefect): discard a + initTimeInterval(seconds = 1)
+    expect(AssertionDefect): discard a.isLeapDay
+    expect(AssertionDefect): discard a < a
+    expect(AssertionDefect): discard a <= a
+    expect(AssertionDefect): discard getDateStr(a)
+    expect(AssertionDefect): discard getClockStr(a)
+    expect(AssertionDefect): discard a.format "yyyy"
+    expect(AssertionDefect): discard a.format initTimeFormat("yyyy")
+    expect(AssertionDefect): discard between(a, a)
+
+  block: # inX procs
+    doAssert initDuration(seconds = 1).inSeconds == 1
+    doAssert initDuration(seconds = -1).inSeconds == -1
+    doAssert initDuration(seconds = -1, nanoseconds = 1).inSeconds == 0
+    doAssert initDuration(nanoseconds = -1).inSeconds == 0
+    doAssert initDuration(milliseconds = 500).inMilliseconds == 500
+    doAssert initDuration(milliseconds = -500).inMilliseconds == -500
+    doAssert initDuration(nanoseconds = -999999999).inMilliseconds == -999
+
+  block: # getIsoWeekAndYear
+    doAssert getIsoWeekAndYear(initDateTime(04, mNov, 2019, 00, 00, 00)) == (isoweek: 45.IsoWeekRange, isoyear: 2019.IsoYear)
+    doAssert initDateTime(dMon, 45, 2019.IsoYear, 00, 00, 00) == initDateTime(04, mNov, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(28, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear)
+    doAssert initDateTime(dSat, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(28, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(29, mDec, 2019, 00, 00, 00)) == (isoweek: 52.IsoWeekRange, isoyear: 2019.IsoYear)
+    doAssert initDateTime(dSun, 52, 2019.IsoYear, 00, 00, 00) == initDateTime(29, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(30, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(30, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2019, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dTue, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2019, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dWed, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2020, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 01, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(05, mApr, 2020, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 14, 2020.IsoYear, 00, 00, 00) == initDateTime(05, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(06, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(06, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(10, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dFri, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(10, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(12, mApr, 2020, 00, 00, 00)) == (isoweek: 15.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 15, 2020.IsoYear, 00, 00, 00) == initDateTime(12, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(13, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(13, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(15, mApr, 2020, 00, 00, 00)) == (isoweek: 16.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 16, 2020.IsoYear, 00, 00, 00) == initDateTime(16, mApr, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(17, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dFri, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(17, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(19, mJul, 2020, 00, 00, 00)) == (isoweek: 29.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 29, 2020.IsoYear, 00, 00, 00) == initDateTime(19, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(20, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dMon, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(20, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(23, mJul, 2020, 00, 00, 00)) == (isoweek: 30.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 30, 2020.IsoYear, 00, 00, 00) == initDateTime(23, mJul, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(31, mDec, 2020, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dThu, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(31, mDec, 2020, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dFri, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(01, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(02, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSat, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(02, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(03, mJan, 2021, 00, 00, 00)) == (isoweek: 53.IsoWeekRange, isoyear: 2020.IsoYear)
+    doAssert initDateTime(dSun, 53, 2020.IsoYear, 00, 00, 00) == initDateTime(03, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(04, mJan, 2021, 00, 00, 00)) == (isoweek: 01.IsoWeekRange, isoyear: 2021.IsoYear)
+    doAssert initDateTime(dMon, 01, 2021.IsoYear, 00, 00, 00) == initDateTime(04, mJan, 2021, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 00, 00, 00)) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear)
+    doAssert initDateTime(dMon, 05, 2021.IsoYear, 00, 00, 00) == initDateTime(01, mFeb, 2021, 00, 00, 00)
+
+    doAssert getIsoWeekAndYear(initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1))) == (isoweek: 05.IsoWeekRange, isoyear: 2021.IsoYear)
+    doAssert initDateTime(dMon, 05, 2021.IsoYear, 01, 02, 03, 400_000_000, staticTz(hours=1)) == initDateTime(01, mFeb, 2021, 01, 02, 03, 400_000_000, staticTz(hours=1))
+
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0001.IsoYear)
+    doAssert initDateTime(dSun, 13, 0001.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0001, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, +0000, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: 0000.IsoYear)
+    doAssert initDateTime(dSat, 13, 0000.IsoYear, 00, 00, 00) == initDateTime(01, mApr, 0000, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0001, 00, 00, 00)) == (isoweek: 13.IsoWeekRange, isoyear: (-0001).IsoYear)
+    doAssert initDateTime(dThu, 13, (-0001).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0001, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0002, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0002).IsoYear)
+    doAssert initDateTime(dWed, 14, (-0002).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0002, 00, 00, 00)
+    doAssert getIsoWeekAndYear(initDateTime(01, mApr, -0753, 00, 00, 00)) == (isoweek: 14.IsoWeekRange, isoyear: (-0753).IsoYear)
+    doAssert initDateTime(dMon, 14, (-0753).IsoYear, 00, 00, 00) == initDateTime(01, mApr, -0753, 00, 00, 00)
+
+  block: # getWeeksInIsoYear
+    doAssert getWeeksInIsoYear((-0014).IsoYear) == 52
+    doAssert getWeeksInIsoYear((-0013).IsoYear) == 53
+    doAssert getWeeksInIsoYear((-0012).IsoYear) == 52
+
+    doAssert getWeeksInIsoYear((-0009).IsoYear) == 52
+    doAssert getWeeksInIsoYear((-0008).IsoYear) == 53
+    doAssert getWeeksInIsoYear((-0007).IsoYear) == 52
+
+    doAssert getWeeksInIsoYear((-0003).IsoYear) == 52
+    doAssert getWeeksInIsoYear((-0002).IsoYear) == 53
+    doAssert getWeeksInIsoYear((-0001).IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(0003.IsoYear) == 52
+    doAssert getWeeksInIsoYear(0004.IsoYear) == 53
+    doAssert getWeeksInIsoYear(0005.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(1653.IsoYear) == 52
+    doAssert getWeeksInIsoYear(1654.IsoYear) == 53
+    doAssert getWeeksInIsoYear(1655.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(1997.IsoYear) == 52
+    doAssert getWeeksInIsoYear(1998.IsoYear) == 53
+    doAssert getWeeksInIsoYear(1999.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(2008.IsoYear) == 52
+    doAssert getWeeksInIsoYear(2009.IsoYear) == 53
+    doAssert getWeeksInIsoYear(2010.IsoYear) == 52
+
+    doAssert getWeeksInIsoYear(2014.IsoYear) == 52
+    doAssert getWeeksInIsoYear(2015.IsoYear) == 53
+    doAssert getWeeksInIsoYear(2016.IsoYear) == 52
+
+  block: # parse and generate iso years
+    # short calendar week with text
+    parseTest("KW 23 2023", "'KW' VV GGGG",
+      "2023-06-05T00:00:00Z", 155)
+    parseTest("KW 5 2023", "'KW' V GGGG",
+      "2023-01-30T00:00:00Z", 29)
+    parseTest("KW 05 23 Saturday", "'KW' V GG dddd",
+      "2023-02-04T00:00:00Z", 34)
+    parseTest("KW 53 20 Fri", "'KW' VV GG ddd",
+      "2021-01-01T00:00:00Z", 0)
+
+    parseTestExcp("KW 23", "'KW' VV") # no year
+    parseTestExcp("KW 23", "'KW' V") # no year
+    parseTestExcp("KW 23", "'KW' GG") # no week
+    parseTestExcp("KW 2023", "'KW' GGGG") # no week
+    
+    var dt = initDateTime(5, mJan, 2023, 0, 0, 0, utc())
+    check dt.format("V") == "1"
+    check dt.format("VV") == "01"
+    check dt.format("GG") == "23"
+    check dt.format("GGGG") == "2023"
+    check dt.format("dddd 'KW'V GGGG") == "Thursday KW1 2023"
+
+  block: # Can be used inside gcsafe proc
+    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
new file mode 100644
index 000000000..9bbc2e92c
--- /dev/null
+++ b/tests/stdlib/ttypeinfo.nim
@@ -0,0 +1,93 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/typeinfo
+import std/assertions
+
+type
+  TE = enum
+    blah, blah2
+
+  TestObj = object
+    test, asd: int
+    case test2: TE
+    of blah:
+      help: string
+    else:
+      nil
+
+
+var test = @[0,1,2,3,4]
+var x = toAny(test)
+var y = 78
+x[4] = toAny(y)
+doAssert x[2].getInt == 2
+
+var test2: tuple[name: string, s: int] = ("test", 56)
+var x2 = toAny(test2)
+var i = 0
+for n, a in fields(x2):
+  case i
+  of 0: doAssert n == "Field0" and $a.kind == "akString"
+  of 1: doAssert n == "Field1" and $a.kind == "akInt"
+  else: doAssert false
+  inc i
+
+var test3: TestObj
+test3.test = 42
+test3 = TestObj(test2: blah2)
+var x3 = toAny(test3)
+i = 0
+for n, a in fields(x3):
+  case i
+  of 0: doAssert n == "test" and $a.kind == "akInt"
+  of 1: doAssert n == "asd" and $a.kind == "akInt"
+  of 2: doAssert n == "test2" and $a.kind == "akEnum"
+  else: doAssert false
+  inc i
+
+var test4: ref string
+new(test4)
+test4[] = "test"
+var x4 = toAny(test4)
+doAssert($x4[].kind() == "akString")
+
+block:
+  # gimme a new scope dammit
+  var myArr: array[0..4, array[0..4, string]] = [
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
+    ["test", "1", "2", "3", "4"]]
+  var m = toAny(myArr)
+  for i in 0 .. m.len-1:
+    for j in 0 .. m[i].len-1:
+      doAssert getString(m[i][j]) == myArr[i][j]
+
+block:
+  type
+    Test = enum
+      Hello, he_llo
+
+  var x = hello
+  var y = x.toAny
+
+  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/ttypeinfo.nims b/tests/stdlib/ttypeinfo.nims
new file mode 100644
index 000000000..d31d0b26f
--- /dev/null
+++ b/tests/stdlib/ttypeinfo.nims
@@ -0,0 +1 @@
+--styleCheck:off
\ No newline at end of file
diff --git a/tests/stdlib/ttypetraits.nim b/tests/stdlib/ttypetraits.nim
new file mode 100644
index 000000000..6851b9220
--- /dev/null
+++ b/tests/stdlib/ttypetraits.nim
@@ -0,0 +1,94 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+# xxx merge with tests/metatype/ttypetraits.nim
+
+import std/typetraits
+import std/assertions
+
+macro testClosure(fn: typed, flag: static bool) =
+  if flag:
+    doAssert hasClosure(fn)
+  else:
+    doAssert not hasClosure(fn)
+
+block:
+  proc h1() =
+    echo 1
+
+  testClosure(h1, false)
+
+  proc h2() {.nimcall.} =
+    echo 2
+
+  testClosure(h2, false)
+
+
+block:
+  proc fn(): auto =
+    proc hello() {.nimcall.} =
+      echo 3
+    hello
+
+  let name = fn()
+  testClosure(name, false)
+
+block:
+  proc fn(): auto =
+    proc hello() =
+      echo 3
+    hello
+
+  let name = fn()
+  testClosure(name, false)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() {.closure.} =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+block:
+  proc fn(): auto =
+    var x = 0
+    proc hello() {.closure.} =
+      echo 3
+      inc x
+    hello
+
+  let name = fn()
+  testClosure(name, true)
+
+  let name2 = name
+  testClosure(name2, true)
+
+block:
+  iterator hello(): int =
+    yield 1
+
+  testClosure(hello, false)
+
+when not defined(js):
+  block:
+    iterator hello(): int {.closure.}=
+      yield 1
+
+    testClosure(hello, true)
diff --git a/tests/stdlib/tunicode.nim b/tests/stdlib/tunicode.nim
new file mode 100644
index 000000000..b9e68b15b
--- /dev/null
+++ b/tests/stdlib/tunicode.nim
@@ -0,0 +1,228 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/unicode
+import std/assertions
+
+proc asRune(s: static[string]): Rune =
+  ## Compile-time conversion proc for converting string literals to a Rune
+  ## value. Returns the first Rune of the specified string.
+  ##
+  ## Shortcuts code like ``"Ã¥".runeAt(0)`` to ``"Ã¥".asRune`` and returns a
+  ## compile-time constant.
+  if s.len == 0: Rune(0)
+  else: s.runeAt(0)
+
+let
+  someString = "öÑ"
+  someRunes = toRunes(someString)
+  compared = (someString == $someRunes)
+doAssert compared == true
+
+proc testReplacements(word: string): string =
+  case word
+  of "two":
+    return "2"
+  of "foo":
+    return "BAR"
+  of "βeta":
+    return "beta"
+  of "alpha":
+    return "αlpha"
+  else:
+    return "12345"
+
+doAssert translate("two not alpha foo βeta", testReplacements) == "2 12345 αlpha BAR beta"
+doAssert translate("  two not foo βeta  ", testReplacements) == "  2 12345 BAR beta  "
+
+doAssert title("foo bar") == "Foo Bar"
+doAssert title("αlpha βeta γamma") == "Αlpha Βeta Γamma"
+doAssert title("") == ""
+
+doAssert capitalize("βeta") == "Βeta"
+doAssert capitalize("foo") == "Foo"
+doAssert capitalize("") == ""
+
+doAssert swapCase("FooBar") == "fOObAR"
+doAssert swapCase(" ") == " "
+doAssert swapCase("Αlpha Βeta Γamma") == "αLPHA βETA γAMMA"
+doAssert swapCase("a✓B") == "A✓b"
+doAssert swapCase("ЈамогујеÑтиÑтаклоитоминештети") == "јÐМОГУЈЕСТИСТÐКЛОИТОМИÐЕШТЕТИ"
+doAssert swapCase("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "á½Î‘ΛΟÎΦΑΓΕῖÎΔΎÎΑΜΑΙΤΟῦΤΟΟὔΜΕΒΛΆΠΤΕΙ"
+doAssert swapCase("Ô¿Ö€Õ¶Õ¡Õ´Õ¡ÕºÕ¡Õ¯Õ«Õ¸Ö‚Õ¿Õ¥Ö‡Õ«Õ¶Õ®Õ«Õ¡Õ¶Õ°Õ¡Õ¶Õ£Õ«Õ½Õ¿Õ¹Õ¨Õ¶Õ¥Ö€") == "Õ¯ÕÕ†Ô±Õ„Ô±ÕŠÔ±Ô¿Ô»ÕˆÕ’ÕÔµÖ‡Ô»Õ†Ô¾Ô»Ô±Õ†Õ€Ô±Õ†Ô³Ô»ÕÕÕ‰Ô¸Õ†ÔµÕ"
+doAssert swapCase("") == ""
+
+doAssert isAlpha("r")
+doAssert isAlpha("α")
+doAssert isAlpha("Ï™")
+doAssert isAlpha("à®¶")
+doAssert isAlpha("网")
+doAssert(not isAlpha("$"))
+doAssert(not isAlpha(""))
+
+doAssert isAlpha("Î’eta")
+doAssert isAlpha("Args")
+doAssert isAlpha("ðŒ¼ðŒ°ðŒ²ðŒ²ðŒ»ðŒ´ðƒð„ðŒ°ðŒ½")
+doAssert isAlpha("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει")
+doAssert isAlpha("ЈамогујеÑтиÑтаклоитоминештети")
+doAssert isAlpha("Ô¿Ö€Õ¶Õ¡Õ´Õ¡ÕºÕ¡Õ¯Õ«Õ¸Ö‚Õ¿Õ¥Ö‡Õ«Õ¶Õ®Õ«Õ¡Õ¶Õ°Õ¡Õ¶Õ£Õ«Õ½Õ¿Õ¹Õ¨Õ¶Õ¥Ö€")
+doAssert isAlpha("编程语言")
+doAssert(not isAlpha("$Foo✓"))
+doAssert(not isAlpha("⠙⠕⠑⠎â â ž"))
+
+doAssert isSpace("\t")
+doAssert isSpace("\l")
+doAssert(not isSpace("Î’"))
+doAssert(not isSpace("Î’eta"))
+
+doAssert isSpace("\t\l \v\r\f")
+doAssert isSpace("       ")
+doAssert(not isSpace(""))
+doAssert(not isSpace("ΑΓc   \td"))
+
+doAssert(not isLower(' '.Rune))
+
+doAssert(not isUpper(' '.Rune))
+
+doAssert toUpper("Γ") == "Γ"
+doAssert toUpper("b") == "B"
+doAssert toUpper("α") == "Α"
+doAssert toUpper("✓") == "✓"
+doAssert toUpper("ϙ") == "Ϙ"
+doAssert toUpper("") == ""
+
+doAssert toUpper("ΑΒΓ") == "ΑΒΓ"
+doAssert toUpper("AAccβ") == "AACCΒ"
+doAssert toUpper("A✓$β") == "A✓$Β"
+
+doAssert toLower("a") == "a"
+doAssert toLower("γ") == "γ"
+doAssert toLower("Γ") == "γ"
+doAssert toLower("4") == "4"
+doAssert toLower("Ϙ") == "ϙ"
+doAssert toLower("") == ""
+
+doAssert toLower("abcdγ") == "abcdγ"
+doAssert toLower("abCDΓ") == "abcdγ"
+doAssert toLower("33aaΓ") == "33aaγ"
+
+doAssert reversed("Reverse this!") == "!siht esreveR"
+doAssert reversed("先秦兩漢") == "漢兩秦先"
+doAssert reversed("asâƒdfÌ…") == "fÌ…dsâƒa"
+doAssert reversed("a⃞b⃞c⃞") == "c⃞b⃞a⃞"
+doAssert reversed("ὕαλονϕαγεῖνδύναμαιτοῦτοοὔμεβλάπτει") == "ιετπάλβεμὔοοτῦοτιαμανύδνῖεγαϕνολαὕ"
+doAssert reversed("ЈамогујеÑтиÑтаклоитоминештети") == "итетшенимотиолкатÑитÑејугомаЈ"
+doAssert reversed("Ô¿Ö€Õ¶Õ¡Õ´Õ¡ÕºÕ¡Õ¯Õ«Õ¸Ö‚Õ¿Õ¥Ö‡Õ«Õ¶Õ®Õ«Õ¡Õ¶Õ°Õ¡Õ¶Õ£Õ«Õ½Õ¿Õ¹Õ¨Õ¶Õ¥Ö€") == "Ö€Õ¥Õ¶Õ¨Õ¹Õ¿Õ½Õ«Õ£Õ¶Õ¡Õ°Õ¶Õ¡Õ«Õ®Õ¶Õ«Ö‡Õ¥Õ¿Ö‚Õ¸Õ«Õ¯Õ¡ÕºÕ¡Õ´Õ¡Õ¶Ö€Ô¿"
+doAssert len(toRunes("asâƒdfÌ…")) == runeLen("asâƒdfÌ…")
+const test = "asâƒ"
+doAssert lastRune(test, test.len-1)[1] == 3
+doAssert graphemeLen("è", 0) == 2
+
+# test for rune positioning and runeSubStr()
+let s = "Hänsel  ««: 10,00€"
+
+var t = ""
+for c in s.utf8:
+  t.add c
+
+doAssert(s == t)
+
+doAssert(runeReverseOffset(s, 1) == (20, 18))
+doAssert(runeReverseOffset(s, 19) == (-1, 18))
+
+doAssert(runeStrAtPos(s, 0) == "H")
+doAssert(runeSubStr(s, 0, 1) == "H")
+doAssert(runeStrAtPos(s, 10) == ":")
+doAssert(runeSubStr(s, 10, 1) == ":")
+doAssert(runeStrAtPos(s, 9) == "«")
+doAssert(runeSubStr(s, 9, 1) == "«")
+doAssert(runeStrAtPos(s, 17) == "€")
+doAssert(runeSubStr(s, 17, 1) == "€")
+# echo runeStrAtPos(s, 18) # index error
+
+doAssert(runeSubStr(s, 0) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, -18) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, 10) == ": 10,00€")
+doAssert(runeSubStr(s, 18) == "")
+doAssert(runeSubStr(s, 0, 10) == "Hänsel  ««")
+
+doAssert(runeSubStr(s, 12) == "10,00€")
+doAssert(runeSubStr(s, -6) == "10,00€")
+
+doAssert(runeSubStr(s, 12, 5) == "10,00")
+doAssert(runeSubStr(s, 12, -1) == "10,00")
+doAssert(runeSubStr(s, -6, 5) == "10,00")
+doAssert(runeSubStr(s, -6, -1) == "10,00")
+
+doAssert(runeSubStr(s, 0, 100) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, -100, 100) == "Hänsel  ««: 10,00€")
+doAssert(runeSubStr(s, 0, -100) == "")
+doAssert(runeSubStr(s, 100, -100) == "")
+
+block splitTests:
+  let s = " this is an example  "
+  let s2 = ":this;is;an:example;;"
+  let s3 = ":this×is×an:example××"
+  doAssert s.split() == @["", "this", "is", "an", "example", "", ""]
+  doAssert s2.split(seps = [':'.Rune, ';'.Rune]) == @["", "this", "is", "an",
+      "example", "", ""]
+  doAssert s3.split(seps = [':'.Rune, "×".asRune]) == @["", "this", "is",
+      "an", "example", "", ""]
+  doAssert s.split(maxsplit = 4) == @["", "this", "is", "an", "example  "]
+  doAssert s.split(' '.Rune, maxsplit = 1) == @["", "this is an example  "]
+  doAssert s3.split("×".runeAt(0)) == @[":this", "is", "an:example", "", ""]
+
+block stripTests:
+  doAssert(strip("") == "")
+  doAssert(strip(" ") == "")
+  doAssert(strip("y") == "y")
+  doAssert(strip("  foofoofoo  ") == "foofoofoo")
+  doAssert(strip("sfoofoofoos", runes = ['s'.Rune]) == "foofoofoo")
+
+  block:
+    let stripTestRunes = ['b'.Rune, 'a'.Rune, 'r'.Rune]
+    doAssert(strip("barfoofoofoobar", runes = stripTestRunes) == "foofoofoo")
+  doAssert(strip("sfoofoofoos", leading = false, runes = ['s'.Rune]) == "sfoofoofoo")
+  doAssert(strip("sfoofoofoos", trailing = false, runes = ['s'.Rune]) == "foofoofoos")
+
+  block:
+    let stripTestRunes = ["«".asRune, "»".asRune]
+    doAssert(strip("«TEXT»", runes = stripTestRunes) == "TEXT")
+  doAssert(strip("copyright©", leading = false, runes = ["©".asRune]) == "copyright")
+  doAssert(strip("¿Question?", trailing = false, runes = ["¿".asRune]) == "Question?")
+  doAssert(strip("×text×", leading = false, runes = ["×".asRune]) == "×text")
+  doAssert(strip("×text×", trailing = false, runes = ["×".asRune]) == "text×")
+
+block repeatTests:
+  doAssert repeat('c'.Rune, 5) == "ccccc"
+  doAssert repeat("×".asRune, 5) == "×××××"
+
+block alignTests:
+  doAssert align("abc", 4) == " abc"
+  doAssert align("a", 0) == "a"
+  doAssert align("1232", 6) == "  1232"
+  doAssert align("1232", 6, '#'.Rune) == "##1232"
+  doAssert align("1232", 6, "×".asRune) == "××1232"
+  doAssert alignLeft("abc", 4) == "abc "
+  doAssert alignLeft("a", 0) == "a"
+  doAssert alignLeft("1232", 6) == "1232  "
+  doAssert alignLeft("1232", 6, '#'.Rune) == "1232##"
+  doAssert alignLeft("1232", 6, "×".asRune) == "1232××"
+
+block differentSizes:
+  # upper and lower variants have different number of bytes
+  doAssert toLower("AẞC") == "aßc"
+  doAssert toLower("ȺẞCD") == "ⱥßcd"
+  doAssert toUpper("ⱥbc") == "ȺBC"
+  doAssert toUpper("rsⱦuv") == "RSȾUV"
+  doAssert swapCase("ⱥbCd") == "ȺBcD"
+  doAssert swapCase("XyꟆaB") == "xYᶎAb"
+  doAssert swapCase("aáµ¹cᲈd") == "Aê½CꙊD"
+
+block: # bug #17768
+  let s1 = "abcdef"
+  let s2 = "abcdéf"
+
+  doAssert s1.runeSubStr(0, -1) == "abcde"
+  doAssert s2.runeSubStr(0, -1) == "abcdé"
diff --git a/tests/stdlib/tunidecode.nim b/tests/stdlib/tunidecode.nim
new file mode 100644
index 000000000..653016ea9
--- /dev/null
+++ b/tests/stdlib/tunidecode.nim
@@ -0,0 +1,13 @@
+discard """
+  cmd: "nim $target --hints:on -d:embedUnidecodeTable $options $file"
+"""
+
+import unidecode
+
+import std/unidecode # #14112
+import std/assertions
+
+loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
+
+doAssert unidecode("北京") == "Bei Jing "
+doAssert unidecode("Äußerst") == "Ausserst"
diff --git a/tests/stdlib/tunittest.nim b/tests/stdlib/tunittest.nim
new file mode 100644
index 000000000..0442c7863
--- /dev/null
+++ b/tests/stdlib/tunittest.nim
@@ -0,0 +1,194 @@
+discard """
+  output: '''
+
+[Suite] suite with only teardown
+
+[Suite] suite with only setup
+
+[Suite] suite with none
+
+[Suite] suite with both
+
+[Suite] bug #4494
+
+[Suite] bug #5571
+
+[Suite] bug #5784
+
+[Suite] test suite
+
+[Suite] test name filtering
+'''
+matrix: "--mm:refc; --mm:orc"
+targets: "c js"
+"""
+
+import std/[unittest, sequtils, assertions]
+from std/unittest {.all.} import matchFilter
+
+proc doThings(spuds: var int): int =
+  spuds = 24
+  return 99
+test "#964":
+  var spuds = 0
+  check doThings(spuds) == 99
+  check spuds == 24
+
+
+from std/strutils import toUpperAscii
+test "#1384":
+  check(@["hello", "world"].map(toUpperAscii) == @["HELLO", "WORLD"])
+
+
+import std/options
+test "unittest typedescs":
+  check(none(int) == none(int))
+  check(none(int) != some(1))
+
+
+test "unittest multiple requires":
+  require(true)
+  require(true)
+
+
+import std/random
+from std/strutils import parseInt
+proc defectiveRobot() =
+  case rand(1..4)
+  of 1: raise newException(OSError, "CANNOT COMPUTE!")
+  of 2: discard parseInt("Hello World!")
+  of 3: raise newException(IOError, "I can't do that Dave.")
+  else: doAssert 2 + 2 == 5
+test "unittest expect":
+  expect IOError, OSError, ValueError, AssertionDefect:
+    defectiveRobot()
+
+var
+  a = 1
+  b = -1
+  c = 1
+
+#unittests are sequential right now
+suite "suite with only teardown":
+  teardown:
+    b = 2
+
+  test "unittest with only teardown 1":
+    check a == c
+
+  test "unittest with only teardown 2":
+    check b > a
+
+suite "suite with only setup":
+  setup:
+    var testVar {.used.} = "from setup"
+
+  test "unittest with only setup 1":
+    check testVar == "from setup"
+    check b > a
+    b = -1
+
+  test "unittest with only setup 2":
+    check b < a
+
+suite "suite with none":
+  test "unittest with none":
+    check b < a
+
+suite "suite with both":
+  setup:
+    a = -2
+
+  teardown:
+    c = 2
+
+  test "unittest with both 1":
+    check b > a
+
+  test "unittest with both 2":
+    check c == 2
+
+suite "bug #4494":
+    test "Uniqueness check":
+      var tags = @[1, 2, 3, 4, 5]
+      check:
+        allIt(0..3, tags[it] != tags[it + 1])
+
+suite "bug #5571":
+  test "can define gcsafe procs within tests":
+    proc doTest {.gcsafe.} =
+      let line = "a"
+      check: line == "a"
+    doTest()
+
+suite "bug #5784":
+  test "`or` should short circuit":
+    type Obj = ref object
+      field: int
+    var obj: Obj
+    check obj.isNil or obj.field == 0
+
+type
+    SomeType = object
+        value: int
+        children: seq[SomeType]
+
+# bug #5252
+
+proc `==`(a, b: SomeType): bool =
+    return a.value == b.value
+
+suite "test suite":
+    test "test":
+        let a = SomeType(value: 10)
+        let b = SomeType(value: 10)
+
+        check(a == b)
+
+suite "test name filtering":
+  test "test name":
+    check matchFilter("suite1", "foo", "")
+    check matchFilter("suite1", "foo", "foo")
+    check matchFilter("suite1", "foo", "::")
+    check matchFilter("suite1", "foo", "*")
+    check matchFilter("suite1", "foo", "::foo")
+    check matchFilter("suite1", "::foo", "::foo")
+
+  test "test name - glob":
+    check matchFilter("suite1", "foo", "f*")
+    check matchFilter("suite1", "foo", "*oo")
+    check matchFilter("suite1", "12345", "12*345")
+    check matchFilter("suite1", "q*wefoo", "q*wefoo")
+    check false == matchFilter("suite1", "foo", "::x")
+    check false == matchFilter("suite1", "foo", "::x*")
+    check false == matchFilter("suite1", "foo", "::*x")
+    #  overlap
+    check false == matchFilter("suite1", "12345", "123*345")
+    check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f")
+
+  test "suite name":
+    check matchFilter("suite1", "foo", "suite1::")
+    check false == matchFilter("suite1", "foo", "suite2::")
+    check matchFilter("suite1", "qwe::foo", "qwe::foo")
+    check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo")
+
+  test "suite name - glob":
+    check matchFilter("suite1", "foo", "::*")
+    check matchFilter("suite1", "foo", "*::*")
+    check matchFilter("suite1", "foo", "*::foo")
+    check false == matchFilter("suite1", "foo", "*ite2::")
+    check matchFilter("suite1", "q**we::foo", "q**we::foo")
+    check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e")
+
+
+block:
+  type MyFoo = object
+  var obj = MyFoo()
+  let check = 1
+  check(obj == obj)
+
+block:
+  let check = 123
+  var a = 1
+  var b = 1
+  check(a == b)
diff --git a/tests/stdlib/tunittest_error.nim b/tests/stdlib/tunittest_error.nim
new file mode 100644
index 000000000..7f05ec2a9
--- /dev/null
+++ b/tests/stdlib/tunittest_error.nim
@@ -0,0 +1,22 @@
+discard """
+  exitcode: 1
+  outputsub: "failed: 1 == 3"
+  matrix: "-d:case1; -d:case2"
+  targets: "c js"
+  joinable: false
+"""
+
+when defined case1:
+  import unittest
+  suite "Test":
+    test "test require":
+      check 1==2
+      check 1==3
+
+when defined case2:
+  import unittest
+  suite "Test":
+    test "test require":
+      require 1 == 3
+      if true:
+        quit 0 # intentional
diff --git a/tests/stdlib/tunittestexceptiontype.nim b/tests/stdlib/tunittestexceptiontype.nim
new file mode 100644
index 000000000..e05a25409
--- /dev/null
+++ b/tests/stdlib/tunittestexceptiontype.nim
@@ -0,0 +1,10 @@
+discard """
+  exitcode: 1
+  outputsub: '''exception type is [ValueError]'''
+"""
+
+import unittest
+
+suite "exception from test":
+  test "show exception type":
+    raise newException(ValueError, "exception type is")
diff --git a/tests/stdlib/tunittestpass.nim b/tests/stdlib/tunittestpass.nim
new file mode 100644
index 000000000..d8de277b7
--- /dev/null
+++ b/tests/stdlib/tunittestpass.nim
@@ -0,0 +1,20 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c js"
+"""
+
+
+import unittest
+
+block:
+  check (type(1.0)) is float
+  check type(1.0) is float
+  check (typeof(1)) isnot float
+  check typeof(1) isnot float
+
+  check 1.0 is float
+  check 1 isnot float
+
+  type T = type(0.1)
+  check T is float
+  check T isnot int
diff --git a/tests/stdlib/tunittesttemplate.nim b/tests/stdlib/tunittesttemplate.nim
new file mode 100644
index 000000000..c29e0de01
--- /dev/null
+++ b/tests/stdlib/tunittesttemplate.nim
@@ -0,0 +1,25 @@
+discard """
+  exitcode: 1
+  outputsub: '''
+    tunittesttemplate.nim(20, 12): Check failed: a.b == 2
+    a.b was 0
+  [FAILED] 1
+'''
+"""
+
+
+
+# bug #6736
+import std/unittest
+
+type
+  A = object
+    b: int
+
+template t: untyped =
+  check(a.b == 2)
+
+suite "1":
+  test "1":
+    var a = A(b: 0)
+    t()
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/turi.nim b/tests/stdlib/turi.nim
new file mode 100644
index 000000000..9c717c5b1
--- /dev/null
+++ b/tests/stdlib/turi.nim
@@ -0,0 +1,323 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets:  "c js"
+"""
+
+import std/uri
+from std/uri {.all.} as uri2 import removeDotSegments
+from std/sequtils import toSeq
+import std/assertions
+
+template main() =
+  block: # encodeUrl, decodeUrl
+    const test1 = "abc\L+def xyz"
+    doAssert encodeUrl(test1) == "abc%0A%2Bdef+xyz"
+    doAssert decodeUrl(encodeUrl(test1)) == test1
+    doAssert encodeUrl(test1, false) == "abc%0A%2Bdef%20xyz"
+    doAssert decodeUrl(encodeUrl(test1, false), false) == test1
+    doAssert decodeUrl(encodeUrl(test1)) == test1
+
+  block: # removeDotSegments
+    doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz"
+    doAssert removeDotSegments("") == "" # empty test
+    doAssert removeDotSegments(".") == "." # trailing period
+    doAssert removeDotSegments("a1/a2/../a3/a4/a5/./a6/a7/././") == "a1/a3/a4/a5/a6/a7/"
+    doAssert removeDotSegments("https://a1/a2/../a3/a4/a5/./a6/a7/././") == "https://a1/a3/a4/a5/a6/a7/"
+    doAssert removeDotSegments("http://a1/a2") == "http://a1/a2"
+    doAssert removeDotSegments("http://www.ai.") == "http://www.ai."
+    when false: # xxx these cases are buggy
+      # this should work, refs https://webmasters.stackexchange.com/questions/73934/how-can-urls-have-a-dot-at-the-end-e-g-www-bla-de
+      doAssert removeDotSegments("http://www.ai./") == "http://www.ai./" # fails
+      echo removeDotSegments("http://www.ai./")  # http://www.ai/
+      echo removeDotSegments("a/b.../c") # b.c
+      echo removeDotSegments("a/b../c") # bc
+      echo removeDotSegments("a/.../c") # .c
+      echo removeDotSegments("a//../b") # a/b
+      echo removeDotSegments("a/b/c//") # a/b/c//
+
+  block: # parseUri
+    block:
+      let org = "udp://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080"
+      let url = parseUri(org)
+      doAssert url.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true
+      let newUrl = parseUri($url)
+      doAssert newUrl.hostname == "2001:0db8:85a3:0000:0000:8a2e:0370:7334" # true
+
+    block:
+      let str = "http://localhost"
+      let test = parseUri(str)
+      doAssert test.path == ""
+
+    block:
+      let str = "http://localhost/"
+      let test = parseUri(str)
+      doAssert test.path == "/"
+
+    block:
+      let str = "http://localhost:8080/test"
+      let test = parseUri(str)
+      doAssert test.scheme == "http"
+      doAssert test.port == "8080"
+      doAssert test.path == "/test"
+      doAssert test.hostname == "localhost"
+      doAssert($test == str)
+
+    block:
+      let str = "foo://username:password@example.com:8042/over/there" &
+                "/index.dtb?type=animal&name=narwhal#nose"
+      let test = parseUri(str)
+      doAssert test.scheme == "foo"
+      doAssert test.username == "username"
+      doAssert test.password == "password"
+      doAssert test.hostname == "example.com"
+      doAssert test.port == "8042"
+      doAssert test.path == "/over/there/index.dtb"
+      doAssert test.query == "type=animal&name=narwhal"
+      doAssert test.anchor == "nose"
+      doAssert($test == str)
+
+    block:
+      # IPv6 address
+      let str = "foo://[::1]:1234/bar?baz=true&qux#quux"
+      let uri = parseUri(str)
+      doAssert uri.scheme == "foo"
+      doAssert uri.hostname == "::1"
+      doAssert uri.port == "1234"
+      doAssert uri.path == "/bar"
+      doAssert uri.query == "baz=true&qux"
+      doAssert uri.anchor == "quux"
+
+    block:
+      let str = "urn:example:animal:ferret:nose"
+      let test = parseUri(str)
+      doAssert test.scheme == "urn"
+      doAssert test.path == "example:animal:ferret:nose"
+      doAssert($test == str)
+
+    block:
+      let str = "mailto:username@example.com?subject=Topic"
+      let test = parseUri(str)
+      doAssert test.scheme == "mailto"
+      doAssert test.username == "username"
+      doAssert test.hostname == "example.com"
+      doAssert test.query == "subject=Topic"
+      doAssert($test == str)
+
+    block:
+      let str = "magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+      let test = parseUri(str)
+      doAssert test.scheme == "magnet"
+      doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+      doAssert($test == str)
+
+    block:
+      let str = "/test/foo/bar?q=2#asdf"
+      let test = parseUri(str)
+      doAssert test.scheme == ""
+      doAssert test.path == "/test/foo/bar"
+      doAssert test.query == "q=2"
+      doAssert test.anchor == "asdf"
+      doAssert($test == str)
+
+    block:
+      let str = "test/no/slash"
+      let test = parseUri(str)
+      doAssert test.path == "test/no/slash"
+      doAssert($test == str)
+
+    block:
+      let str = "//git@github.com:dom96/packages"
+      let test = parseUri(str)
+      doAssert test.scheme == ""
+      doAssert test.username == "git"
+      doAssert test.hostname == "github.com"
+      doAssert test.port == "dom96"
+      doAssert test.path == "/packages"
+
+    block:
+      let str = "file:///foo/bar/baz.txt"
+      let test = parseUri(str)
+      doAssert test.scheme == "file"
+      doAssert test.username == ""
+      doAssert test.hostname == ""
+      doAssert test.port == ""
+      doAssert test.path == "/foo/bar/baz.txt"
+
+  block: # combine
+    block:
+      let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz"))
+      doAssert concat.path == "/foo/bar/baz"
+      doAssert concat.hostname == "google.com"
+      doAssert concat.scheme == "http"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz"))
+      doAssert concat.path == "/baz"
+      doAssert concat.hostname == "google.com"
+      doAssert concat.scheme == "http"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+      doAssert concat.path == "/foo/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar"))
+      doAssert concat.path == "/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+      doAssert concat.path == "/foo/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar"))
+      doAssert concat.path == "/foo/test/bar"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"))
+      doAssert concat.path == "/foo/test/bar/"
+
+    block:
+      let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"),
+                           parseUri("baz"))
+      doAssert concat.path == "/foo/test/bar/baz"
+
+  block: # `/`
+    block:
+      let test = parseUri("http://example.com/foo") / "bar/asd"
+      doAssert test.path == "/foo/bar/asd"
+
+    block:
+      let test = parseUri("http://example.com/foo/") / "/bar/asd"
+      doAssert test.path == "/foo/bar/asd"
+
+  block: # bug #3207
+    doAssert parseUri("http://qq/1").combine(parseUri("https://qqq")).`$` == "https://qqq"
+
+  block: # bug #4959
+    let foo = parseUri("http://example.com") / "/baz"
+    doAssert foo.path == "/baz"
+
+  block: # bug found on stream 13/10/17
+    let foo = parseUri("http://localhost:9515") / "status"
+    doAssert $foo == "http://localhost:9515/status"
+
+  block: # bug #6649 #6652
+    var foo = parseUri("http://example.com")
+    foo.hostname = "example.com"
+    foo.path = "baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com/"
+    foo.path = "baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com"
+    foo.path = "/baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com/"
+    foo.path = "/baz"
+    doAssert $foo == "http://example.com/baz"
+
+    foo.hostname = "example.com/"
+    foo.port = "8000"
+    foo.path = "baz"
+    doAssert $foo == "http://example.com:8000/baz"
+
+    foo = parseUri("file:/dir/file")
+    foo.path = "relative"
+    doAssert $foo == "file:relative"
+
+  block: # isAbsolute tests
+    doAssert "www.google.com".parseUri().isAbsolute() == false
+    doAssert "http://www.google.com".parseUri().isAbsolute() == true
+    doAssert "file:/dir/file".parseUri().isAbsolute() == true
+    doAssert "file://localhost/dir/file".parseUri().isAbsolute() == true
+    doAssert "urn:ISSN:1535-3613".parseUri().isAbsolute() == true
+
+    # path-relative URL *relative
+    doAssert "about".parseUri().isAbsolute == false
+    doAssert "about/staff.html".parseUri().isAbsolute == false
+    doAssert "about/staff.html?".parseUri().isAbsolute == false
+    doAssert "about/staff.html?parameters".parseUri().isAbsolute == false
+
+    # absolute-path-relative URL *relative
+    doAssert "/".parseUri().isAbsolute == false
+    doAssert "/about".parseUri().isAbsolute == false
+    doAssert "/about/staff.html".parseUri().isAbsolute == false
+    doAssert "/about/staff.html?".parseUri().isAbsolute == false
+    doAssert "/about/staff.html?parameters".parseUri().isAbsolute == false
+
+    # scheme-relative URL *relative
+    doAssert "//username:password@example.com:8888".parseUri().isAbsolute == false
+    doAssert "//username@example.com".parseUri().isAbsolute == false
+    doAssert "//example.com".parseUri().isAbsolute == false
+    doAssert "//example.com/".parseUri().isAbsolute == false
+    doAssert "//example.com/about".parseUri().isAbsolute == false
+    doAssert "//example.com/about/staff.html".parseUri().isAbsolute == false
+    doAssert "//example.com/about/staff.html?".parseUri().isAbsolute == false
+    doAssert "//example.com/about/staff.html?parameters".parseUri().isAbsolute == false
+
+    # absolute URL *absolute
+    doAssert "https://username:password@example.com:8888".parseUri().isAbsolute == true
+    doAssert "https://username@example.com".parseUri().isAbsolute == true
+    doAssert "https://example.com".parseUri().isAbsolute == true
+    doAssert "https://example.com/".parseUri().isAbsolute == true
+    doAssert "https://example.com/about".parseUri().isAbsolute == true
+    doAssert "https://example.com/about/staff.html".parseUri().isAbsolute == true
+    doAssert "https://example.com/about/staff.html?".parseUri().isAbsolute == true
+    doAssert "https://example.com/about/staff.html?parameters".parseUri().isAbsolute == true
+
+  block: # encodeQuery tests
+    doAssert encodeQuery({:}) == ""
+    doAssert encodeQuery({"foo": "bar"}) == "foo=bar"
+    doAssert encodeQuery({"foo": "bar & baz"}) == "foo=bar+%26+baz"
+    doAssert encodeQuery({"foo": "bar & baz"}, usePlus = false) == "foo=bar%20%26%20baz"
+    doAssert encodeQuery({"foo": ""}) == "foo"
+    doAssert encodeQuery({"foo": ""}, omitEq = false) == "foo="
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}) == "a=1&b&c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, sep = ';') == "a=1;b;c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false) == "a=1&b=&c=3"
+    doAssert encodeQuery({"a": "1", "b": "", "c": "3"}, omitEq = false, sep = ';') == "a=1;b=;c=3"
+
+  block: # `?`
+    block:
+      var foo = parseUri("http://example.com") / "foo" ? {"bar": "1", "baz": "qux"}
+      var foo1 = parseUri("http://example.com/foo?bar=1&baz=qux")
+      doAssert foo == foo1
+    block:
+      var foo = parseUri("http://example.com") / "foo" ? {"do": "do", "bar": ""}
+      var foo1 = parseUri("http://example.com/foo?do=do&bar")
+      doAssert foo == foo1
+
+  block: # getDataUri, dataUriBase64
+    doAssert getDataUri("", "text/plain") == "data:text/plain;charset=utf-8;base64,"
+    doAssert getDataUri(" ", "text/plain") == "data:text/plain;charset=utf-8;base64,IA=="
+    doAssert getDataUri("c\xf7>", "text/plain") == "data:text/plain;charset=utf-8;base64,Y/c+"
+    doAssert getDataUri("Hello World", "text/plain") == "data:text/plain;charset=utf-8;base64,SGVsbG8gV29ybGQ="
+    doAssert getDataUri("leasure.", "text/plain") == "data:text/plain;charset=utf-8;base64,bGVhc3VyZS4="
+    doAssert getDataUri("""!@#$%^&*()_+""", "text/plain") == "data:text/plain;charset=utf-8;base64,IUAjJCVeJiooKV8r"
+    doAssert(getDataUri("the quick brown dog jumps over the lazy fox", "text/plain") ==
+      "data:text/plain;charset=utf-8;base64,dGhlIHF1aWNrIGJyb3duIGRvZyBqdW1wcyBvdmVyIHRoZSBsYXp5IGZveA==")
+    doAssert(getDataUri("The present is theirs\n      The future, for which I really worked, is mine.", "text/plain") ==
+      "data:text/plain;charset=utf-8;base64,VGhlIHByZXNlbnQgaXMgdGhlaXJzCiAgICAgIFRoZSBmdXR1cmUsIGZvciB3aGljaCBJIHJlYWxseSB3b3JrZWQsIGlzIG1pbmUu")
+
+  block: # decodeQuery
+    doAssert toSeq(decodeQuery("a=1&b=0")) == @[("a", "1"), ("b", "0")]
+    doAssert toSeq(decodeQuery("a=1;b=0", sep = ';')) == @[("a", "1"), ("b", "0")]
+    doAssert toSeq(decodeQuery("a=1&b=2c=6")) == @[("a", "1"), ("b", "2c=6")]
+    doAssert toSeq(decodeQuery("a=1;b=2c=6", sep = ';')) == @[("a", "1"), ("b", "2c=6")]
+
+  block: # bug #17481
+    let u1 = parseUri("./")
+    let u2 = parseUri("./path")
+    let u3 = parseUri("a/path")
+    doAssert u1.scheme.len == 0
+    doAssert u1.path == "./"
+    doAssert u2.scheme.len == 0
+    doAssert u2.path == "./path"
+    doAssert u3.scheme.len == 0
+    doAssert u3.path == "a/path"
+
+static: main()
+main()
diff --git a/tests/stdlib/tuserlocks.nim b/tests/stdlib/tuserlocks.nim
new file mode 100644
index 000000000..927077120
--- /dev/null
+++ b/tests/stdlib/tuserlocks.nim
@@ -0,0 +1,21 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/rlocks
+import std/assertions
+
+var r: RLock
+r.initRLock()
+doAssert r.tryAcquire()
+doAssert r.tryAcquire()
+r.release()
+r.release()
+
+block:
+  var x = 12
+  withRLock r:
+    inc x
+  doAssert x == 13
+
+r.deinitRLock()
diff --git a/tests/stdlib/tvarargs.nim b/tests/stdlib/tvarargs.nim
new file mode 100644
index 000000000..2edc26264
--- /dev/null
+++ b/tests/stdlib/tvarargs.nim
@@ -0,0 +1,18 @@
+discard """
+  targets: "c js"
+  matrix: "--mm:refc; --mm:orc"
+"""
+import std/assertions
+
+template main =
+  proc hello(x: varargs[string]): seq[string] =
+    var s: seq[string]
+    s.add x
+    s
+
+  doAssert hello() == @[]
+  doAssert hello("a1") == @["a1"]
+  doAssert hello("a1", "a2") == @["a1", "a2"]
+
+static: main()
+main()
diff --git a/tests/stdlib/tvarints.nim b/tests/stdlib/tvarints.nim
new file mode 100644
index 000000000..f9624ee5b
--- /dev/null
+++ b/tests/stdlib/tvarints.nim
@@ -0,0 +1,73 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/varints
+import std/assertions
+
+# xxx doesn't work with js: tvarints.nim(18, 14) `wrLen == rdLen`  [AssertionDefect]
+
+block:
+  var dest: array[50, byte]
+  var got: uint64
+
+  for test in [0xFFFF_FFFF_FFFFF_FFFFu64, 77u64, 0u64, 10_000_000u64, uint64(high(int64)),
+              uint64(high(int32)), uint64(high(int32)), uint64(high(int64))]:
+    let wrLen = writeVu64(dest, test)
+    let rdLen = readVu64(dest, got)
+    doAssert wrLen == rdLen
+    doAssert got == test
+
+  for test in 0u64..300u64:
+    let wrLen = writeVu64(dest, test)
+    let rdLen = readVu64(dest, got)
+    doAssert wrLen == rdLen
+    doAssert got == test
+
+  # check this also works for floats:
+  for test in [0.0, 0.1, 2.0, +Inf, NegInf]:
+    let t = cast[uint64](test)
+    let wrLenB = writeVu64(dest, t)
+    let rdLenB = readVu64(dest, got)
+    doAssert wrLenB == rdLenB
+    doAssert cast[float64](got) == test
+
+block:
+  var hugeIntArray: array[9, byte]
+  var readedInt: uint64
+
+  template chk(a) =
+    let b = cast[uint64](a)
+    doAssert writeVu64(hugeIntArray, b) == readVu64(hugeIntArray, readedInt)
+    doAssert readedInt == b
+
+  chk 0
+  chk uint64.high
+  chk int64.high
+  chk int32.high
+  chk int16.high
+  chk int16.high
+  chk int8.high
+  chk 0.0
+  chk -0.0
+  chk 0.1
+  chk Inf
+  chk NegInf
+  chk NaN
+  chk 3.1415926535897932384626433
+
+block:
+  template chk(a) =
+    let b = cast[uint64](a)
+    doAssert encodeZigzag(decodeZigzag(b)) == b
+  chk 0
+  chk uint32.high
+  chk int32.high
+  chk int16.high
+  chk int8.high
+  chk 0.0
+  chk 0.1
+  chk 0.9555555555555555555555501
+  chk Inf
+  chk 3.1415926535897932384626433
+  chk 2.71828182845904523536028747
diff --git a/tests/stdlib/tvmutils.nim b/tests/stdlib/tvmutils.nim
new file mode 100644
index 000000000..63804c136
--- /dev/null
+++ b/tests/stdlib/tvmutils.nim
@@ -0,0 +1,31 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  joinable: false
+  nimout: '''
+0
+1
+2
+tvmutils.nim(28, 13) [opcLdImmInt]     if i == 4:
+tvmutils.nim(28, 10) [opcEqInt]     if i == 4:
+tvmutils.nim(28, 10) [opcFJmp]     if i == 4:
+tvmutils.nim(28, 13) [opcLdImmInt]     if i == 4:
+tvmutils.nim(28, 10) [opcEqInt]     if i == 4:
+tvmutils.nim(28, 10) [opcFJmp]     if i == 4:
+tvmutils.nim(29, 7) [opcLdConst]       vmTrace(false)
+tvmutils.nim(29, 15) [opcLdImmInt]       vmTrace(false)
+tvmutils.nim(29, 14) [opcIndCall]       vmTrace(false)
+5
+6
+'''
+"""
+# line 20 (only showing a subset of nimout to avoid making the test rigid)
+import std/vmutils
+proc main() =
+  for i in 0..<7:
+    echo i
+    if i == 2:
+      vmTrace(true)
+    if i == 4:
+      vmTrace(false)
+
+static: main()
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/twchartoutf8.nim b/tests/stdlib/twchartoutf8.nim
new file mode 100644
index 000000000..e437177ac
--- /dev/null
+++ b/tests/stdlib/twchartoutf8.nim
@@ -0,0 +1,112 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''OK'''
+"""
+
+import std/[syncio, assertions]
+
+#assume WideCharToMultiByte always produce correct result
+#windows only
+
+when not defined(windows):
+  echo "OK"
+else:
+  import std/widestrs
+  {.push gcsafe.}
+
+  const CP_UTF8 = 65001'i32
+
+  type
+    LPBOOL = ptr int32
+    LPWCSTR = ptr uint16
+
+  proc WideCharToMultiByte*(CodePage: int32, dwFlags: int32,
+                            lpWideCharStr: LPWCSTR, cchWideChar: int32,
+                            lpMultiByteStr: cstring, cchMultiByte: int32,
+                            lpDefaultChar: cstring, lpUsedDefaultChar: LPBOOL): int32{.
+      stdcall, dynlib: "kernel32", importc: "WideCharToMultiByte".}
+
+  {.pop.}
+
+  proc convertToUTF8(wc: WideCString, wclen: int32): string =
+    let size = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
+      cstring(nil), 0'i32, cstring(nil), LPBOOL(nil))
+    result = newString(size)
+    let res = WideCharToMultiByte(CP_UTF8, 0'i32, cast[LPWCSTR](addr(wc[0])), wclen,
+      cstring(result), size, cstring(nil), LPBOOL(nil))
+    doAssert size == res
+
+  proc testCP(wc: WideCString, lo, hi: int) =
+    var x = 0
+    let chunk = 1024
+    for i in lo..hi:
+      wc[x] = cast[Utf16Char](i)
+      if (x >= chunk) or (i >= hi):
+        wc[x] = Utf16Char(0)
+        var a = convertToUTF8(wc, int32(x))
+        var b = wc $ chunk
+        doAssert a == b
+        x = 0
+      inc x
+
+  proc testCP2(wc: WideCString, lo, hi: int) =
+    doAssert((lo >= 0x10000) and (hi <= 0x10FFFF))
+    var x = 0
+    let chunk = 1024
+    for i in lo..hi:
+      let ch = i - 0x10000
+      let W1 = 0xD800 or (ch shr 10)
+      let W2 = 0xDC00 or (0x3FF and ch)
+      wc[x] = cast[Utf16Char](W1)
+      wc[x+1] = cast[Utf16Char](W2)
+      inc(x, 2)
+
+      if (x >= chunk) or (i >= hi):
+        wc[x] = Utf16Char(0)
+        var a = convertToUTF8(wc, int32(x))
+        var b = wc $ chunk
+        doAssert a == b
+        x = 0
+
+  #RFC-2781 "UTF-16, an encoding of ISO 10646"
+
+  var wc: WideCString = newWideCString(1024 * 2)
+
+  #U+0000 to U+D7FF
+  #skip the U+0000
+  wc.testCP(1, 0xD7FF)
+
+  #U+E000 to U+FFFF
+  wc.testCP(0xE000, 0xFFFF)
+
+  #U+10000 to U+10FFFF
+  wc.testCP2(0x10000, 0x10FFFF)
+
+  #invalid UTF-16
+  const
+    b = "\xEF\xBF\xBD"
+    c = "\xEF\xBF\xBF"
+
+  wc[0] = cast[Utf16Char](0xDC00)
+  wc[1] = Utf16Char(0)
+  var a = $wc
+  doAssert a == b
+
+  wc[0] = cast[Utf16Char](0xFFFF)
+  wc[1] = cast[Utf16Char](0xDC00)
+  wc[2] = Utf16Char(0)
+  a = $wc
+  doAssert a == c & b
+
+  wc[0] = cast[Utf16Char](0xD800)
+  wc[1] = Utf16Char(0)
+  a = $wc
+  doAssert a == b
+
+  wc[0] = cast[Utf16Char](0xD800)
+  wc[1] = cast[Utf16Char](0xFFFF)
+  wc[2] = Utf16Char(0)
+  a = $wc
+  doAssert a == b & c
+
+  echo "OK"
diff --git a/tests/stdlib/twith.nim b/tests/stdlib/twith.nim
new file mode 100644
index 000000000..ceadbe7bf
--- /dev/null
+++ b/tests/stdlib/twith.nim
@@ -0,0 +1,44 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/with
+import std/[assertions, formatfloat]
+
+type
+  Foo = object
+    col, pos: string
+    name: string
+
+proc setColor(f: var Foo; r, g, b: int) = f.col = $(r, g, b)
+proc setPosition(f: var Foo; x, y: float) = f.pos = $(x, y)
+
+var f: Foo
+with(f, setColor(2, 3, 4), setPosition(0.0, 1.0))
+doAssert f.col == "(2, 3, 4)"
+doAssert f.pos == "(0.0, 1.0)"
+
+f = Foo()
+with f:
+  col = $(2, 3, 4)
+  pos = $(0.0, 1.0)
+  _.name = "bar"
+doAssert f.col == "(2, 3, 4)"
+doAssert f.pos == "(0.0, 1.0)"
+doAssert f.name == "bar"
+
+type
+  Baz* = object
+    a*, b*: int
+  Bar* = object
+    x*: int
+    baz*: Baz
+
+var bar: Bar
+with bar:
+  x = 1
+  with baz:
+    a = 2
+
+doAssert bar.x == 1
+doAssert bar.baz.a == 2
diff --git a/tests/stdlib/twordwrap.nim b/tests/stdlib/twordwrap.nim
new file mode 100644
index 000000000..5d49477d3
--- /dev/null
+++ b/tests/stdlib/twordwrap.nim
@@ -0,0 +1,48 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/wordwrap
+import std/assertions
+
+when true:
+  let
+    inp = """ this is a long text --  muchlongerthan10chars and here
+                it goes"""
+    outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
+  doAssert wrapWords(inp, 10, false) == outp
+
+  let
+    longInp = """ThisIsOneVeryLongStringWhichWeWillSplitIntoEightSeparatePartsNow"""
+    longOutp = "ThisIsOn\neVeryLon\ngStringW\nhichWeWi\nllSplitI\nntoEight\nSeparate\nPartsNow"
+  doAssert wrapWords(longInp, 8, true) == longOutp
+
+# test we don't break Umlauts into invalid bytes:
+let fies = "äöüöäöüöäöüöäöüööäöüöäößßßßüöäößßßßßß"
+let fiesRes = "ä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nä\nö\nü\nö\nö\nä\nö\nü\nö\nä\nö\nß\nß\nß\nß\nü\nö\nä\nö\nß\nß\nß\nß\nß\nß"
+doAssert wrapWords(fies, 1, true) == fiesRes
+
+let longlongword = """abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüö
+äzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüüöäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiqfglwcßqfgxvlcwgtfhiaoen
+rsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocfqclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdrtnaetdr
+iaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψÏχκψÏτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψÏκγτφγτχκγτεκÏγτιχνκιωχσιλωσλωχξλξλξωχωχ
+ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνÏκψγκψφϵιηαααοε"""
+let longlongwordRes = """
+abc uitdaeröägfßhydüäpydqfü,träpydqgpmüdträpydföägpydörztdüöäfguiaeowäzjdtrüöäp
+psnrtuiydrözenrüöäpyfdqazpesnrtulocjtüöäzydgyqgfqfgprtnwjlcydkqgfüöezmäzydydqüü
+öäpdtrnvwfhgckdumböäpydfgtdgfhtdrntdrntydfogiayqfguiatrnydrntüöärtniaoeydfgaoeiq
+fglwcßqfgxvlcwgtfhiaoenrsüöäapmböäptdrniaoydfglckqfhouenrtsüöäptrniaoeyqfgulocf
+qclgwxßqflgcwßqfxglcwrniatrnmüböäpmöäbpümöäbpüöämpbaoestnriaesnrtdiaesrtdniaesdr
+tnaetdriaoenvlcyfglwckßqfgvwkßqgfvlwkßqfgvlwckßqvlwkgfUIαοιαοιαχολωχσωχνωκψÏχκψ
+ÏτιεαοσηζϵηζιοεννκεωνιαλωσωκνκψÏκγτφγτχκγτεκÏγτιχνκιωχσιλωσλωχξλξλξωχωχ
+ξχλωωχαοεοιαεοαεοιαεοαεοιαοεσναοεκνÏκψγκψφϵιηαααοε"""
+doAssert wrapWords(longlongword) == longlongwordRes
+
+# bug #14579
+const input60 = """
+This string is wrapped to 60 characters. If we call
+wrapwords on it it will be re-wrapped to 80 characters.
+"""
+const input60Res = """This string is wrapped to 60 characters. If we call wrapwords on it it will be
+re-wrapped to 80 characters."""
+doAssert wrapWords(input60) == input60Res
\ No newline at end of file
diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim
new file mode 100644
index 000000000..3da230b5e
--- /dev/null
+++ b/tests/stdlib/twrapnils.nim
@@ -0,0 +1,224 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/wrapnils
+from std/options import get, isSome
+import std/assertions
+
+proc checkNotZero(x: float): float =
+  doAssert x != 0
+  x
+
+proc main() =
+  var witness = 0
+  block:
+    type Bar = object
+      b1: int
+      b2: ptr string
+
+    type Foo = ref object
+      x1: float
+      x2: Foo
+      x3: string
+      x4: Bar
+      x5: seq[int]
+      x6: ptr Bar
+      x7: array[2, string]
+      x8: seq[int]
+      x9: ref Bar
+
+    type Goo = ref object
+      foo: Foo
+
+    proc fun(a: Bar): auto = a.b2
+
+    var a: Foo
+
+    var x6: ptr Bar
+    when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568
+    else:
+      x6 = create(Bar)
+      x6.b1 = 42
+    var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6)
+    var a3 = Foo(x1: 1.2, x3: "abc")
+    a3.x2 = a3
+
+    var goo = Goo(foo: a)
+
+    proc initFoo(x1: float): auto =
+      witness.inc
+      result = Foo(x1: x1)
+
+    doAssert ?.a.x2.x2.x1 == 0.0
+    doAssert ?.a3.x2.x2.x1 == 1.2
+    doAssert ?.a3.x2.x2.x3[1] == 'b'
+
+    doAssert ?.a3.x2.x2.x5.len == 0
+    doAssert a3.x2.x2.x3.len == 3
+
+    doAssert ?.a.x2.x2.x3[1] == default(char)
+    # here we only apply wrapnil around goo.foo, not goo (and assume goo is not nil)
+    doAssert ?.(goo.foo).x2.x2.x1 == 0.0
+
+    when nimvm: discard
+    else:
+      doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar
+
+    doAssert ?.a2.x1.checkNotZero == 1.0
+    doAssert a == nil
+    # shows that checkNotZero won't be called if a nil is found earlier in chain
+    doAssert ?.a.x1.checkNotZero == 0.0
+
+    when nimvm: discard
+    else:
+      # checks that a chain without nil but with an empty seq still raises
+      doAssertRaises(IndexDefect): discard ?.a2.x8[3]
+
+    # make sure no double evaluation bug
+    doAssert witness == 0
+    doAssert ?.initFoo(1.3).x1 == 1.3
+    doAssert witness == 1
+
+    # here, it's used twice, to deref `ref Bar` and then `ptr string`
+    doAssert ?.a.x9[].fun[] == ""
+
+    block: # `??.`
+      doAssert (??.a3.x2.x2.x3.len).get == 3
+      doAssert (??.a2.x4).isSome
+      doAssert not (??.a.x4).isSome
+
+  block:
+    type
+      A = object
+        b: B
+      B = object
+        c: C
+      C = object
+        d: D
+      D = ref object
+        e: E
+        e2: array[2, E]
+        e3: seq[E]
+        d3: D
+        i4: int
+      E = object
+        f: int
+        d2: D
+    proc identity[T](a: T): T = a
+    proc identity2[T](a: T, ignore: int): T = a
+    var a: A
+    doAssert ?.a.b.c.d.e.f == 0
+    doAssert ?.a.b.c.d.e.d2.d3[].d3.e.d2.e.f == 0
+    doAssert ?.a.b.c.d.d3[].e.f == 0
+    doAssert ?.a.b.c.d.e2[0].d2.e3[0].f == 0
+    doAssert ?.a == A.default
+    doAssert ?.a.b.c.d.e == E.default
+    doAssert ?.a.b.c.d.e.d2 == nil
+
+    doAssert ?.a.identity.b.c.identity2(12).d.d3.e.f == 0
+    doAssert ?.a.b.c.d.d3.e2[0].f == 0
+    a.b.c.d = D()
+    a.b.c.d.d3 = a.b.c.d
+    a.b.c.d.e2[0].f = 5
+    doAssert ?.a.b.c.d.d3.e2[0].f == 5
+
+    var d: D = nil
+    doAssert ?.d.identity.i4 == 0
+    doAssert ?.d.i4.identity == 0
+
+  block: # case objects
+    type
+      Kind = enum k0, k1, k2
+      V = object
+        case kind: Kind
+        of k0:
+          x0: int
+        of k1:
+          x1: int
+        of k2:
+          x2: int
+      A = object
+        v0: V
+
+    block:
+      var a = V(kind: k0, x0: 3)
+      doAssert ?.a.x0 == 3
+      doAssert ?.a.x1 == 0
+      a = V(kind: k1, x1: 5)
+      doAssert ?.a.x0 == 0
+      doAssert ?.a.x1 == 5
+
+    block:
+      var a = A(v0: V(kind: k0, x0: 10))
+      doAssert ?.a.v0.x0 == 10
+      doAssert ?.a.v0.x1 == 0
+      a.v0 = V(kind: k2, x2: 8)
+      doAssert ?.a.v0.x0 == 0
+      doAssert ?.a.v0.x1 == 0
+      doAssert ?.a.v0.x2 == 8
+
+  block: # `nnkCall`
+    type
+      A = object
+        a0: int
+        d: D
+      D = ref object
+        i4: int
+
+    proc identity[T](a: T): T = a
+    var d: D = nil
+    doAssert ?.d.i4.identity == 0
+    doAssert ?.identity(?.d.i4) == 0
+    doAssert ?.identity(d.i4) == 0
+    doAssert ?.identity(d) == nil
+    doAssert ?.identity(d[]) == default(typeof(d[]))
+    doAssert ?.identity(d[]).i4 == 0
+    var a: A
+    doAssert ?.identity(a) == default(A)
+    doAssert ?.identity(a.a0) == 0
+    doAssert ?.identity(a.d) == nil
+    doAssert ?.identity(a.d.i4) == 0
+
+  block: # lvalue semantic propagation
+    type
+      A = ref object
+        a0: A
+        a1: seq[A]
+        a2: int
+
+      B = object
+        b0: int
+        case cond: bool
+        of false: discard
+        of true:
+          b1: float
+
+    block:
+      var a: A
+      doAssert ?.a.a0.a1[0].a2.addr == nil
+      a = A(a2: 3)
+      doAssert ?.a.a0.a1[0].a2.addr == nil
+      a.a0 = a
+      a.a1 = @[a]
+      let p = ?.a.a0.a1[0].a2.addr
+      doAssert p != nil
+      p[] = 5
+      doAssert a.a2 == 5
+
+    block:
+      var b = B(cond: false, b0: 3)
+      let p = ?.b.b1.addr
+      doAssert p == nil
+      b = B(cond: true, b1: 4.5)
+      let p2 = ?.b.b1.addr
+      doAssert p2 != nil
+      p2[] = 4.6
+      doAssert b.b1 == 4.6
+      # useful pattern, impossible with Options
+      if (let p3 = ?.b.b1.addr; p3 != nil):
+        p3[] = 4.7
+      doAssert b.b1 == 4.7
+
+main()
+static: main()
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/txmltree.nim b/tests/stdlib/txmltree.nim
new file mode 100644
index 000000000..add12a3fc
--- /dev/null
+++ b/tests/stdlib/txmltree.nim
@@ -0,0 +1,120 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+"""
+
+import std/[xmltree, assertions, xmlparser]
+
+
+block:
+  var
+    x: XmlNode
+
+  x = <>a(href = "http://nim-lang.org", newText("Nim rules."))
+  doAssert $x == """<a href="http://nim-lang.org">Nim rules.</a>"""
+
+  x = <>outer(<>inner())
+  doAssert $x == """<outer>
+  <inner />
+</outer>"""
+
+  x = <>outer(<>middle(<>inner1(), <>inner2(), <>inner3(), <>inner4()))
+  doAssert $x == """<outer>
+  <middle>
+    <inner1 />
+    <inner2 />
+    <inner3 />
+    <inner4 />
+  </middle>
+</outer>"""
+
+  x = <>l0(<>l1(<>l2(<>l3(<>l4()))))
+  doAssert $x == """<l0>
+  <l1>
+    <l2>
+      <l3>
+        <l4 />
+      </l3>
+    </l2>
+  </l1>
+</l0>"""
+
+  x = <>l0(<>l1p1(), <>l1p2(), <>l1p3())
+  doAssert $x == """<l0>
+  <l1p1 />
+  <l1p2 />
+  <l1p3 />
+</l0>"""
+
+  x = <>l0(<>l1(<>l2p1(), <>l2p2()))
+  doAssert $x == """<l0>
+  <l1>
+    <l2p1 />
+    <l2p2 />
+  </l1>
+</l0>"""
+
+  x = <>l0(<>l1(<>l2_1(), <>l2_2(<>l3_1(), <>l3_2(), <>l3_3(<>l4_1(), <>l4_2(), <>l4_3())), <>l2_3(), <>l2_4()))
+  doAssert $x == """<l0>
+  <l1>
+    <l2_1 />
+    <l2_2>
+      <l3_1 />
+      <l3_2 />
+      <l3_3>
+        <l4_1 />
+        <l4_2 />
+        <l4_3 />
+      </l3_3>
+    </l2_2>
+    <l2_3 />
+    <l2_4 />
+  </l1>
+</l0>"""
+
+  let
+    innermost = newElement("innermost")
+    middle = newXmlTree("middle", [innermost])
+  innermost.add newText("innermost text")
+  x = newXmlTree("outer", [middle])
+  doAssert $x == """<outer>
+  <middle>
+    <innermost>innermost text</innermost>
+  </middle>
+</outer>"""
+
+  x = newElement("myTag")
+  x.add newText("my text")
+  x.add newElement("sonTag")
+  x.add newEntity("my entity")
+  doAssert $x == "<myTag>my text<sonTag />&my entity;</myTag>"
+
+block: # bug #21290
+  let x = newXmlTree("foo",[
+    newXmlTree("bar",[
+      newText("Hola"),
+      newXmlTree("qux",[
+        newXmlTree("plugh",[])
+      ])
+    ])
+  ])
+
+  let s = $x
+  doAssert $parseXml(s) == s
+  doAssert s == """<foo>
+  <bar>Hola<qux>    <plugh />  </qux></bar>
+</foo>"""
+
+block: #21541
+  let root = <>root()
+  root.add <>child(newText("hello"))
+  root.add <>more(newVerbatimText("hola"))
+  let s = $root
+  doAssert s == """<root>
+  <child>hello</child>
+  <more>hola</more>
+</root>"""
+
+  let temp = newVerbatimText("Hello!")
+  doAssert temp.text == "Hello!"
+  temp.text = "Hola!"
+  doAssert temp.text == "Hola!"
diff --git a/tests/stdlib/tyield.nim b/tests/stdlib/tyield.nim
new file mode 100644
index 000000000..f385ddd05
--- /dev/null
+++ b/tests/stdlib/tyield.nim
@@ -0,0 +1,258 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  targets: "c cpp js"
+"""
+
+import std/[sugar, algorithm]
+import std/assertions
+
+block:
+  var x = @[(6.0, 6, '6'),
+            (5.0, 5, '5'),
+            (4.0, 4, '4'),
+            (3.0, 3, '3'),
+            (2.0, 2, '2'),
+            (1.0, 1, '1')]
+
+  let y = x.reversed
+
+  block:
+    let res = collect:
+      for (f, i, c) in x:
+        (f, i, c)
+
+    doAssert res == x
+
+  iterator popAscending[T](q: var seq[T]): T =
+    while q.len > 0: yield q.pop
+
+  block:
+    var res = collect:
+      for f, i, c in popAscending(x):
+        (f, i, c)
+
+    doAssert res == y
+
+    let z = reversed(res)
+    let res2 = collect:
+      for (f, i, c) in popAscending(res):
+        (f, i, c)
+
+    doAssert res2 == z
+
+
+block:
+  var visits = 0
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    iterator foo(): (int, int) =
+      yield bar()
+
+    for a, b in foo():
+      doAssert a == b
+
+    doAssert visits == 1
+
+  block:
+    proc iterAux(a: seq[int], i: var int): (int, string) =
+      result = (a[i], $a[i])
+      inc i
+
+    iterator pairs(a: seq[int]): (int, string) =
+      var i = 0
+      while i < a.len:
+        yield iterAux(a, i)
+
+    var x = newSeq[int](10)
+    for i in 0 ..< x.len:
+      x[i] = i
+
+    let res = collect:
+      for k, v in x:
+        (k, v)
+
+    let expected = collect:
+      for i in 0 ..< x.len:
+        (i, $i)
+
+    doAssert res == expected
+
+  block:
+    proc bar(): (int, int, int) =
+      inc visits
+      (visits, visits, visits)
+
+    iterator foo(): (int, int, int) =
+      yield bar()
+
+    for a, b, c in foo():
+      doAssert a == b
+
+    doAssert visits == 2
+
+
+  block:
+
+    proc bar(): int =
+      inc visits
+      visits
+
+    proc car(): int =
+      inc visits
+      visits
+
+    iterator foo(): (int, int) =
+      yield (bar(), car())
+      yield (bar(), car())
+
+    for a, b in foo():
+      doAssert b == a + 1
+
+    doAssert visits == 6
+
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield (12, t2())
+      yield bar()
+
+    let res = collect:
+      for (a, b) in foo():
+        (a, b)
+
+    doAssert res == @[(12, 99), (7, 7)]
+    doAssert visits == 7
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield ((12, t2()))
+      yield (bar())
+
+    let res = collect:
+      for (a, b) in foo():
+        (a, b)
+
+    doAssert res == @[(12, 99), (8, 8)]
+    doAssert visits == 8
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t1(): int = 99
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield (t1(), t2())
+      yield bar()
+
+    let res = collect:
+      for a, b in foo():
+        (a, b)
+
+    doAssert res == @[(99, 99), (9, 9)]
+    doAssert visits == 9
+
+
+  block:
+    proc bar(): ((int, int), string) =
+      inc visits
+      ((visits, visits), $visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): ((int, int), string) =
+      yield ((1, 2), $t2())
+      yield bar()
+
+    let res = collect:
+      for a, b in foo():
+        (a, b)
+
+    doAssert res == @[((1, 2), "99"), ((10, 10), "10")]
+    doAssert visits == 10
+
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    iterator foo(): (int, int) =
+      yield (for i in 0 ..< 10: discard bar(); bar())
+      yield (bar())
+
+    let res = collect:
+      for (a, b) in foo():
+        (a, b)
+
+    doAssert res == @[(21, 21), (22, 22)]
+
+  block:
+    proc bar(): (int, int) =
+      inc visits
+      (visits, visits)
+
+    proc t2(): int = 99
+
+    iterator foo(): (int, int) =
+      yield if true: bar() else: (t2(), t2())
+      yield (bar())
+
+    let res = collect:
+      for a, b in foo():
+        (a, b)
+
+    doAssert res == @[(23, 23), (24, 24)]
+
+
+block:
+  iterator foo(): (int, int, int) =
+    var time = 777
+    yield (1, time, 3)
+
+  let res = collect:
+    for a, b, c in foo():
+      (a, b, c)
+
+  doAssert res == @[(1, 777, 3)]
+
+block:
+  iterator foo(): (int, int, int) =
+    var time = 777
+    yield (1, time, 3)
+
+  let res = collect:
+    for t in foo():
+      (t[0], t[1], t[2])
+
+  doAssert res == @[(1, 777, 3)]
+
+
+block:
+  proc bar(): (int, int, int) =
+    (1, 2, 3)
+  iterator foo(): (int, int, int) =
+    yield bar()
+
+  let res = collect:
+    for a, b, c in foo():
+      (a, b, c)
+
+  doAssert res == @[(1, 2, 3)]
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/stdlib/uselocks.nim b/tests/stdlib/uselocks.nim
new file mode 100644
index 000000000..f87623b5e
--- /dev/null
+++ b/tests/stdlib/uselocks.nim
@@ -0,0 +1,16 @@
+import locks
+import std/assertions
+
+type MyType* [T] = object
+  lock: Lock
+
+proc createMyType*[T]: MyType[T] =
+  initLock(result.lock)
+
+proc use* (m: var MyType): int =
+  withLock m.lock:
+    result = 3
+
+block:
+  var l: Lock
+  doAssert $l == "()"
diff --git a/tests/stmt/tforloop_tuple_multiple_underscore.nim b/tests/stmt/tforloop_tuple_multiple_underscore.nim
new file mode 100644
index 000000000..96804df18
--- /dev/null
+++ b/tests/stmt/tforloop_tuple_multiple_underscore.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "the special identifier '_' is ignored in declarations and cannot be used"
+"""
+
+iterator iter(): (int, int, int) =
+  yield (1, 1, 2)
+
+
+for (_, i, _) in iter():
+  echo _
diff --git a/tests/stmt/tforloop_tuple_underscore.nim b/tests/stmt/tforloop_tuple_underscore.nim
new file mode 100644
index 000000000..eda42d527
--- /dev/null
+++ b/tests/stmt/tforloop_tuple_underscore.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "the special identifier '_' is ignored in declarations and cannot be used"
+"""
+
+iterator iter(): (int, int) =
+  yield (1, 2)
+  yield (3, 4)
+  yield (1, 2)
+  yield (3, 4)
+  yield (1, 2)
+  yield (3, 4)
+
+
+for (_, i) in iter():
+  echo _
+
diff --git a/tests/stmt/tforloop_underscore.nim b/tests/stmt/tforloop_underscore.nim
new file mode 100644
index 000000000..ce1c86386
--- /dev/null
+++ b/tests/stmt/tforloop_underscore.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "the special identifier '_' is ignored in declarations and cannot be used"
+"""
+
+for _ in ["a"]:
+  echo _
diff --git a/tests/stmt/tgenericsunderscore.nim b/tests/stmt/tgenericsunderscore.nim
new file mode 100644
index 000000000..be2b8ec78
--- /dev/null
+++ b/tests/stmt/tgenericsunderscore.nim
@@ -0,0 +1,4 @@
+# issue #21435
+
+proc foo[_](x: typedesc[_]): string = "BAR" #[tt.Error
+                        ^ the special identifier '_' is ignored in declarations and cannot be used]#
diff --git a/tests/stmt/tmiscunderscore.nim b/tests/stmt/tmiscunderscore.nim
new file mode 100644
index 000000000..c4bae1c3d
--- /dev/null
+++ b/tests/stmt/tmiscunderscore.nim
@@ -0,0 +1,15 @@
+import std/assertions
+
+block:
+  proc _() = echo "one"
+  doAssert not compiles(_())
+  proc _() = echo "two"
+  doAssert not compiles(_())
+
+block:
+  type _ = int
+  doAssert not (compiles do:
+    let x: _ = 3)
+  type _ = float
+  doAssert not (compiles do:
+    let x: _ = 3)
diff --git a/tests/strictnotnil/tnilcheck.nim b/tests/strictnotnil/tnilcheck.nim
new file mode 100644
index 000000000..b8057de74
--- /dev/null
+++ b/tests/strictnotnil/tnilcheck.nim
@@ -0,0 +1,381 @@
+discard """
+action: compile
+"""
+
+import tables
+
+{.experimental: "strictNotNil".}
+
+type
+  Nilable* = ref object
+    a*: int
+    field*: Nilable
+    
+  NonNilable* = Nilable not nil
+
+  Nilable2* = nil NonNilable
+
+
+# proc `[]`(a: Nilable, b: int): Nilable =
+#   nil
+
+
+# Nilable tests
+
+
+
+# test deref
+proc testDeref(a: Nilable) =
+  echo a.a > 0 #[tt.Warning
+       ^ can't deref a, it might be nil
+  ]#
+
+
+
+# # # test if else
+proc testIfElse(a: Nilable) =
+  if a.isNil:
+    echo a.a #[tt.Warning
+         ^ can't deref a, it is nil
+    ]#
+  else:
+    echo a.a # ok
+
+proc testIfNoElse(a: Nilable) =
+  if a.isNil:
+    echo a.a #[tt.Warning
+         ^ can't deref a, it is nil
+         ]#
+  echo a.a #[tt.Warning
+       ^ can't deref a, it might be nil
+   ]#
+
+proc testIfReturn(a: Nilable) =
+  if not a.isNil:
+    return
+  echo a.a #[tt.Warning
+       ^ can't deref a, it is nil
+  ]#
+
+proc testIfBreak(a: seq[Nilable]) =
+  for b in a:
+    if not b.isNil:
+      break
+    echo b.a #[tt.Warning
+         ^ can't deref b, it is nil
+    ]#
+
+proc testIfContinue(a: seq[Nilable]) =
+  for b in a:
+    if not b.isNil:
+      continue
+    echo b.a #[tt.Warning
+         ^ can't deref b, it is nil
+    ]#
+
+proc testIfRaise(a: Nilable) =
+  if not a.isNil:
+    raise newException(ValueError, "")
+  echo a.a #[tt.Warning
+       ^ can't deref a, it is nil
+  ]#
+
+proc testIfElif(a: Nilable) =
+  var c = 0
+  if c == 0:
+    echo a.a #[tt.Warning
+         ^ can't deref a, it might be nil
+      ]#
+  elif c == 1:
+    echo a.a #[tt.Warning
+         ^ can't deref a, it might be nil
+      ]#
+  elif not a.isNil:
+    echo a.a # ok
+  elif c == 2:
+    echo 0
+  else:
+    echo a.a #[tt.Warning
+         ^ can't deref a, it is nil
+    ]#
+
+proc testAssignUnify(a: Nilable, b: int) =
+  var a2 = a
+  if b == 0:
+    a2 = Nilable()
+  echo a2.a #[tt.Warning
+       ^ can't deref a2, it might be nil
+  ]#
+
+
+# # test assign in branch and unifiying that with the main block after end of branch
+proc testAssignUnifyNil(a: Nilable, b: int) =
+  var a2 = a
+  if b == 0:
+    a2 = nil
+  echo a2.a #[tt.Warning
+       ^ can't deref a2, it might be nil
+  ]#
+
+# test loop
+proc testForLoop(a: Nilable) =
+  var b = Nilable()
+  for i in 0 .. 5:
+    echo b.a #[tt.Warning
+         ^ can't deref b, it might be nil
+    ]#
+    if i == 2:
+      b = a
+  echo b.a #[tt.Warning
+       ^ can't deref b, it might be nil
+  ]#
+
+
+
+# # TODO implement this after discussion
+# # proc testResultCompoundNonNilableElement(a: Nilable): (NonNilable, NonNilable) = #[t t.Warning
+# #      ^ result might be not initialized, so it or an element might be nil
+# # ]#
+# #   if not a.isNil:
+# #     result[0] = a #[t t.Warning
+# #                 ^ can't assign nilable to non nilable: it might be nil
+# #     #]
+
+# # proc testNonNilDeref(a: NonNilable) =
+# #   echo a.a # ok
+
+
+
+# # # not only calls: we can use partitions for dependencies for field aliases
+# # # so we can detect on change what does this affect or was this mutated between us and the original field
+
+# # proc testRootAliasField(a: Nilable) =
+# #   var aliasA = a
+# #   if not a.isNil and not a.field.isNil:
+# #     aliasA.field = nil
+# #     # a.field = nil
+# #     # aliasA = nil 
+# #     echo a.field.a # [tt.Warning
+# #          ^ can't deref a.field, it might be nil
+# #     ]#
+
+
+proc testAliasChanging(a: Nilable) =
+  var b = a
+  var aliasA = b
+  b = Nilable()
+  if not b.isNil:
+    echo aliasA.a #[tt.Warning
+         ^ can't deref aliasA, it might be nil
+    ]#
+
+# # TODO
+# # proc testAliasUnion(a: Nilable) =
+# #   var a2 = a
+# #   var b = a2
+# #   if a.isNil:
+# #     b = Nilable()
+# #     a2 = nil
+# #   else:
+# #     a2 = Nilable()
+# #     b = a2
+# #   if not b.isNil:
+# #     echo a2.a #[ tt.Warning
+# #          ^ can't deref a2, it might be nil
+# #     ]#
+
+# # TODO after alias support
+# #proc callVar(a: var Nilable) =
+# #  a.field = nil
+
+
+# # TODO ptr support
+# # proc testPtrAlias(a: Nilable) =
+# #   # pointer to a: hm.
+# #   # alias to a?
+# #   var ptrA = a.addr # {0, 1} 
+# #   if not a.isNil: # {0, 1}
+# #     ptrA[] = nil # {0, 1} 0: MaybeNil 1: MaybeNil
+# #     echo a.a #[ tt.Warning
+# #          ^ can't deref a, it might be nil
+# #     ]#
+
+# # TODO field stuff
+# # currently it just doesnt support dot, so accidentally it shows a warning but because that
+# # not alias i think
+# # proc testFieldAlias(a: Nilable) =
+# #   var b = a # {0, 1} {2} 
+# #   if not a.isNil and not a.field.isNil: # {0, 1} {2}
+# #     callVar(b) # {0, 1} {2} 0: Safe 1: Safe
+# #     echo a.field.a #[ tt.Warning
+# #           ^ can't deref a.field, it might be nil
+# #     ]#
+# #
+# # proc testUniqueHashTree(a: Nilable): Nilable =
+# #   # TODO what would be a clash
+# #   var field = 0
+# #   if not a.isNil and not a.field.isNil:
+# #     # echo a.field.a
+# #     echo a[field].a
+# #   result = Nilable()
+  
+# # proc testSeparateShadowingResult(a: Nilable): Nilable =
+# #   result = Nilable()
+# #   if not a.isNil:
+# #     var result: Nilable = nil
+# #   echo result.a
+
+
+proc testCStringDeref(a: cstring) =
+  echo a[0] #[tt.Warning
+       ^ can't deref a, it might be nil
+  ]#
+
+
+proc testNilablePtr(a: ptr int) =
+  if not a.isNil:
+    echo a[] # ok
+  echo a[] #[tt.Warning
+       ^ can't deref a, it might be nil
+  ]#
+
+# # proc testNonNilPtr(a: ptr int not nil) =
+# #   echo a[] # ok
+
+proc raiseCall: NonNilable = #[tt.Warning
+^ return value is nil
+]#
+  raise newException(ValueError, "raise for test") 
+
+# proc testTryCatch(a: Nilable) =
+#   var other = a
+#   try:
+#     other = raiseCall()
+#   except:
+#     discard
+#   echo other.a #[ tt.Warning
+#             ^ can't deref other, it might be nil
+#   ]#
+
+# # proc testTryCatchDetectNoRaise(a: Nilable) =
+# #   var other = Nilable()
+# #   try:
+# #     other = nil
+# #     other = a
+# #     other = Nilable()
+# #   except:
+# #     other = nil
+# #   echo other.a # ok
+
+# # proc testTryCatchDetectFinally =
+# #   var other = Nilable()
+# #   try:
+# #     other = nil
+# #     other = Nilable()
+# #   except:
+# #     other = Nilable()
+# #   finally:
+# #     other = nil
+# #   echo other.a # can't deref other: it is nil
+
+# # proc testTryCatchDetectNilableWithRaise(b: bool) =
+# #   var other = Nilable()
+# #   try:
+# #     if b:
+# #       other = nil
+# #     else:
+# #       other = Nilable()
+# #       var other2 = raiseCall()
+# #   except:
+# #     echo other.a # ok
+
+# #   echo other.a # can't deref a: it might be nil
+
+# # proc testRaise(a: Nilable) =
+# #   if a.isNil:
+# #     raise newException(ValueError, "a == nil")
+# #   echo a.a # ok
+
+
+# # proc testBlockScope(a: Nilable) =
+# #   var other = a
+# #   block:
+# #     var other = Nilable()
+# #     echo other.a # ok
+# #   echo other.a # can't deref other: it might be nil
+
+# # ok we can't really get the nil value from here, so should be ok
+# # proc testDirectRaiseCall: NonNilable =
+# #   var a = raiseCall()
+# #   result = NonNilable()
+
+# # proc testStmtList =
+# #   var a = Nilable()
+# #   block:
+# #     a = nil
+# #     a = Nilable()
+# #   echo a.a # ok
+
+proc callChange(a: Nilable) =
+  if not a.isNil:
+    a.field = nil
+
+proc testCallChangeField =
+  var a = Nilable()
+  a.field = Nilable()
+  callChange(a)
+  echo a.field.a #[ tt.Warning
+        ^ can't deref a.field, it might be nil
+       ]#
+
+proc testReassignVarWithField =
+  var a = Nilable()
+  a.field = Nilable()
+  echo a.field.a # ok
+  a = Nilable()
+  echo a.field.a #[ tt.Warning
+        ^ can't deref a.field, it might be nil
+        ]#
+
+
+proc testItemDeref(a: var seq[Nilable]) =
+  echo a[0].a #[tt.Warning
+        ^ can't deref a[0], it might be nil
+       ]#
+  a[0] = Nilable() # good: now .. if we dont track, how do we know 
+  echo a[0].a # ok
+  echo a[1].a #[tt.Warning
+        ^ can't deref a[1], it might be nil
+  ]#
+  var b = 1
+  if a[b].isNil:
+    echo a[1].a #[tt.Warning
+          ^ can't deref a[1], it might be nil
+    ]#
+    var c = 0
+    echo a[c].a #[tt.Warning
+          ^ can't deref a[c], it might be nil
+    ]#
+
+  # known false positive
+  if not a[b].isNil:
+    echo a[b].a #[tt.Warning
+          ^ can't deref a[b], it might be nil
+    ]#
+
+  const c = 0
+  if a[c].isNil:
+    echo a[0].a #[tt.Warning
+          ^ can't deref a[0], it is nil
+    ]#
+  a[c] = Nilable()
+  echo a[0].a # ok
+
+
+
+# # # proc test10(a: Nilable) =
+# # #   if not a.isNil and not a.b.isNil:
+# # #     c_memset(globalA.addr, 0, globalA.sizeOf.csize_t)
+# # #     globalA = nil
+# # #     echo a.a # can't deref a: it might be nil
+
diff --git a/tests/strictnotnil/tnilcheck_no_warnings.nim b/tests/strictnotnil/tnilcheck_no_warnings.nim
new file mode 100644
index 000000000..5ec9bc575
--- /dev/null
+++ b/tests/strictnotnil/tnilcheck_no_warnings.nim
@@ -0,0 +1,182 @@
+discard """
+cmd: "nim check --warningAsError:StrictNotNil $file"
+action: "compile"
+"""
+
+import tables
+
+{.experimental: "strictNotNil".}
+
+type
+  Nilable* = ref object
+    a*: int
+    field*: Nilable
+    
+  NonNilable* = Nilable not nil
+
+  Nilable2* = nil NonNilable
+
+
+# proc `[]`(a: Nilable, b: int): Nilable =
+#   nil
+
+
+# Nilable tests
+
+
+
+# # test and
+proc testAnd(a: Nilable) =
+  echo not a.isNil and a.a > 0 # ok
+
+
+# test else branch and inferring not isNil
+# proc testElse(a: Nilable, b: int) =
+#   if a.isNil:
+#     echo 0
+#   else:
+#     echo a.a
+
+# test that here we can infer that n can't be nil anymore
+proc testNotNilAfterAssign(a: Nilable, b: int) =
+  var n = a # a: MaybeNil n: MaybeNil
+  if n.isNil: # n: Safe a: MaybeNil
+    n = Nilable() # n: Safe a: MaybeNil
+  echo n.a # ok
+
+proc callVar(a: var Nilable) =
+   a = nil
+
+proc testVarAlias(a: Nilable) = # a: 0 aliasA: 1 {0} {1} 
+  var aliasA = a # {0, 1} 0 MaybeNil 1 MaybeNil
+  if not a.isNil: # {0, 1} 0 Safe 1 Safe
+    callVar(aliasA) # {0, 1} 0 MaybeNil 1 MaybeNil
+    # if aliasA stops being in alias: it might be nil, but then a is still not nil
+    # if not: it cant be nil as it still points here
+    echo a.a # ok 
+
+proc testAliasCheck(a: Nilable) =
+  var aliasA = a
+  if not a.isNil:
+    echo aliasA.a # ok
+
+proc testFieldCheck(a: Nilable) =
+  if not a.isNil and not a.field.isNil:
+    echo a.field.a # ok
+
+proc testTrackField =
+  var a = Nilable(field: Nilable())
+  echo a.field.a # ok
+
+proc testNonNilDeref(a: NonNilable) =
+  echo a.a # ok
+
+# # not only calls: we can use partitions for dependencies for field aliases
+# # so we can detect on change what does this affect or was this mutated between us and the original field
+
+
+# proc testUniqueHashTree(a: Nilable): Nilable =
+#   # TODO what would be a clash
+#   var field = 0
+#   if not a.isNil and not a.field.isNil:
+#     # echo a.field.a
+#     echo a[field].a
+#   result = Nilable()
+  
+proc testSeparateShadowingResult(a: Nilable): Nilable =
+  result = Nilable()
+  if not a.isNil:
+    var result: Nilable = nil
+  echo result.a
+
+
+proc testNonNilCString(a: cstring not nil) =
+  echo a[0] # ok
+
+proc testNonNilPtr(a: ptr int not nil) =
+  echo a[] # ok
+
+
+# proc testTryCatchDetectNoRaise(a: Nilable) =
+#   var other = Nilable()
+#   try:
+#     other = nil
+#     other = a
+#     other = Nilable()
+#   except:
+#     other = nil
+#   echo other.a # ok
+
+# proc testTryCatchDetectFinally =
+#   var other = Nilable()
+#   try:
+#     other = nil
+#     other = Nilable()
+#   except:
+#     other = Nilable()
+#   finally:
+#     other = nil
+#   echo other.a # can't deref other: it is nil
+
+# proc testTryCatchDetectNilableWithRaise(b: bool) =
+#   var other = Nilable()
+#   try:
+#     if b:
+#       other = nil
+#     else:
+#       other = Nilable()
+#       var other2 = raiseCall()
+#   except:
+#     echo other.a # ok
+
+#   echo other.a # can't deref a: it might be nil
+
+proc testRaise(a: Nilable) =
+  if a.isNil:
+    raise newException(ValueError, "a == nil")
+  echo a.a # ok
+
+# proc testBlockScope(a: Nilable) =
+#   var other = a
+#   block:
+#     var other = Nilable()
+#     echo other.a # ok
+#   echo other.a # can't deref other: it might be nil
+
+# # (ask Araq about this: not supported yet) ok we can't really get the nil value from here, so should be ok
+# proc testDirectRaiseCall: NonNilable =
+#   var a = raiseCall()
+#   result = NonNilable()
+
+proc testStmtList =
+  var a = Nilable()
+  block:
+    a = nil
+    a = Nilable()
+  echo a.a # ok
+
+proc testItemDerefNoWarning(a: var seq[Nilable]) =
+  a[0] = Nilable() # good: now .. if we dont track, how do we know 
+  echo a[0].a # ok
+  var b = 1
+
+  const c = 0
+  a[c] = Nilable()
+  echo a[0].a # ok
+
+# proc callChange(a: Nilable) =
+#   a.field = nil
+
+# proc testCallAlias =
+#   var a = Nilable(field: Nilable())
+#   callChange(a)
+#   echo a.field.a # can't deref a.field, it might be nil
+
+# # proc test10(a: Nilable) =
+# #   if not a.isNil and not a.b.isNil:
+# #     c_memset(globalA.addr, 0, globalA.sizeOf.csize_t)
+# #     globalA = nil
+# #     echo a.a # can't deref a: it might be nil
+
+var nilable: Nilable
+var withField = Nilable(a: 0, field: Nilable())
diff --git a/tests/stylecheck/fileinfo.nim b/tests/stylecheck/fileinfo.nim
new file mode 100644
index 000000000..d6faf0c73
--- /dev/null
+++ b/tests/stylecheck/fileinfo.nim
@@ -0,0 +1,2 @@
+# fileinfo.nim
+type FileInfo* = object
\ No newline at end of file
diff --git a/tests/stylecheck/foreign_package/foreign_package.nim b/tests/stylecheck/foreign_package/foreign_package.nim
new file mode 100644
index 000000000..f95be006c
--- /dev/null
+++ b/tests/stylecheck/foreign_package/foreign_package.nim
@@ -0,0 +1 @@
+include ../thint
\ No newline at end of file
diff --git a/tests/stylecheck/foreign_package/foreign_package.nimble b/tests/stylecheck/foreign_package/foreign_package.nimble
new file mode 100644
index 000000000..a2c49e389
--- /dev/null
+++ b/tests/stylecheck/foreign_package/foreign_package.nimble
@@ -0,0 +1,2 @@
+# See `tstyleCheck`
+# Needed to mark `mstyleCheck` as a foreign package.
diff --git a/tests/stylecheck/t20397.nim b/tests/stylecheck/t20397.nim
new file mode 100644
index 000000000..486a97d73
--- /dev/null
+++ b/tests/stylecheck/t20397.nim
@@ -0,0 +1,4 @@
+{.hintAsError[Name]:on.}
+var a_b = 1
+discard a_b
+{.hintAsError[Name]:off.}
\ No newline at end of file
diff --git a/tests/stylecheck/t20397_1.nim b/tests/stylecheck/t20397_1.nim
new file mode 100644
index 000000000..76c03dca1
--- /dev/null
+++ b/tests/stylecheck/t20397_1.nim
@@ -0,0 +1,8 @@
+discard """
+  matrix: "--styleCheck:off --hint:Name:on"
+"""
+
+{.hintAsError[Name]:on.}
+var a_b = 1
+discard a_b
+{.hintAsError[Name]:off.}
diff --git a/tests/stylecheck/t20397_2.nim b/tests/stylecheck/t20397_2.nim
new file mode 100644
index 000000000..3b8e1c4d6
--- /dev/null
+++ b/tests/stylecheck/t20397_2.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "'a_b' should be: 'aB'"
+  matrix: "--styleCheck:error"
+"""
+
+var a_b = 1
+discard a_b
\ No newline at end of file
diff --git a/tests/stylecheck/taccept.nim b/tests/stylecheck/taccept.nim
new file mode 100644
index 000000000..43a9ab71f
--- /dev/null
+++ b/tests/stylecheck/taccept.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--styleCheck:error --styleCheck:usages"
+"""
+
+import std/[asyncdispatch, nre]
+
+type
+  Name = object
+    id: int
+
+template hello =
+  var iD = "string"
+  var name: Name
+  doAssert name.id == 0
+  doAssert iD == "string"
+
+hello()
+
+# bug #12955
+import os
+import fileinfo
+var xs: seq[fileinfo.FileInfo]
diff --git a/tests/stylecheck/tforeign_package.nim b/tests/stylecheck/tforeign_package.nim
new file mode 100644
index 000000000..8594ad802
--- /dev/null
+++ b/tests/stylecheck/tforeign_package.nim
@@ -0,0 +1,16 @@
+discard """
+  matrix: "--errorMax:0 --styleCheck:error"
+  action: compile
+"""
+
+import foreign_package/foreign_package
+
+# This call tests that:
+#   - an instantiation of a generic in a foreign package doesn't raise errors
+#     when the generic body contains:
+#     - definition and usage violations
+#     - builtin pragma usage violations
+#     - user pragma usage violations
+#   - definition violations in foreign packages are ignored
+#   - usage violations in foreign packages are ignored
+genericProc[int]()
diff --git a/tests/stylecheck/thint.nim b/tests/stylecheck/thint.nim
new file mode 100644
index 000000000..c19aac1b8
--- /dev/null
+++ b/tests/stylecheck/thint.nim
@@ -0,0 +1,43 @@
+discard """
+  matrix: "--styleCheck:hint"
+  action: compile
+"""
+
+# Test violating ident definition:
+{.pragma: user_pragma.} #[tt.Hint
+        ^ 'user_pragma' should be: 'userPragma' [Name] ]#
+
+# Test violating ident usage style matches definition style:
+{.userPragma.} #[tt.Hint
+  ^ 'userPragma' should be: 'user_pragma' [template declared in thint.nim(7, 9)] [Name] ]#
+
+# Test violating builtin pragma usage style:
+{.no_side_effect.}: #[tt.Hint
+  ^ 'no_side_effect' should be: 'noSideEffect' [Name] ]#
+  discard 0
+
+# Test:
+#  - definition style violation
+#  - user pragma usage style violation
+#  - builtin pragma usage style violation
+proc generic_proc*[T] {.no_destroy, userPragma.} = #[tt.Hint
+     ^ 'generic_proc' should be: 'genericProc' [Name]; tt.Hint
+                        ^ 'no_destroy' should be: 'nodestroy' [Name]; tt.Hint
+                                    ^ 'userPragma' should be: 'user_pragma' [template declared in thint.nim(7, 9)] [Name] ]#
+  # Test definition style violation:
+  let snake_case = 0 #[tt.Hint
+      ^ 'snake_case' should be: 'snakeCase' [Name] ]#
+  # Test user pragma definition style violation:
+  {.pragma: another_user_pragma.} #[tt.Hint
+          ^ 'another_user_pragma' should be: 'anotherUserPragma' [Name] ]#
+  # Test user pragma usage style violation:
+  {.anotherUserPragma.} #[tt.Hint
+    ^ 'anotherUserPragma' should be: 'another_user_pragma' [template declared in thint.nim(31, 11)] [Name] ]#
+  # Test violating builtin pragma usage style:
+  {.no_side_effect.}: #[tt.Hint
+    ^ 'no_side_effect' should be: 'noSideEffect' [Name] ]#
+    # Test usage style violation:
+    discard snakeCase #[tt.Hint
+            ^ 'snakeCase' should be: 'snake_case' [let declared in thint.nim(28, 7)] [Name] ]#
+
+generic_proc[int]()
diff --git a/tests/stylecheck/treject.nim b/tests/stylecheck/treject.nim
new file mode 100644
index 000000000..458a2d039
--- /dev/null
+++ b/tests/stylecheck/treject.nim
@@ -0,0 +1,17 @@
+discard """
+  action: reject
+  nimout: '''treject.nim(14, 13) Error: 'iD' should be: 'id' [field declared in treject.nim(9, 5)]'''
+  matrix: "--styleCheck:error --styleCheck:usages  --hint:Name:on"
+"""
+
+type
+  Name = object
+    id: int
+
+template hello =
+  var iD = "string"
+  var name: Name
+  echo name.iD
+  echo iD
+
+hello()
diff --git a/tests/stylecheck/tusages.nim b/tests/stylecheck/tusages.nim
new file mode 100644
index 000000000..b689dabb3
--- /dev/null
+++ b/tests/stylecheck/tusages.nim
@@ -0,0 +1,22 @@
+discard """
+  action: reject
+  nimout: '''tusages.nim(20, 5) Error: 'BAD_STYLE' should be: 'BADSTYLE' [proc declared in tusages.nim(9, 6)]'''
+  matrix: "--styleCheck:error --styleCheck:usages --hint:all:off --hint:Name:on"
+"""
+
+import strutils
+
+proc BADSTYLE(c: char) = discard
+
+proc toSnakeCase(s: string): string =
+  result = newStringOfCap(s.len + 3)
+  for i in 0..<s.len:
+    if s[i] in {'A'..'Z'}:
+      if i > 0 and s[i-1] in {'a'..'z'}:
+        result.add '_'
+      result.add toLowerAscii(s[i])
+    else:
+      result.add s[i]
+    BAD_STYLE(s[i])
+
+echo toSnakeCase("fooBarBaz Yes")
diff --git a/tests/system/helpers/readall_echo.nim b/tests/system/helpers/readall_echo.nim
new file mode 100644
index 000000000..2891ef3ae
--- /dev/null
+++ b/tests/system/helpers/readall_echo.nim
@@ -0,0 +1,2 @@
+when true:
+  echo(stdin.readAll)
diff --git a/tests/system/t10307.nim b/tests/system/t10307.nim
new file mode 100644
index 000000000..b5a93c5c6
--- /dev/null
+++ b/tests/system/t10307.nim
@@ -0,0 +1,24 @@
+discard """
+  cmd: "nim c --mm:refc -d:useGcAssert $file"
+  output: '''running someProc(true)
+res: yes
+yes
+running someProc(false)
+res: 
+
+'''
+"""
+
+proc someProc(x:bool):cstring =
+  var res:string = ""
+  if x:
+    res = "yes"
+  echo "res: ", res
+  GC_ref(res)
+  result = res
+
+echo "running someProc(true)"
+echo someProc(true)
+
+echo "running someProc(false)"
+echo someProc(false)
diff --git a/tests/system/t20938.nim b/tests/system/t20938.nim
new file mode 100644
index 000000000..7341cbb91
--- /dev/null
+++ b/tests/system/t20938.nim
@@ -0,0 +1,12 @@
+discard """
+  cmd: "nim c --mm:refc $file"
+  action: "compile"
+"""
+
+template foo(x: typed) =
+  discard x
+
+foo:
+  var x = "hello"
+  x.shallowCopy("test")
+  true
diff --git a/tests/system/t7894.nim b/tests/system/t7894.nim
new file mode 100644
index 000000000..60dbe86cb
--- /dev/null
+++ b/tests/system/t7894.nim
@@ -0,0 +1,23 @@
+discard """
+disabled: true
+"""
+
+# CI integration servers are out of memory for this test
+
+const size = 250000000
+
+proc main() =
+
+  var saved = newSeq[seq[int8]]()
+
+  for i in 0..22:
+    # one of these is 0.25GB.
+    #echo i
+    var x = newSeq[int8](size)
+    saved.add(x)
+
+  for x in saved:
+    #echo x.len
+    doAssert x.len == size
+
+main()
diff --git a/tests/system/talloc.nim b/tests/system/talloc.nim
new file mode 100644
index 000000000..a81fef481
--- /dev/null
+++ b/tests/system/talloc.nim
@@ -0,0 +1,59 @@
+# was: appveyor is "out of memory"
+
+var x: ptr int
+
+x = cast[ptr int](alloc(7))
+doAssert x != nil
+x = cast[ptr int](x.realloc(2))
+doAssert x != nil
+x.dealloc()
+
+x = createU(int, 3)
+doAssert x != nil
+x.dealloc()
+
+x = create(int, 4)
+doAssert cast[ptr array[4, int]](x)[0] == 0
+doAssert cast[ptr array[4, int]](x)[1] == 0
+doAssert cast[ptr array[4, int]](x)[2] == 0
+doAssert cast[ptr array[4, int]](x)[3] == 0
+
+x = x.resize(4)
+doAssert x != nil
+x.dealloc()
+
+x = cast[ptr int](allocShared(100))
+doAssert x != nil
+deallocShared(x)
+
+x = createSharedU(int, 3)
+doAssert x != nil
+x.deallocShared()
+
+x = createShared(int, 3)
+doAssert x != nil
+doAssert cast[ptr array[3, int]](x)[0] == 0
+doAssert cast[ptr array[3, int]](x)[1] == 0
+doAssert cast[ptr array[3, int]](x)[2] == 0
+
+doAssert x != nil
+x = cast[ptr int](x.resizeShared(2))
+doAssert x != nil
+x.deallocShared()
+
+x = create(int, 10)
+doAssert x != nil
+x = x.resize(12)
+doAssert x != nil
+x.dealloc()
+
+x = createShared(int, 1)
+doAssert x != nil
+x = x.resizeShared(1)
+doAssert x != nil
+x.deallocShared()
+
+x = cast[ptr int](alloc0(125 shl 23))
+dealloc(x)
+x = cast[ptr int](alloc0(126 shl 23))
+dealloc(x)
diff --git a/tests/system/talloc2.nim b/tests/system/talloc2.nim
new file mode 100644
index 000000000..9d1687f34
--- /dev/null
+++ b/tests/system/talloc2.nim
@@ -0,0 +1,46 @@
+discard """
+disabled: "windows"
+disabled: "openbsd"
+joinable: false
+disabled: 32bit
+"""
+# no point to test this on system with smaller address space
+# was: appveyor is "out of memory"
+
+const
+  nmax = 2*1024*1024*1024
+
+proc test(n: int) =
+  var a = alloc0(9999)
+  var t = cast[ptr UncheckedArray[int8]](alloc(n))
+  var b = alloc0(9999)
+  t[0] = 1
+  t[1] = 2
+  t[n-2] = 3
+  t[n-1] = 4
+  dealloc(a)
+  dealloc(t)
+  dealloc(b)
+
+# allocator adds 48 bytes to BigChunk
+# BigChunk allocator edges at 2^n * (1 - s) for s = [1..32]/64
+proc test2(n: int) =
+  let d = n div 256  # cover edges and more
+  for i in countdown(128,1):
+    for j in [-4096, -64, -49, -48, -47, -32, 0, 4096]:
+      let b = n + j - i*d
+      if b>0 and b<=nmax:
+        test(b)
+        #echo b, ": ", getTotalMem(), " ", getOccupiedMem(), " ", getFreeMem()
+
+proc test3 =
+  var n = 1
+  while n <= nmax:
+    test2(n)
+    n *= 2
+  n = nmax
+  while n >= 1:
+    test2(n)
+    n = n div 2
+
+test3()
diff --git a/tests/system/tatomics1.nim b/tests/system/tatomics1.nim
new file mode 100644
index 000000000..217fd07fa
--- /dev/null
+++ b/tests/system/tatomics1.nim
@@ -0,0 +1,9 @@
+discard """
+  targets: "c cpp js"
+"""
+
+var x = 10
+atomicInc(x)
+doAssert x == 11
+atomicDec(x)
+doAssert x == 10
diff --git a/tests/system/tcomparisons.nim b/tests/system/tcomparisons.nim
new file mode 100644
index 000000000..a661b14a1
--- /dev/null
+++ b/tests/system/tcomparisons.nim
@@ -0,0 +1,51 @@
+discard """
+  targets: "c cpp js"
+"""
+
+template main =
+  block: # proc equality
+    var prc: proc(): int {.closure.}
+    prc = nil
+    doAssert prc == nil
+    doAssert prc.isNil
+    prc = proc(): int =
+      result = 123
+    doAssert prc != nil
+    doAssert not prc.isNil
+    doAssert prc == prc
+    let prc2 = prc
+    doAssert prc == prc2
+    doAssert prc2 != nil
+    doAssert not prc2.isNil
+    doAssert not prc.isNil
+    prc = proc(): int =
+      result = 456
+    doAssert prc != nil
+    doAssert not prc.isNil
+    doAssert prc != prc2
+  block: # iterator equality
+    when nimvm: discard # vm does not support closure iterators
+    else:
+      when not defined(js): # js also does not support closure iterators
+        var iter: iterator(): int {.closure.}
+        iter = nil
+        doAssert iter == nil
+        doAssert iter.isNil
+        iter = iterator(): int =
+          yield 123
+        doAssert iter != nil
+        doAssert not iter.isNil
+        doAssert iter == iter
+        let iter2 = iter
+        doAssert iter == iter2
+        doAssert iter2 != nil
+        doAssert not iter2.isNil
+        doAssert not iter.isNil
+        iter = iterator(): int =
+          yield 456
+        doAssert iter != nil
+        doAssert not iter.isNil
+        doAssert iter != iter2
+
+static: main()
+main()
diff --git a/tests/system/tconcat.nim b/tests/system/tconcat.nim
new file mode 100644
index 000000000..fdce3ea00
--- /dev/null
+++ b/tests/system/tconcat.nim
@@ -0,0 +1,11 @@
+discard """
+  output: "DabcD"
+"""
+
+const
+  x = "abc"
+
+var v = "D" & x & "D"
+
+echo v
+
diff --git a/tests/system/tdeepcopy.nim b/tests/system/tdeepcopy.nim
new file mode 100644
index 000000000..92ba48115
--- /dev/null
+++ b/tests/system/tdeepcopy.nim
@@ -0,0 +1,95 @@
+discard """
+  matrix: "--mm:refc; --mm:orc --deepcopy:on"
+  output: "ok"
+"""
+
+import tables, lists
+
+type
+  ListTable[K, V] = object
+    valList: DoublyLinkedList[V]
+    table: Table[K, DoublyLinkedNode[V]]
+
+  ListTableRef*[K, V] = ref ListTable[K, V]
+
+proc initListTable*[K, V](initialSize = 64): ListTable[K, V] =
+  result.valList = initDoublyLinkedList[V]()
+  result.table = initTable[K, DoublyLinkedNode[V]]()
+
+proc newListTable*[K, V](initialSize = 64): ListTableRef[K, V] =
+  new(result)
+  result[] = initListTable[K, V](initialSize)
+
+proc `[]=`*[K, V](t: var ListTable[K, V], key: K, val: V) =
+  if key in t.table:
+    t.table[key].value = val
+  else:
+    let node = newDoublyLinkedNode(val)
+    t.valList.append(node)
+    t.table[key] = node
+
+proc `[]`*[K, V](t: ListTable[K, V], key: K): var V {.inline.} =
+  result = t.table[key].value
+
+proc len*[K, V](t: ListTable[K, V]): Natural {.inline.} =
+  result = t.table.len
+
+iterator values*[K, V](t: ListTable[K, V]): V =
+  for val in t.valList.items():
+    yield val
+
+proc `[]=`*[K, V](t: ListTableRef[K, V], key: K, val: V) =
+  t[][key] = val
+
+proc `[]`*[K, V](t: ListTableRef[K, V], key: K): var V {.inline.} =
+  t[][key]
+
+proc len*[K, V](t: ListTableRef[K, V]): Natural {.inline.} =
+  t[].len
+
+iterator values*[K, V](t: ListTableRef[K, V]): V =
+  for val in t[].values:
+    yield val
+
+proc main() =
+  type SomeObj = ref object
+
+  for outer in 0..10_000:
+    let myObj = new(SomeObj)
+    let table = newListTable[int, SomeObj]()
+
+    table[0] = myObj
+    for i in 1..100:
+      table[i] = new(SomeObj)
+
+    var myObj2: SomeObj
+    for val in table.values():
+      if myObj2.isNil:
+        myObj2 = val
+    doAssert(myObj == myObj2) # passes
+
+    var tableCopy: ListTableRef[int, SomeObj]
+    deepCopy(tableCopy, table)
+
+    let myObjCopy = tableCopy[0]
+    var myObjCopy2: SomeObj = nil
+    for val in tableCopy.values():
+      if myObjCopy2.isNil:
+        myObjCopy2 = val
+
+    #echo cast[int](myObj)
+    #echo cast[int](myObjCopy)
+    #echo cast[int](myObjCopy2)
+
+    doAssert(myObjCopy == myObjCopy2) # fails
+
+
+type
+  PtrTable = object
+    counter, max: int
+    data: array[0..99, (pointer, pointer)]
+
+doAssert(sizeof(PtrTable) == 2*sizeof(int)+sizeof(pointer)*2*100)
+
+main()
+echo "ok"
diff --git a/tests/system/tdollars.nim b/tests/system/tdollars.nim
new file mode 100644
index 000000000..eabee81b3
--- /dev/null
+++ b/tests/system/tdollars.nim
@@ -0,0 +1,199 @@
+discard """
+  matrix: "--mm:refc; --mm:orc; --backend:cpp; --backend:js --jsbigint64:off -d:nimStringHash2; --backend:js --jsbigint64:on"
+"""
+
+#[
+if https://github.com/nim-lang/Nim/pull/14043 is merged (or at least its
+tests/system/tostring.nim diff subset), merge
+tests/system/tostring.nim into this file, named after dollars.nim
+
+The goal is to increase test coverage across backends while minimizing test code
+duplication (which always results in weaker test coverage in practice).
+]#
+
+import std/unittest
+import std/private/jsutils
+template test[T](a: T, expected: string) =
+  check $a == expected
+  var b = a
+  check $b == expected
+  static:
+    doAssert $a == expected
+
+template testType(T: typedesc) =
+  when T is bool:
+    test true, "true"
+    test false, "false"
+  elif T is char:
+    test char, "\0"
+    test char.high, static($T.high)
+  else:
+    test T.default, "0"
+    test 1.T, "1"
+    test T.low, static($T.low)
+    test T.high, static($T.high)
+
+block: # `$`(SomeInteger)
+  # direct tests
+  check $0'u8 == "0"
+  check $255'u8 == "255"
+  check $(-127'i8) == "-127"
+
+  # known limitation: Error: number out of range: '128'i8',
+  # see https://github.com/timotheecour/Nim/issues/125
+  # check $(-128'i8) == "-128"
+
+  check $int8.low == "-128"
+  check $int8(-128) == "-128"
+  check $cast[int8](-128) == "-128"
+
+  var a = 12345'u16
+  check $a == "12345"
+  check $12345678'u64 == "12345678"
+  check $12345678'i64 == "12345678"
+  check $(-12345678'i64) == "-12345678"
+
+  # systematic tests
+  testType uint8
+  testType uint16
+  testType uint32
+  testType uint
+
+  testType int8
+  testType int16
+  testType int32
+
+  testType int
+  testType bool
+
+  whenJsNoBigInt64: discard
+  do:
+    testType uint64
+    testType int64
+    testType BiggestInt
+
+block: # #14350, #16674, #16686 for JS
+  var cstr: cstring
+  doAssert cstr == cstring(nil)
+  doAssert cstr == nil
+  doAssert cstr.isNil
+  doAssert cstr != cstring("")
+  doAssert cstr.len == 0
+
+  when defined(js):
+    cstr.add(cstring("abc"))
+    doAssert cstr == cstring("abc")
+
+    var nil1, nil2: cstring = nil
+
+    nil1.add(nil2)
+    doAssert nil1 == cstring(nil)
+    doAssert nil2 == cstring(nil)
+
+    nil1.add(cstring(""))
+    doAssert nil1 == cstring("")
+    doAssert nil2 == cstring(nil)
+
+    nil1.add(nil2)
+    doAssert nil1 == cstring("")
+    doAssert nil2 == cstring(nil)
+
+    nil2.add(nil1)
+    doAssert nil1 == cstring("")
+    doAssert nil2 == cstring("")
+
+block:
+  when defined(js): # bug #18591
+    let a1 = -1'i8
+    let a2 = uint8(a1)
+    # 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 == 255'u8
+    doAssert a3 == "255"
+    proc intToStr(a: uint8): cstring {.importjs: "(# + \"\")".}
+    doAssert $intToStr(a2) == "255"
+  else:
+    block:
+      let x = -1'i8
+      let y = uint32(x)
+      doAssert $y == "4294967295"
+    block:
+      let x = -1'i16
+      let y = uint32(x)
+      doAssert $y == "4294967295"
+    block:
+      let x = -1'i32
+      let y = uint32(x)
+      doAssert $y == "4294967295"
+    block:
+      proc foo1(arg: int): string =
+        let x = uint32(arg)
+        $x
+      doAssert $foo1(-1) == "4294967295"
+
+  block:
+    let x = 4294967295'u32
+    doAssert $x == "4294967295"
+  block:
+    doAssert $(4294967295'u32) == "4294967295"
+
+proc main()=
+  block:
+    let a = -0.0
+    doAssert $a == "-0.0"
+    doAssert $(-0.0) == "-0.0"
+
+  block:
+    let a = 0.0
+    doAssert $a == "0.0"
+    doAssert $(0.0) == "0.0"
+
+  block:
+    let b = -0
+    doAssert $b == "0"
+    doAssert $(-0) == "0"
+
+  block:
+    let b = 0
+    doAssert $b == "0"
+    doAssert $(0) == "0"
+
+  doAssert $uint32.high == "4294967295"
+
+  block: # addInt
+    var res = newStringOfCap(24)
+    template test2(a, b) =
+      res.setLen(0)
+      res.addInt a
+      doAssert res == b
+
+    for i in 0 .. 9:
+      res.addInt int64(i)
+    doAssert res == "0123456789"
+
+    res.setLen(0)
+    for i in -9 .. 0:
+      res.addInt int64(i)
+    doAssert res == "-9-8-7-6-5-4-3-2-10"
+
+    whenJsNoBigInt64: discard
+    do:
+      test2 high(int64), "9223372036854775807"
+      test2 low(int64), "-9223372036854775808"
+    test2 high(int32), "2147483647"
+    test2 low(int32), "-2147483648"
+    test2 high(int16), "32767"
+    test2 low(int16), "-32768"
+    test2 high(int8), "127"
+    test2 low(int8), "-128"
+
+  block:
+    const
+      a: array[3, char] = ['N', 'i', 'm']
+      aStr = $(a)
+
+    doAssert aStr == """['N', 'i', 'm']"""
+
+static: main()
+main()
diff --git a/tests/system/techo_unicode.nim b/tests/system/techo_unicode.nim
new file mode 100644
index 000000000..cb7c49c68
--- /dev/null
+++ b/tests/system/techo_unicode.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''ÄhmÖÜ
+abasdfdsmÄhmaИ
+Иnastystring
+A你好
+ИnastystringA你好
+ÖÜhmabasdfdsmÄhmaИOK'''
+  disabled: "posix"
+  joinable: "false"
+"""
+
+import winlean
+
+echo "ÄhmÖÜ"
+echo "abasdfdsmÄhmaИ"
+echo "Иnastystring"
+echo "A你好"
+
+write stdout, "Иnastystring"
+writeLine stdout, "A你好"
+stdout.flushFile()
+
+let handle = getOsFileHandle(stdout)
+var a = "ÖÜhmabasdfdsmÄhmaИ"
+var ac = 0'i32
+discard writeFile(handle, addr a[0], int32(len(a)), addr ac, nil)
+stdout.flushFile()
+
+import os
+
+let str = "some nulls: \0\0\0 (three of them)"
+
+let fpath = getTempDir() / "file_with_nulls.bin"
+
+writeFile(fpath, str)
+
+doAssert(getFileSize(fpath) == 31)
+doAssert(readFile(fpath) == str)
+removeFile(fpath)
+
+echo "OK"
diff --git a/tests/system/temptyecho.nim b/tests/system/temptyecho.nim
new file mode 100644
index 000000000..a3c407897
--- /dev/null
+++ b/tests/system/temptyecho.nim
@@ -0,0 +1,6 @@
+discard """
+output: "\n"
+"""
+
+echo()
+
diff --git a/tests/system/tensuremove.nim b/tests/system/tensuremove.nim
new file mode 100644
index 000000000..668d5aed1
--- /dev/null
+++ b/tests/system/tensuremove.nim
@@ -0,0 +1,131 @@
+discard """
+  targets: "c js"
+  matrix: "--cursorinference:on; --cursorinference:off"
+"""
+
+block:
+  type
+    X = object
+      s: string
+
+  proc `=copy`(x: var X, y: X) =
+    x.s = "copied " & y.s
+
+  proc `=sink`(x: var X, y: X) =
+    `=destroy`(x)
+    wasMoved(x)
+    x.s = "moved " & y.s
+
+  proc consume(x: sink X) =
+    discard x.s
+
+  proc main =
+    let m = "abcdefg"
+    var x = X(s: ensureMove m)
+    consume(ensureMove x)
+
+  static: main()
+  main()
+
+block:
+  type
+    String = object
+      id: string
+
+  proc hello =
+    var s = String(id: "1")
+    var m = ensureMove s
+    doAssert m.id == "1"
+
+  hello()
+
+block:
+  type
+    String = object
+      id: string
+
+  proc hello =
+    var n = "1"
+    var s = String(id: ensureMove n)
+    var m = ensureMove s
+    doAssert m.id == "1"
+
+  hello()
+
+block:
+  type
+    String = object
+      id: string
+
+  proc hello =
+    var n = "1"
+    var s = [ensureMove n]
+    var m = ensureMove s
+    doAssert m[0] == "1"
+
+  hello()
+
+block:
+  type
+    String = object
+      id: string
+
+  proc hello =
+    var n = "1"
+    var s = @[ensureMove n]
+    var m = ensureMove s
+    doAssert m[0] == "1"
+
+  hello()
+
+block:
+  type
+    String = object
+      id: string
+
+  proc hello =
+    var s = String(id: "1")
+    var m = ensureMove s.id
+    doAssert m == "1"
+
+  hello()
+
+block:
+  proc foo =
+    var x = 1
+    let y = ensureMove x # move
+    when not defined(js):
+      doAssert (y, x) == (1, 0) # (1, 0)
+  foo()
+
+block:
+  proc foo =
+    var x = 1
+    let y = ensureMove x # move
+    doAssert y == 1
+  foo()
+
+block:
+  proc foo =
+    var x = @[1, 2, 3]
+    let y = ensureMove x[0] # move
+    doAssert y == 1
+    when not defined(js):
+      doAssert x == @[0, 2, 3]
+  foo()
+
+block:
+  proc foo =
+    var x = [1, 2, 3]
+    let y = ensureMove x[0] # move
+    doAssert y == 1
+    when not defined(js):
+      doAssert x == @[0, 2, 3]
+  foo()
+
+block:
+  proc foo =
+    var x = @["1", "2", "3"]
+    let y = ensureMove x[0] # move
+    doAssert y == "1"
+  foo()
diff --git a/tests/system/tensuremove1.nim b/tests/system/tensuremove1.nim
new file mode 100644
index 000000000..b7e19c4fb
--- /dev/null
+++ b/tests/system/tensuremove1.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "cannot move 's', which introduces an implicit copy"
+  matrix: "--cursorinference:on; --cursorinference:off"
+"""
+
+type
+  String = object
+    id: string
+
+proc hello =
+  var s = String(id: "1")
+  var m = ensureMove s
+  discard m
+  discard s
+
+hello()
\ No newline at end of file
diff --git a/tests/system/tensuremove2.nim b/tests/system/tensuremove2.nim
new file mode 100644
index 000000000..39bbeb22e
--- /dev/null
+++ b/tests/system/tensuremove2.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "Nested expressions cannot be moved: 'if true: s else: String()'"
+"""
+
+type
+  String = object
+    id: string
+
+proc hello =
+  var s = String(id: "1")
+  var m = ensureMove(if true: s else: String())
+  discard m
+  discard s
+
+hello()
\ No newline at end of file
diff --git a/tests/system/tensuremove3.nim b/tests/system/tensuremove3.nim
new file mode 100644
index 000000000..eca032673
--- /dev/null
+++ b/tests/system/tensuremove3.nim
@@ -0,0 +1,28 @@
+discard """
+  errormsg: "cannot move 'x', passing 'x' to a sink parameter introduces an implicit copy"
+  matrix: "--cursorinference:on; --cursorinference:off"
+"""
+
+block:
+  type
+    X = object
+      s: string
+
+  proc `=copy`(x: var X, y: X) =
+    x.s = "copied " & y.s
+
+  proc `=sink`(x: var X, y: X) =
+    `=destroy`(x)
+    wasMoved(x)
+    x.s = "moved " & y.s
+
+  proc consume(x: sink X) =
+    discard x.s
+
+  proc main =
+    var s = "abcdefg"
+    var x = X(s: ensureMove s)
+    consume(ensureMove x)
+    discard x
+
+  main()
\ No newline at end of file
diff --git a/tests/system/tenum_array_repr.nim b/tests/system/tenum_array_repr.nim
new file mode 100644
index 000000000..39b1a5f9a
--- /dev/null
+++ b/tests/system/tenum_array_repr.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''
+1
+[a, b]
+2
+[c, d]
+4
+[e, f]'''
+"""
+
+# issue 5045
+
+type size1 = enum a, b
+echo sizeof(size1)
+echo repr([a, b])
+
+type size2 = enum c=0, d=20000
+echo sizeof(size2)
+echo repr([c, d])
+
+type size4 = enum e=0, f=2000000000
+echo sizeof(size4)
+echo repr([e, f])
diff --git a/tests/system/tfielditerator.nim b/tests/system/tfielditerator.nim
new file mode 100644
index 000000000..7e063c6cf
--- /dev/null
+++ b/tests/system/tfielditerator.nim
@@ -0,0 +1,126 @@
+discard """
+  output: '''
+a char: true
+a char: false
+an int: 5
+an int: 6
+a string: abc
+false
+true
+true
+false
+true
+a: a
+b: b
+x: 5
+y: 6
+z: abc
+a char: true
+a char: false
+an int: 5
+an int: 6
+a string: abc
+a string: I'm root!
+CMP false
+CMP true
+CMP true
+CMP false
+CMP true
+CMP true
+a: a
+b: b
+x: 5
+y: 6
+z: abc
+thaRootMan: I'm root!
+myDisc: enC
+c: Z
+enC
+Z
+'''
+"""
+
+block titerator1:
+  type
+    TMyTuple = tuple[a, b: char, x, y: int, z: string]
+
+  proc p(x: char) = echo "a char: ", x <= 'a'
+  proc p(x: int) = echo "an int: ", x
+  proc p(x: string) = echo "a string: ", x
+
+  var x: TMyTuple = ('a', 'b', 5, 6, "abc")
+  var y: TMyTuple = ('A', 'b', 5, 9, "abc")
+
+  for f in fields(x):
+    p f
+
+  for a, b in fields(x, y):
+    echo a == b
+
+  for key, val in fieldPairs(x):
+    echo key, ": ", val
+
+  doAssert x != y
+  doAssert x == x
+  doAssert(not (x < x))
+  doAssert x <= x
+  doAssert y < x
+  doAssert y <= x
+
+
+block titerator2:
+  type
+    SomeRootObj = object of RootObj
+      thaRootMan: string
+    TMyObj = object of SomeRootObj
+      a, b: char
+      x, y: int
+      z: string
+
+    TEnum = enum enA, enB, enC
+    TMyCaseObj = object
+      case myDisc: TEnum
+      of enA: a: int
+      of enB: b: string
+      of enC: c: char
+
+  proc p(x: char) = echo "a char: ", x <= 'a'
+  proc p(x: int) = echo "an int: ", x
+  proc p(x: string) = echo "a string: ", x
+
+  proc myobj(a, b: char, x, y: int, z: string): TMyObj =
+    result.a = a; result.b = b; result.x = x; result.y = y; result.z = z
+    result.thaRootMan = "I'm root!"
+
+  var x = myobj('a', 'b', 5, 6, "abc")
+  var y = myobj('A', 'b', 5, 9, "abc")
+
+  for f in fields(x):
+    p f
+
+  for a, b in fields(x, y):
+    echo "CMP ", a == b
+
+  for key, val in fieldPairs(x):
+    echo key, ": ", val
+
+  var co = TMyCaseObj(myDisc: enC, c: 'Z')
+  for key, val in fieldPairs(co):
+    echo key, ": ", val
+
+  for val in fields(co):
+    echo val
+
+block:
+  type
+    Enum = enum A, B
+    Object = object
+      case a: Enum
+      of A:
+        integer: int
+      of B:
+        time: string
+
+  let x = A
+  let s = Object(a: x)
+  doAssert s.integer == 0
diff --git a/tests/system/tfields.nim b/tests/system/tfields.nim
new file mode 100644
index 000000000..0bf3a4e1a
--- /dev/null
+++ b/tests/system/tfields.nim
@@ -0,0 +1,108 @@
+discard """
+  output: '''
+n
+n
+(one: 1, two: 2, three: 3)
+1
+2
+3
+(one: 4, two: 5, three: 6)
+4
+(one: 7, two: 8, three: 9)
+7
+8
+9
+(foo: 38, other: "string here")
+43
+100
+90
+'''
+"""
+
+
+block tindex:
+  type
+    TMyTuple = tuple[a, b: int]
+
+  proc indexOf(t: typedesc, name: string): int =
+    ## takes a tuple and looks for the field by name.
+    ## returs index of that field.
+    var
+      d: t
+      i = 0
+    for n, x in fieldPairs(d):
+      if n == name: return i
+      i.inc
+    raise newException(ValueError, "No field " & name & " in type " &
+      astToStr(t))
+
+  doAssert TMyTuple.indexOf("b") == 1
+
+
+
+block ttemplate:
+  # bug #1902
+  # This works.
+  for name, value in (n: "v").fieldPairs:
+    echo name
+
+  template wrapper(): void =
+    for name, value in (n: "v").fieldPairs:
+      echo name
+  wrapper()
+
+
+
+block tbreak:
+  # bug #2134
+  type
+    TestType = object
+      one: int
+      two: int
+      three: int
+
+  var
+    ab = TestType(one:1, two:2, three:3)
+    ac = TestType(one:4, two:5, three:6)
+    ad = TestType(one:7, two:8, three:9)
+    tstSeq = [ab, ac, ad]
+
+  for tstElement in mitems(tstSeq):
+    echo tstElement
+    for tstField in fields(tstElement):
+      #for tstField in [1,2,4,6]:
+      echo tstField
+      if tstField == 4:
+        break
+
+
+
+block timplicit_with_partial:
+  type
+    Base = ref object of RootObj
+    Foo {.partial.} = ref object of Base
+
+  proc my(f: Foo) =
+    #var f.next = f
+    let f.foo = 38
+    let f.other = "string here"
+    echo f[]
+    echo f.foo + 5
+
+  var g: Foo
+  new(g)
+  my(g)
+
+  type
+    FooTask {.partial.} = ref object of RootObj
+
+  proc foo(t: FooTask) {.liftLocals: t.} =
+    var x = 90
+    if true:
+      var x = 10
+      while x < 100:
+        inc x
+      echo x
+    echo x
+
+  foo(FooTask())
\ No newline at end of file
diff --git a/tests/system/tgcnone.nim b/tests/system/tgcnone.nim
new file mode 100644
index 000000000..1ccb9e29c
--- /dev/null
+++ b/tests/system/tgcnone.nim
@@ -0,0 +1,7 @@
+discard """
+  matrix: "--mm:none -d:useMalloc"
+"""
+# bug #15617
+# bug #22262
+let x = 4
+doAssert x == 4
diff --git a/tests/system/tgcregions.nim b/tests/system/tgcregions.nim
new file mode 100644
index 000000000..e14865be3
--- /dev/null
+++ b/tests/system/tgcregions.nim
@@ -0,0 +1,6 @@
+discard """
+cmd: "nim c --gc:regions $file"
+"""
+
+# issue #12597
+# it just tests that --gc:regions compiles. Nothing else.   :'(
diff --git a/tests/system/tgogc.nim b/tests/system/tgogc.nim
new file mode 100644
index 000000000..fd45bb120
--- /dev/null
+++ b/tests/system/tgogc.nim
@@ -0,0 +1,7 @@
+discard """
+  disabled: "windows"
+  cmd: "nim c --gc:go $file"
+  action: "compile"
+"""
+# bug #11447
+echo "Go GC test"
diff --git a/tests/system/timmutableinc.nim b/tests/system/timmutableinc.nim
new file mode 100644
index 000000000..e857800b3
--- /dev/null
+++ b/tests/system/timmutableinc.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <int>"
+  file: "timmutableinc.nim"
+  line: 8
+"""
+var x = 0
+
+inc(x+1)
diff --git a/tests/tnot.nim b/tests/system/tinvalidnot.nim
index cda551654..df0291a8a 100755..100644
--- a/tests/tnot.nim
+++ b/tests/system/tinvalidnot.nim
@@ -1,15 +1,19 @@
+discard """
+  errormsg: "type mismatch"
+  file: "tinvalidnot.nim"
+  line: 14
+"""
 # BUG: following compiles, but should not:
 
-proc nodeOfDegree(x: Int): bool = 
+proc nodeOfDegree(x: int): bool =
   result = false
 
-proc main = 
+proc main =
   for j in 0..2:
     for i in 0..10:
       if not nodeOfDegree(1) >= 0: #ERROR_MSG type mismatch
-        Echo "Yes"
+        echo "Yes"
       else:
-        Echo "No"
+        echo "No"
 
 main()
-
diff --git a/tests/system/tio.nim b/tests/system/tio.nim
new file mode 100644
index 000000000..52a21837a
--- /dev/null
+++ b/tests/system/tio.nim
@@ -0,0 +1,55 @@
+discard """
+outputsub: ""
+disabled: true
+"""
+
+import
+  unittest, osproc, streams, os, strformat, strutils
+const STRING_DATA = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
+
+const TEST_FILE = "tests/testdata/string.txt"
+
+proc echoLoop(str: string): string =
+  result = ""
+  let exe = findExe("tests/system/helpers/readall_echo")
+  echo "exe: ", exe
+  var process = startProcess(exe)
+  var input = process.inputStream
+  input.write(str)
+  input.close()
+  var output = process.outputStream
+  discard process.waitForExit
+  while not output.atEnd:
+    result.add(output.readLine)
+
+block: # io
+  block: # readAll
+    block: # stdin
+      check:
+        echoLoop(STRING_DATA) == STRING_DATA
+    block: # file
+      check:
+        readFile(TEST_FILE).strip == STRING_DATA
+
+
+proc verifyFileSize(sz: int64) =
+  # issue 7121, large file size (2-4GB and >4Gb)
+  const fn = "tmpfile112358"
+  let size_in_mb = sz div 1_000_000
+
+  when defined(windows):
+    discard execProcess(&"fsutil file createnew {fn} {sz}" )
+  else:
+    discard execProcess(&"dd if=/dev/zero of={fn} bs=1000000 count={size_in_mb}")
+
+  doAssert os.getFileSize(fn) == sz # Verify OS filesize by string
+
+  var f = open(fn)
+  doAssert f.getFileSize() == sz # Verify file handle filesize
+  f.close()
+
+  os.removeFile(fn)
+
+#disable tests for automatic testers
+#for s in [50_000_000'i64, 3_000_000_000, 5_000_000_000]:
+#  verifyFileSize(s)
diff --git a/tests/system/tlocals.nim b/tests/system/tlocals.nim
new file mode 100644
index 000000000..e59976102
--- /dev/null
+++ b/tests/system/tlocals.nim
@@ -0,0 +1,76 @@
+discard """
+  matrix: "--mm:refc; --mm:orc"
+  output: '''(x: "string here", a: 1)
+b is 5
+x is 12'''
+"""
+
+proc simple[T](a: T) =
+  var
+    x = "string here"
+  echo locals()
+
+simple(1)
+
+type Foo2[T]=object
+  a2: T
+
+proc numFields*(T: typedesc[tuple|object]): int=
+  var t:T
+  for _ in t.fields: inc result
+
+proc test(baz: int, qux: var int): int =
+  var foo: Foo2[int]
+  let bar = "abc"
+  let c1 = locals()
+  doAssert numFields(c1.foo.type) == 1
+  doAssert c1.bar == "abc"
+  doAssert c1.baz == 123
+  doAssert c1.result == 0
+  doAssert c1.qux == 456
+
+var x1 = 456
+discard test(123, x1)
+
+# bug #11958
+proc foo() =
+  var a = 5
+  proc bar() {.nimcall.} =
+    var b = 5
+    for k, v in fieldpairs(locals()):
+      echo k, " is ", v
+
+  bar()
+foo()
+
+
+proc foo2() =
+  var a = 5
+  proc bar2() {.nimcall.} =
+    for k, v in fieldpairs(locals()):
+      echo k, " is ", v
+
+  bar2()
+foo2()
+
+
+proc foo3[T](y: T) =
+  var a = 5
+  proc bar2[T](x: T) {.nimcall.} =
+    for k, v in fieldpairs(locals()):
+      echo k, " is ", v
+
+  bar2(y)
+
+foo3(12)
+
+block: # bug #12682
+  template foo(): untyped =
+    var c1 = locals()
+    1
+
+  proc testAll()=
+    doAssert foo() == 1
+    let c2=locals()
+
+  testAll()
diff --git a/tests/system/tlowhigh.nim b/tests/system/tlowhigh.nim
new file mode 100644
index 000000000..6ae871255
--- /dev/null
+++ b/tests/system/tlowhigh.nim
@@ -0,0 +1,32 @@
+discard """
+    action: run
+    output: '''
+18446744073709551615
+9223372036854775807
+4294967295
+0
+0
+'''
+"""
+
+var x: range[-1'f32..1'f32]
+doAssert x.low == -1'f32
+doAssert x.high == 1'f32
+doAssert x.type.low == -1'f32
+doAssert x.type.high == 1'f32
+var y: range[-1'f64..1'f64]
+doAssert y.low == -1'f64
+doAssert y.high == 1'f64
+doAssert y.type.low == -1'f64
+doAssert y.type.high == 1'f64
+
+# bug #11972
+var num: uint8
+doAssert num.high.float == 255.0
+
+echo high(uint64)
+echo high(int64)
+echo high(uint32)
+
+echo low(uint64)
+echo low(uint32)
diff --git a/tests/system/tmagics.nim b/tests/system/tmagics.nim
new file mode 100644
index 000000000..6088c9600
--- /dev/null
+++ b/tests/system/tmagics.nim
@@ -0,0 +1,62 @@
+discard """
+  matrix: "--mm:refc"
+  output: '''
+true
+true
+false
+true
+true
+false
+true
+'''
+joinable: false
+"""
+
+block tlowhigh:
+  type myEnum = enum e1, e2, e3, e4, e5
+  var a: array[myEnum, int]
+
+  for i in low(a) .. high(a):
+    a[i] = 0
+
+  proc sum(a: openArray[int]): int =
+    result = 0
+    for i in low(a)..high(a):
+      inc(result, a[i])
+
+  doAssert sum([1, 2, 3, 4]) == 10
+
+
+block t8693:
+  type Foo = int | float
+
+  proc bar(t1, t2: typedesc): bool =
+    echo (t1 is t2)
+    (t2 is t1)
+
+  proc bar[T](x: T, t2: typedesc): bool =
+    echo (T is t2)
+    (t2 is T)
+
+  doAssert bar(int, Foo) == false
+  doAssert bar(4, Foo) == false
+  doAssert bar(any, int)
+  doAssert bar(int, any) == false
+  doAssert bar(Foo, Foo)
+  doAssert bar(any, Foo)
+  doAssert bar(Foo, any) == false
+
+block t9442:
+  var v1: ref char
+  var v2: string
+  var v3: seq[char]
+  GC_ref(v1)
+  GC_unref(v1)
+  GC_ref(v2)
+  GC_unref(v2)
+  GC_ref(v3)
+  GC_unref(v3)
+
+block: # bug #12229
+  proc foo(T: typedesc) = discard
+  foo(ref)
diff --git a/tests/system/tmemory.nim b/tests/system/tmemory.nim
new file mode 100644
index 000000000..553037011
--- /dev/null
+++ b/tests/system/tmemory.nim
@@ -0,0 +1,16 @@
+import std/assertions
+
+block: # cmpMem
+  type
+    SomeHash = array[15, byte]
+
+  var
+    a: SomeHash
+    b: SomeHash
+
+  a[^1] = byte(1)
+  let c = a
+
+  doAssert cmpMem(a.addr, b.addr, sizeof(SomeHash)) > 0
+  doAssert cmpMem(b.addr, a.addr, sizeof(SomeHash)) < 0
+  doAssert cmpMem(a.addr, c.addr, sizeof(SomeHash)) == 0
diff --git a/tests/tnew.nim b/tests/system/tnew.nim
index 6527541a2..c28c1187f 100755..100644
--- a/tests/tnew.nim
+++ b/tests/system/tnew.nim
@@ -1,49 +1,61 @@
-# Test the implementation of the new operator

-# and the code generation for gc walkers

-# (and the garbage collector):

-

-type

-  PNode = ref TNode

-  TNode = object

-    data: int

-    str: string

-    le, ri: PNode

-

-  TStressTest = ref array [0..45, array [1..45, TNode]]

-

-proc finalizer(n: PNode) =

-  write(stdout, n.data)

-  write(stdout, " is now freed\n")

-

-proc newNode(data: int, le, ri: PNode): PNode =

-  new(result, finalizer)

-  result.le = le

-  result.ri = ri

-  result.data = data

-

-# now loop and build a tree

-proc main() =

-  var

-    i = 0

-    p: TStressTest

-  while i < 1000:

-    var n: PNode

-

-    n = newNode(i, nil, newNode(i + 10000, nil, nil))

-    inc(i)

-  new(p)

-

-  write(stdout, "Simple tree node allocation worked!\n")

-  i = 0

-  while i < 1000:

-    var m = newNode(i + 20000, nil, nil)

-    var k = newNode(i + 30000, nil, nil)

-    m.le = m

-    m.ri = k

-    k.le = m

-    k.ri = k

-    inc(i)

-

-  write(stdout, "Simple cycle allocation worked!\n")

-

-main()

+discard """
+matrix: "--mm:refc; --mm:orc"
+outputsub: '''
+Simple tree node allocation worked!
+Simple cycle allocation worked!
+'''
+joinable: false
+"""
+
+# Test the implementation of the new operator
+# and the code generation for gc walkers
+# (and the garbage collector):
+
+type
+  PNode = ref TNode
+  TNode = object
+    data: int
+    str: string
+    le, ri: PNode
+
+  TStressTest = ref array[0..45, array[1..45, TNode]]
+
+proc finalizer(n: PNode) =
+  write(stdout, n.data)
+  write(stdout, " is now freed\n")
+
+proc newNode(data: int, le, ri: PNode): PNode =
+  when defined(gcDestructors): # using finalizer breaks the test for orc
+    new(result)
+  else:
+    new(result, finalizer)
+  result.le = le
+  result.ri = ri
+  result.data = data
+
+# now loop and build a tree
+proc main() =
+  var
+    i = 0
+    p: TStressTest
+  while i < 1000:
+    var n: PNode
+
+    n = newNode(i, nil, newNode(i + 10000, nil, nil))
+    inc(i)
+  new(p)
+
+  write(stdout, "Simple tree node allocation worked!\n")
+  i = 0
+  while i < 1000:
+    var m = newNode(i + 20000, nil, nil)
+    var k = newNode(i + 30000, nil, nil)
+    m.le = m
+    m.ri = k
+    k.le = m
+    k.ri = k
+    inc(i)
+
+  write(stdout, "Simple cycle allocation worked!\n")
+
+main()
diff --git a/tests/system/tnewderef.nim b/tests/system/tnewderef.nim
new file mode 100644
index 000000000..3394dbddf
--- /dev/null
+++ b/tests/system/tnewderef.nim
@@ -0,0 +1,11 @@
+discard """
+  output: 3
+
+"""
+
+var x: ref int
+new(x)
+x[] = 3
+
+echo x[]
+
diff --git a/tests/system/tnewstring_uninitialized.nim b/tests/system/tnewstring_uninitialized.nim
new file mode 100644
index 000000000..9bc0e1622
--- /dev/null
+++ b/tests/system/tnewstring_uninitialized.nim
@@ -0,0 +1,11 @@
+discard """
+  matrix: "--mm:refc;"
+"""
+
+# bug #22555
+var x = newStringUninit(10)
+doAssert x.len == 10
+for i in 0..<x.len:
+  x[i] = chr(ord('a') + i)
+
+doAssert x == "abcdefghij"
diff --git a/tests/system/tnilconcats.nim b/tests/system/tnilconcats.nim
new file mode 100644
index 000000000..69fc3913c
--- /dev/null
+++ b/tests/system/tnilconcats.nim
@@ -0,0 +1,33 @@
+discard """
+  output: '''@["", "", "", "", "", "", "", "meh"]'''
+  exitcode: "0"
+"""
+
+when true:
+  var ab: string
+  ab &= "more"
+
+  doAssert ab == "more"
+
+  var x: seq[string]
+
+  setLen(x, 7)
+
+  x.add "meh"
+
+  var s: string
+  var z = "abc"
+  var zz: string
+  s &= "foo" & z & zz
+
+  doAssert s == "fooabc"
+
+  echo x
+
+  # casting an empty string as sequence with shallow() should not segfault
+  var s2: string
+  when defined(gcRefc):
+    shallow(s2)
+  s2 &= "foo"
+  doAssert s2 == "foo"
+
diff --git a/tests/system/tnim_stacktrace_override.nim b/tests/system/tnim_stacktrace_override.nim
new file mode 100644
index 000000000..c75da9d9b
--- /dev/null
+++ b/tests/system/tnim_stacktrace_override.nim
@@ -0,0 +1,18 @@
+discard """
+  cmd: "nim c -d:nimStacktraceOverride $file"
+  output: '''begin
+Traceback (most recent call last, using override)
+Error: unhandled exception: stack trace produced [ValueError]
+'''
+  exitcode: 1
+"""
+
+import asyncfutures
+
+proc main =
+  echo "begin"
+  if true:
+    raise newException(ValueError, "stack trace produced")
+  echo "unreachable"
+
+main()
diff --git a/tests/system/tostring.nim b/tests/system/tostring.nim
new file mode 100644
index 000000000..bb6e453fb
--- /dev/null
+++ b/tests/system/tostring.nim
@@ -0,0 +1,125 @@
+doAssert "@[23, 45]" == $(@[23, 45])
+doAssert "[32, 45]" == $([32, 45])
+doAssert """@["", "foo", "bar"]""" == $(@["", "foo", "bar"])
+doAssert """["", "foo", "bar"]""" == $(["", "foo", "bar"])
+doAssert """["", "foo", "bar"]""" == $(@["", "foo", "bar"].toOpenArray(0, 2))
+
+# bug #2395
+let alphaSet: set[char] = {'a'..'c'}
+doAssert "{'a', 'b', 'c'}" == $alphaSet
+doAssert "2.3242" == $(2.3242)
+doAssert "2.982" == $(2.982)
+doAssert "123912.1" == $(123912.1)
+doAssert "123912.1823" == $(123912.1823)
+doAssert "5.0" == $(5.0)
+doAssert "1e+100" == $(1e100)
+doAssert "inf" == $(1e1000000)
+doAssert "-inf" == $(-1e1000000)
+doAssert "nan" == $(0.0/0.0)
+
+# nil tests
+# maybe a bit inconsistent in types
+var x: seq[string]
+doAssert "@[]" == $(x)
+
+var y: string
+doAssert "" == $(y)
+
+type
+  Foo = object
+    a: int
+    b: string
+
+var foo1: Foo
+
+# nil string should be an some point in time equal to the empty string
+doAssert(($foo1)[0..9] == "(a: 0, b: ")
+
+const
+  data = @['a','b', '\0', 'c','d']
+  dataStr = $data
+
+# ensure same result when on VM or when at program execution
+doAssert dataStr == $data
+
+import strutils
+# array test
+
+let arr = ['H','e','l','l','o',' ','W','o','r','l','d','!','\0']
+doAssert $arr == "['H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\\x00']"
+doAssert $cast[cstring](addr arr) == "Hello World!"
+
+proc takes(c: cstring) =
+  doAssert c == cstring""
+
+proc testm() =
+  var x: string
+  # nil is mapped to "":
+  takes(x)
+
+testm()
+
+# nil tests
+var xx: seq[string]
+var yy: string
+doAssert xx == @[]
+doAssert yy == ""
+
+proc bar(arg: cstring) =
+  doAssert arg[0] == '\0'
+
+proc baz(arg: openArray[char]) =
+  doAssert arg.len == 0
+
+proc stringCompare() =
+  var a,b,c,d,e,f,g: string
+  a.add 'a'
+  doAssert a == "a"
+  b.add "bee"
+  doAssert b == "bee"
+  b.add g
+  doAssert b == "bee"
+  c.addFloat 123.456
+  doAssert c == "123.456"
+  d.addInt 123456
+  doAssert d == "123456"
+
+  doAssert e == ""
+  doAssert "" == e
+  doAssert f == g
+  doAssert "" == ""
+
+  g.setLen(10)
+  doAssert g == "\0\0\0\0\0\0\0\0\0\0"
+  doAssert "" != "\0\0\0\0\0\0\0\0\0\0"
+
+  var nilstring: string
+  #bar(nilstring)
+  baz(nilstring)
+
+stringCompare()
+var nilstring: string
+bar(nilstring)
+
+static:
+  stringCompare()
+
+# issue #8847
+var a2: cstring = "fo\"o2"
+
+block:
+  var s: string
+  s.addQuoted a2
+  doAssert s == "\"fo\\\"o2\""
+
+# issue #16650
+template fn() =
+  doAssert len(cstring"ab\0c") == 5
+  doAssert len(cstring("ab\0c")) == 2
+  when nimvm:
+    discard
+  else:
+    let c = cstring("ab\0c")
+    doAssert len(c) == 2
+fn()
+static: fn()
diff --git a/tests/system/tparams.nim b/tests/system/tparams.nim
new file mode 100644
index 000000000..b20cfce1e
--- /dev/null
+++ b/tests/system/tparams.nim
@@ -0,0 +1,22 @@
+discard """
+joinable: false
+"""
+
+# not joinable because it executes itself with parameters
+import os
+import osproc
+import parseopt
+import sequtils
+
+let argv = commandLineParams()
+
+if argv == @[]:
+  # this won't work with spaces
+  doAssert execShellCmd(getAppFilename() & " \"foo bar\" --aa:bar=a --a=c:d --ab -c --a[baz]:doo") == 0
+else:
+  let f = toSeq(getopt())
+  doAssert f[0].kind == cmdArgument and f[0].key == "foo bar" and f[0].val == ""
+  doAssert f[1].kind == cmdLongOption and f[1].key == "aa" and f[1].val == "bar=a"
+  doAssert f[2].kind == cmdLongOption and f[2].key == "a" and f[2].val == "c:d"
+  doAssert f[3].kind == cmdLongOption and f[3].key == "ab" and f[3].val == ""
+  doAssert f[4].kind == cmdShortOption and f[4].key == "c" and f[4].val == ""
diff --git a/tests/system/trealloc.nim b/tests/system/trealloc.nim
new file mode 100644
index 000000000..1d3e00aff
--- /dev/null
+++ b/tests/system/trealloc.nim
@@ -0,0 +1,23 @@
+discard """
+  output: '''success'''
+  joinable: false
+  disabled: "openbsd"
+"""
+
+# bug #4818
+
+# Test that this completes without OOM.
+
+const BUFFER_SIZE = 5000
+var buffer = cast[ptr uint16](alloc(BUFFER_SIZE))
+
+var total_size: int64 = 0
+for i in 0 .. 1000:
+  let size = BUFFER_SIZE * i
+  #echo "requesting ", size
+  total_size += size.int64
+  buffer = cast[ptr uint16](realloc(buffer, size))
+  #echo totalSize, " total: ", getTotalMem(), " occupied: ", getOccupiedMem(), " free: ", getFreeMem()
+
+dealloc(buffer)
+echo "success"
diff --git a/tests/system/trefs.nim b/tests/system/trefs.nim
new file mode 100644
index 000000000..8c36aec52
--- /dev/null
+++ b/tests/system/trefs.nim
@@ -0,0 +1,15 @@
+discard """
+  targets: "c js"
+"""
+
+# bug #21317
+proc parseHook*(v: var ref int) =
+  var a: ref int
+  new(a)
+  a[] = 123
+  v = a
+
+proc fromJson2*(): ref int =
+  parseHook(result)
+
+doAssert fromJson2()[] == 123
diff --git a/tests/system/tsigexitcode.nim b/tests/system/tsigexitcode.nim
new file mode 100644
index 000000000..249256b40
--- /dev/null
+++ b/tests/system/tsigexitcode.nim
@@ -0,0 +1,23 @@
+discard """
+  joinable: false
+  disabled: windows
+"""
+
+import os, osproc, posix, strutils
+
+proc main() =
+  if paramCount() > 0:
+    let signal = cint parseInt paramStr(1)
+    discard posix.raise(signal)
+  else:
+    # synchronize this list with lib/system/except.nim:registerSignalHandler()
+    let sigs = [SIGINT, SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, SIGPIPE]
+    for s in sigs:
+      let (_, exitCode) = execCmdEx(quoteShellCommand [getAppFilename(), $s])
+      if s == SIGPIPE:
+        # SIGPIPE should be ignored
+        doAssert exitCode == 0, $(exitCode, s)
+      else:
+        doAssert exitCode == 128+s, $(exitCode, s)
+
+main()
diff --git a/tests/system/tslices.nim b/tests/system/tslices.nim
new file mode 100644
index 000000000..d0c68f8cb
--- /dev/null
+++ b/tests/system/tslices.nim
@@ -0,0 +1,65 @@
+discard """
+output: '''
+456456
+456456
+456456
+Zugr5nd
+egerichtetd
+verichtetd
+'''
+"""
+
+# Test the new slices.
+
+var mystr = "Abgrund"
+# mystr[..1] = "Zu" # deprecated
+mystr[0..1] = "Zu"
+
+mystr[4..4] = "5"
+
+type
+  TEnum = enum e1, e2, e3, e4, e5, e6
+
+var myarr: array[TEnum, int] = [1, 2, 3, 4, 5, 6]
+myarr[e1..e3] = myarr[e4..e6]
+# myarr[..e3] = myarr[e4..e6] # deprecated
+myarr[0..e3] = myarr[e4..e6]
+
+for x in items(myarr): stdout.write(x)
+echo()
+
+var myarr2: array[0..5, int] = [1, 2, 3, 4, 5, 6]
+myarr2[0..2] = myarr2[3..5]
+
+for x in items(myarr2): stdout.write(x)
+echo()
+
+
+var myseq = @[1, 2, 3, 4, 5, 6]
+myseq[0..2] = myseq[^3 .. ^1]
+
+for x in items(myseq): stdout.write(x)
+echo()
+
+echo mystr
+
+mystr[4..4] = "u"
+
+# test full replacement
+# mystr[.. ^2] = "egerichtet"  # deprecated
+mystr[0 .. ^2] = "egerichtet"
+
+echo mystr
+
+mystr[0..2] = "ve"
+echo mystr
+
+var s = "abcdef"
+s[1 .. ^2] = "xyz"
+assert s == "axyzf"
+
+# issue mentioned in PR #19219
+type Foo = distinct uint64
+# < here calls `pred` which used to cause a codegen error
+# `pred` compiles because distinct ordinals are considered ordinal
+const slice = 0 ..< 42.Foo
diff --git a/tests/system/tslimsystem.nim b/tests/system/tslimsystem.nim
new file mode 100644
index 000000000..4815306b5
--- /dev/null
+++ b/tests/system/tslimsystem.nim
@@ -0,0 +1,6 @@
+discard """
+  output: "123"
+  matrix: "-d:nimPreviewSlimSystem --mm:refc; -d:nimPreviewSlimSystem --mm:arc"
+"""
+
+echo 123
\ No newline at end of file
diff --git a/tests/system/tstatic.nim b/tests/system/tstatic.nim
new file mode 100644
index 000000000..6e2893e2b
--- /dev/null
+++ b/tests/system/tstatic.nim
@@ -0,0 +1,58 @@
+discard """
+  targets: "c cpp js"
+"""
+
+import std/strutils
+
+# bug #6133
+template main() =
+  block:
+    block:
+      proc foo(q: string, a: int): int =
+        result = q.len
+
+      proc foo(q: static[string]): int =
+        result = foo(q, 5)
+
+      doAssert foo("123") == 3
+
+    block:
+      type E = enum A
+
+      if false:
+        var e = A
+        discard $e
+
+      proc foo(a: string): int =
+        len(a) # 16640
+
+      proc foo(a: static[bool]): int {.used.} =
+        discard
+
+      doAssert foo("") == 0
+
+    block:
+      proc foo(a: string): int =
+        len(a)
+
+      proc foo(a: static[bool]): int {.used.} =
+        discard
+
+      doAssert foo("abc") == 3
+
+    block:
+      proc parseInt(f: static[bool]): int {.used.} = discard
+
+      doAssert "123".parseInt == 123
+  block:
+    type
+      MyType = object
+        field: float32
+      AType[T: static MyType] = distinct range[0f32 .. T.field]
+    var a: AType[MyType(field: 5f32)]
+    proc n(S: static Slice[int]): range[S.a..S.b] = discard
+    assert typeof(n 1..2) is range[1..2]
+
+
+static: main()
+main()
diff --git a/tests/system/tstatic_callable.nim b/tests/system/tstatic_callable.nim
new file mode 100644
index 000000000..92d1fca8d
--- /dev/null
+++ b/tests/system/tstatic_callable.nim
@@ -0,0 +1,12 @@
+# bug #16987
+
+proc getNum(a: int): int = a
+
+# Below calls "doAssert getNum(123) == 123" at compile time.
+static:
+  doAssert getNum(123) == 123
+
+# Below calls evaluate the "getNum(123)" at compile time, but the
+# results of those calls get used at run time.
+doAssert (static getNum(123)) == 123
+doAssert (static(getNum(123))) == 123
diff --git a/tests/system/tstatic_callable_error.nim b/tests/system/tstatic_callable_error.nim
new file mode 100644
index 000000000..c6f1e3d07
--- /dev/null
+++ b/tests/system/tstatic_callable_error.nim
@@ -0,0 +1,14 @@
+# bug #16987
+
+discard """
+errormsg: "cannot evaluate at compile time: inp"
+nimout: '''
+tstatic_callable_error.nim(14, 21) Error: cannot evaluate at compile time: inp'''
+"""
+
+
+# line 10
+proc getNum(a: int): int = a
+
+let inp = 123
+echo (static getNum(inp))
diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim
new file mode 100644
index 000000000..1debb7c48
--- /dev/null
+++ b/tests/system/tsystem_misc.nim
@@ -0,0 +1,227 @@
+discard """
+  output:'''1
+1
+2
+3
+11
+12
+13
+14
+15
+2
+3
+4
+2
+1
+2
+3
+2
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+2
+'''
+"""
+
+
+block:
+  const a2 = $(int)
+  const a3 = $int
+  doAssert a2 == "int"
+  doAssert a3 == "int"
+
+  proc fun[T: typedesc](t: T) =
+    const a2 = $(t)
+    const a3 = $t
+    doAssert a2 == "int"
+    doAssert a3 == "int"
+  fun(int)
+
+# check high/low implementations
+doAssert high(int) > low(int)
+doAssert high(int8) > low(int8)
+doAssert high(int16) > low(int16)
+doAssert high(int32) > low(int32)
+doAssert high(int64) > low(int64)
+# doAssert high(uint) > low(uint) # reconsider depending on issue #6620
+doAssert high(uint8) > low(uint8)
+doAssert high(uint16) > low(uint16)
+doAssert high(uint32) > low(uint32)
+# doAssert high(uint64) > low(uint64) # reconsider depending on issue #6620
+doAssert high(float) > low(float)
+doAssert high(float32) > low(float32)
+doAssert high(float64) > low(float64)
+
+proc foo(a: openArray[int]) =
+  for x in a: echo x
+
+foo(toOpenArray([1, 2, 3], 0, 0))
+
+foo(toOpenArray([1, 2, 3], 0, 2))
+
+var arr: array[8..12, int] = [11, 12, 13, 14, 15]
+
+foo(toOpenArray(arr, 8, 12))
+
+var seqq = @[1, 2, 3, 4, 5]
+foo(toOpenArray(seqq, 1, 3))
+
+# empty openArray issue #7904
+foo(toOpenArray(seqq, 0, -1))
+foo(toOpenArray(seqq, 1, 0))
+doAssertRaises(IndexDefect):
+  foo(toOpenArray(seqq, 0, -2))
+
+foo(toOpenArray(arr, 9, 8))
+foo(toOpenArray(arr, 0, -1))
+foo(toOpenArray(arr, 1, 0))
+doAssertRaises(IndexDefect):
+  foo(toOpenArray(arr, 10, 8))
+
+# test openArray of openArray
+proc oaEmpty(a: openArray[int]) =
+  foo(toOpenArray(a, 0, -1))
+
+proc oaFirstElm(a: openArray[int]) =
+  foo(toOpenArray(a, 0, 0))
+
+oaEmpty(toOpenArray(seqq, 0, -1))
+oaEmpty(toOpenArray(seqq, 1, 0))
+oaEmpty(toOpenArray(seqq, 1, 2))
+oaFirstElm(toOpenArray(seqq, 1, seqq.len-1))
+
+var arrNeg: array[-3 .. -1, int] = [1, 2, 3]
+foo(toOpenArray(arrNeg, -3, -1))
+foo(toOpenArray(arrNeg, 0, -1))
+foo(toOpenArray(arrNeg, -3, -4))
+doAssertRaises(IndexDefect):
+  foo(toOpenArray(arrNeg, -4, -1))
+doAssertRaises(IndexDefect):
+  foo(toOpenArray(arrNeg, -1, 0))
+doAssertRaises(IndexDefect):
+  foo(toOpenArray(arrNeg, -1, -3))
+doAssertRaises(Exception):
+  raise newException(Exception, "foo")
+
+block:
+  var didThrow = false
+  try:
+    doAssertRaises(IndexDefect): # should fail since it's wrong exception
+      raise newException(FieldDefect, "foo")
+  except AssertionDefect:
+    # ok, throwing was correct behavior
+    didThrow = true
+  doAssert didThrow
+
+type seqqType = ptr UncheckedArray[int]
+let qData = cast[seqqType](addr seqq[0])
+oaFirstElm(toOpenArray(qData, 1, 3))
+
+proc foo(a: openArray[byte]) =
+  for x in a: echo x
+
+let str = "0123456789"
+foo(toOpenArrayByte(str, 0, str.high))
+
+
+template boundedOpenArray[T](x: seq[T], first, last: int): openArray[T] =
+  toOpenarray(x, max(0, first), min(x.high, last))
+
+# bug #9281
+
+proc foo[T](x: openArray[T]) =
+  echo x.len
+
+let a = @[1, 2, 3]
+
+# a.boundedOpenArray(1, 2).foo()  # Works
+echo a.boundedOpenArray(1, 2).len # Internal compiler error
+
+block: # `$`*[T: tuple|object](x: T)
+  doAssert $(foo1:0, bar1:"a") == """(foo1: 0, bar1: "a")"""
+  doAssert $(foo1:0, ) == """(foo1: 0)"""
+  doAssert $(0, "a") == """(0, "a")"""
+  doAssert $(0, ) == "(0,)"
+  type Foo = object
+    x:int
+    x2:float
+  doAssert $Foo(x:2) == "(x: 2, x2: 0.0)"
+  doAssert $() == "()"
+
+# this is a call indirection to prevent `toInt` to be resolved at compile time.
+proc testToInt(arg: float64, a: int, b: BiggestInt) =
+  doAssert toInt(arg) == a
+  doAssert toBiggestInt(arg) == b
+
+testToInt(0.45, 0, 0)    # should round towards 0
+testToInt(-0.45, 0, 0)   # should round towards 0
+testToInt(0.5, 1, 1)     # should round away from 0
+testToInt(-0.5, -1, -1)  # should round away from 0
+testToInt(13.37, 13, 13)    # should round towards 0
+testToInt(-13.37, -13, -13) # should round towards 0
+testToInt(7.8, 8, 8)     # should round away from 0
+testToInt(-7.8, -8, -8)  # should round away from 0
+
+# test min/max for correct NaN handling
+
+proc testMinMax(a,b: float32) =
+  doAssert max(float32(a),float32(b)) == 0'f32
+  doAssert min(float32(a),float32(b)) == 0'f32
+  doAssert max(float64(a),float64(b)) == 0'f64
+  doAssert min(float64(a),float64(b)) == 0'f64
+
+testMinMax(0.0, NaN)
+testMinMax(NaN, 0.0)
+
+
+block:
+  type Foo = enum
+    k1, k2
+  var
+    a = {k1}
+    b = {k1,k2}
+  doAssert a < b
+
+
+block: # Ordinal
+  doAssert int is Ordinal
+  doAssert uint is Ordinal
+  doAssert int64 is Ordinal
+  doAssert uint64 is Ordinal
+  doAssert char is Ordinal
+  type Foo = enum k1, k2
+  doAssert Foo is Ordinal
+  doAssert Foo is SomeOrdinal
+  doAssert enum is SomeOrdinal
+
+  # these fail:
+  # doAssert enum is Ordinal # fails
+  # doAssert Ordinal is SomeOrdinal
+  # doAssert SomeOrdinal is Ordinal
+
+block:
+  proc p() = discard
+
+  doAssert not compiles(echo p.rawProc.repr)
+  doAssert not compiles(echo p.rawEnv.repr)
+  doAssert not compiles(echo p.finished)
+
+proc bug23223 = # bug #23223
+  var stuff = "hello"
+  stuff.insert ""
+  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/system/tuse_version16.nim b/tests/system/tuse_version16.nim
new file mode 100644
index 000000000..802b617ad
--- /dev/null
+++ b/tests/system/tuse_version16.nim
@@ -0,0 +1,49 @@
+discard """
+  matrix: "-d:NimMajor=1 -d:NimMinor=6 -d:NimPatch=100"
+"""
+
+{.warning[UnusedImport]: off.}
+
+import std/[
+  # Core:
+  bitops, typetraits, lenientops, macros, volatile,
+
+  # Algorithms:
+  algorithm, sequtils,
+
+  # Collections:
+  critbits, deques, heapqueue, intsets, lists, options, sets,
+  sharedlist, tables,
+
+  # Strings:
+  editdistance, wordwrap, parseutils, ropes,
+  pegs, strformat, strmisc, strscans, strtabs,
+  strutils, unicode, unidecode,
+
+  # Generic operator system services:
+  os, streams,
+
+  # Math libraries:
+  complex, math, mersenne, random, rationals, stats, sums,
+
+  # Internet protocols:
+  httpcore, mimetypes, uri,
+
+  # Parsers:
+  htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
+
+  # XML processing:
+  xmltree, xmlparser,
+
+  # Generators:
+  htmlgen,
+
+  # Hashing:
+  base64, hashes,
+
+  # Miscellaneous:
+  colors, sugar, varints,
+]
+
+
+doAssert NimVersion == "1.6.100"
diff --git a/tests/system/tvarargslen.nim b/tests/system/tvarargslen.nim
new file mode 100644
index 000000000..24b54a1e0
--- /dev/null
+++ b/tests/system/tvarargslen.nim
@@ -0,0 +1,60 @@
+discard """
+  output: '''
+tvarargslen.nim:35:2 (1, 2)
+tvarargslen.nim:36:2 12
+tvarargslen.nim:37:2 1
+tvarargslen.nim:38:8 
+done
+'''
+"""
+## line 10
+
+template myecho*(a: varargs[untyped]) =
+  ## shows a useful debugging echo-like proc that is dependency-free (no dependency
+  ## on macros.nim) so can be used in more contexts
+  const info = instantiationInfo(-1, false)
+  const loc = info.filename & ":" & $info.line & ":" & $info.column & " "
+  when varargsLen(a) > 0:
+    echo(loc, a)
+  else:
+    echo(loc)
+
+template fun*(a: varargs[untyped]): untyped =
+  varargsLen(a)
+
+template fun2*(a: varargs[typed]): untyped =
+  a.varargsLen
+
+template fun3*(a: varargs[int]): untyped =
+  a.varargsLen
+
+template fun4*(a: varargs[untyped]): untyped =
+  len(a)
+
+proc main()=
+  myecho (1, 2)
+  myecho 1, 2
+  myecho 1
+  myecho()
+
+  doAssert fun() == 0
+  doAssert fun('a') == 1
+  doAssert fun("asdf", 1) == 2
+
+  doAssert fun2() == 0
+  doAssert fun2('a') == 1
+  doAssert fun2("asdf", 1) == 2
+
+  doAssert fun3() == 0
+  doAssert fun3(10) == 1
+  doAssert fun3(10, 11) == 2
+
+  ## shows why `varargsLen` can't be named `len`
+  doAssert fun4("abcdef") == len("abcdef")
+
+  ## workaround for BUG:D20191218T171447 whereby if testament expected output ends
+  ## in space, testament strips it from expected output but not actual output,
+  ## which leads to a mismatch when running test via megatest
+  echo "done"
+
+main()
diff --git a/tests/tambsym3.nim b/tests/tambsym3.nim
deleted file mode 100755
index 96a5098c9..000000000
--- a/tests/tambsym3.nim
+++ /dev/null
@@ -1,8 +0,0 @@
-# Test ambiguous symbols

-

-import mambsym1, times

-

-var

-  v = mDec #ERROR_MSG ambiguous identifier

-

-writeln(stdout, ord(v))

diff --git a/tests/tarray.nim b/tests/tarray.nim
deleted file mode 100755
index 252cbd991..000000000
--- a/tests/tarray.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-# simple check for one dimensional arrays

-

-type

-  TMyArray = array[0..2, int]

-  TMyRecord = tuple[x, y: int]

-

-proc sum(a: TMyarray): int =

-  result = 0

-  var i = 0

-  while i < len(a):

-    inc(result, a[i])

-    inc(i)

-

-proc sum(a: openarray[int]): int =

-  result = 0

-  var i = 0

-  while i < len(a):

-    inc(result, a[i])

-    inc(i)

-

-proc getPos(r: TMyRecord): int =

-  result = r.x + r.y

-

-write(stdout, sum([1, 2, 3, 4]))

-write(stdout, sum([]))

-write(stdout, getPos( (x: 5, y: 7) ))

-#OUT 10012

diff --git a/tests/tarray2.nim b/tests/tarray2.nim
deleted file mode 100755
index eb0b75692..000000000
--- a/tests/tarray2.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# simple check for one dimensional arrays

-

-type

-  TMyArray = array[0..2, int]

-

-proc mul(a, b: TMyarray): TMyArray =

-  result = a
-  for i in 0..len(a)-1:
-    result[i] = a[i] * b[i]
-
-var
-  x, y, z: TMyArray
- 
-x = [ 4, 5, 6 ]
-y = x
-echo repr(mul(x, y))
-
-#OUT [16, 25, 36]

diff --git a/tests/tarrindx.nim b/tests/tarrindx.nim
deleted file mode 100755
index 13919cc2c..000000000
--- a/tests/tarrindx.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-# test another strange bug ... (I hate this compiler; it is much too buggy!)

-

-proc putEnv(key, val: string) =

-  # XXX: we have to leak memory here, as we cannot

-  # free it before the program ends (says Borland's

-  # documentation)

-  var

-    env: ptr array[0..500000, char]

-  env = cast[ptr array[0..500000, char]](alloc(len(key) + len(val) + 2))

-  for i in 0..len(key)-1: env[i] = key[i]

-  env[len(key)] = '='

-  for i in 0..len(val)-1:

-    env[len(key)+1+i] = val[i]

diff --git a/tests/tassert.nim b/tests/tassert.nim
deleted file mode 100755
index 1eff23502..000000000
--- a/tests/tassert.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-# test assert and exception handling

-

-proc callB() = assert(False)

-proc callA() = callB()

-proc callC() = callA()

-

-try:

-  callC()

-except EAssertionFailed:

-  write(stdout, "assertion failure!\n")

-except:

-  write(stdout, "unknown exception!\n")

-finally:

-  system.write(stdout, "this shall be always written\n")

-

-assert(false)

diff --git a/tests/tassign.nim b/tests/tassign.nim
deleted file mode 100755
index f51c20783..000000000
--- a/tests/tassign.nim
+++ /dev/null
@@ -1,31 +0,0 @@
-# Test the assignment operator for complex types which need RTTI

-

-type

-  TRec = object

-    x, y: int

-    s: string

-    seq: seq[string]

-    arr: seq[seq[array[0..3, string]]]

-  TRecSeq = seq[TRec]

-

-proc test() =

-  var

-    a, b: TRec

-  a.x = 1

-  a.y = 2

-  a.s = "Hallo!"

-  a.seq = @["abc", "def", "ghi", "jkl"]

-  a.arr = @[]

-  setLen(a.arr, 4)

-  a.arr[0] = @[]

-  a.arr[1] = @[]

-

-  b = a # perform a deep copy here!

-  b.seq = @["xyz", "huch", "was", "soll"]

-  writeln(stdout, len(a.seq))

-  writeln(stdout, a.seq[3])

-  writeln(stdout, len(b.seq))

-  writeln(stdout, b.seq[3])

-  writeln(stdout, b.y)

-

-test()

diff --git a/tests/tcasestm.nim b/tests/tcasestm.nim
deleted file mode 100755
index 16051ceb8..000000000
--- a/tests/tcasestm.nim
+++ /dev/null
@@ -1,32 +0,0 @@
-# Test the case statement
-
-type
-  tenum = enum eA, eB, eC
-
-var
-  x: string
-  y: Tenum = eA
-  i: int
-
-case y
-of eA: write(stdout, "a\n")
-of eB, eC: write(stdout, "b oder c\n")
-
-x = readLine(stdin)
-case x
-of "Andreas", "Rumpf": write(stdout, "Hallo Meister!\n")
-of "aa", "bb": write(stdout, "Du bist nicht mein Meister\n")
-of "cc", "hash", "when": nil
-of "will", "it", "finally", "be", "generated": nil
-else: write(stdout, "das sollte nicht passieren!\N")
-
-case i
-of 0..5, 8, 9: nil
-of 6, 7: nil
-elif x == "Ha": 
-  nil
-elif x == "Ho":
-  nil
-else:
-  nil
-
diff --git a/tests/tclosure.nim b/tests/tclosure.nim
deleted file mode 100755
index 399f68463..000000000
--- a/tests/tclosure.nim
+++ /dev/null
@@ -1,26 +0,0 @@
-# Test the closure implementation
-
-proc map(n: var openarray[int], fn: proc (x: int): int {.closure}) =
-  for i in 0..n.len-1: n[i] = fn(n[i])
-
-proc foldr(n: openarray[int], fn: proc (x, y: int): int {.closure}): int =
-  for i in 0..n.len-1:
-    result = fn(result, n[i])
-
-var
-  myData: array[0..4, int] = [0, 1, 2, 3, 4]
-
-proc testA() =
-  var p = 0
-  map(myData, lambda (x: int): int =
-                result = x + 1 shl (lambda (y: int): int =
-                  return y + p
-                )(0)
-                inc(p))
-
-testA()
-for x in items(myData):
-  write(stout, x)
-#OUT 2 4 6 8 10
-
-
diff --git a/tests/tcmdline.nim b/tests/tcmdline.nim
deleted file mode 100755
index f43aecafa..000000000
--- a/tests/tcmdline.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-# Test the command line
-
-import
-  os, strutils
-
-var
-  i: int
-  params = paramCount()
-i = 0
-writeln(stdout, "This exe: " & getApplicationFilename())
-writeln(stdout, "Number of parameters: " & $params)
-while i <= params:
-  writeln(stdout, paramStr(i))
-  i = i + 1
diff --git a/tests/tcopy.nim b/tests/tcopy.nim
deleted file mode 100755
index 81d72c7f2..000000000
--- a/tests/tcopy.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-# tests the copy proc

-

-import

-  strutils

-

-proc main() =

-  const

-    example = r"TEMP=C:\Programs\xyz\bin"

-  var

-    a, b: string

-    p: int

-  p = findSubStr("=", example)

-  a = copy(example, 0, p-1)

-  b = copy(example, p+1)

-  writeln(stdout, a & '=' & b)

-  #writeln(stdout, b)

-

-main()

-#OUT TEMP=C:\Programs\xyz\bin

diff --git a/tests/tcurrncy.nim b/tests/tcurrncy.nim
deleted file mode 100755
index fa08d620b..000000000
--- a/tests/tcurrncy.nim
+++ /dev/null
@@ -1,32 +0,0 @@
-template Additive(typ: typeDesc): stmt =
-  proc `+` *(x, y: typ): typ {.borrow.}
-  proc `-` *(x, y: typ): typ {.borrow.}
-  
-  # unary operators:
-  proc `+` *(x: typ): typ {.borrow.}
-  proc `-` *(x: typ): typ {.borrow.}
-
-template Multiplicative(typ, base: typeDesc): stmt =
-  proc `*` *(x: typ, y: base): typ {.borrow.}
-  proc `*` *(x: base, y: typ): typ {.borrow.}
-  proc `div` *(x: typ, y: base): typ {.borrow.}
-  proc `mod` *(x: typ, y: base): typ {.borrow.}
-
-template Comparable(typ: typeDesc): stmt =
-  proc `<` * (x, y: typ): bool {.borrow.}
-  proc `<=` * (x, y: typ): bool {.borrow.}
-  proc `==` * (x, y: typ): bool {.borrow.}
-
-template DefineCurrency(typ, base: expr): stmt =
-  type
-    typ* = distinct base
-  Additive(typ)
-  Multiplicative(typ, base)
-  Comparable(typ)
-  
-  proc `$` * (t: typ): string {.borrow.}
-
-DefineCurrency(TDollar, int)
-DefineCurrency(TEuro, int)
-echo($( 12.TDollar + 13.TDollar )) #OUT 25
-
diff --git a/tests/tdialogs.nim b/tests/tdialogs.nim
deleted file mode 100755
index 90f241cdf..000000000
--- a/tests/tdialogs.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-# Test the dialogs module
-
-import dialogs, gtk2
-
-gtk_nimrod_init()
-
-var x = ChooseFilesToOpen(nil)
-for a in items(x):
-  writeln(stdout, a)
-
-info(nil, "start with an info box")
-warning(nil, "now a warning ...")
-error(nil, "... and an error!")
-
-writeln(stdout, ChooseFileToOpen(nil))
-writeln(stdout, ChooseFileToSave(nil))
-writeln(stdout, ChooseDir(nil))
diff --git a/tests/techo.nim b/tests/techo.nim
deleted file mode 100755
index beb21fa16..000000000
--- a/tests/techo.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-# Simplest Nimrod program
-
-echo "Hallo, World!"
diff --git a/tests/template/annotate.nim b/tests/template/annotate.nim
new file mode 100644
index 000000000..a7e2f8fdb
--- /dev/null
+++ b/tests/template/annotate.nim
@@ -0,0 +1,113 @@
+import macros, parseutils
+
+# Generate tags
+macro make(names: untyped{nkBracket}): untyped =
+    result = newStmtList()
+
+    for i in 0 .. names.len-1:
+        result.add newProc(
+            name   = ident($names[i]).postfix("*"),
+            params = [
+                ident("string"),
+                newIdentDefs(
+                    ident("content"),
+                    ident("string")
+                )
+            ],
+            body = newStmtList(
+                parseStmt("reindent(content)")
+            )
+        )
+
+
+iterator lines(value: string): string =
+    var i = 0
+    while i < value.len:
+        var line: string
+        inc(i, value.parseUntil(line, 0x0A.char, i) + 1)
+        yield line
+
+
+proc reindent*(value: string, preset_indent = 0): string =
+    var indent = -1
+
+    # Detect indentation!
+    for ln in lines(value):
+        var read = ln.skipWhitespace()
+
+        # If the line is empty, ignore it for indentation
+        if read == ln.len: continue
+
+        indent = if indent < 0: read
+                 else: min(indent, read)
+
+    # Create a precursor indent as-needed
+    var precursor = newString(0)
+    for i in 1 .. preset_indent:
+        precursor.add(' ')
+
+    # Re-indent
+    result = newString(0)
+
+    for ln in lines(value):
+        var value = ln.substr(indent)
+
+        result.add(precursor)
+
+        if value.len > 0:
+            result.add(value)
+            result.add(0x0A.char)
+
+    return result
+
+
+#Define tags
+make([ html, xml, glsl, js, css, rst ])
+
+
+when isMainModule:
+    ## Test tags
+
+    const script = js"""
+        var x = 5;
+        console.log(x.toString());
+    """
+
+    const styles = css"""
+        .someRule {
+            width: 500px;
+        }
+    """
+
+    const body = html"""
+        <ul>
+            <li>1</li>
+            <li>2</li>
+            <li>
+                <a hef="#google">google</a>
+            </li>
+        </ul>
+    """
+
+    const info = xml"""
+        <item>
+            <i>1</i>
+            <i>2</i>
+        </item>
+    """
+
+    const shader = glsl"""
+        void main()
+        {
+            gl_Position = gl_ProjectionMatrix
+                        * gl_ModelViewMatrix
+                        * gl_Vertex;
+        }
+    """
+
+
+    echo script
+    echo styles
+    echo body
+    echo info
+    echo shader
diff --git a/tests/template/i2416.nim b/tests/template/i2416.nim
new file mode 100644
index 000000000..4b53cd0ca
--- /dev/null
+++ b/tests/template/i2416.nim
@@ -0,0 +1 @@
+template i2416*() = echo "i2416"
diff --git a/tests/template/m1027a.nim b/tests/template/m1027a.nim
new file mode 100644
index 000000000..fad915a2f
--- /dev/null
+++ b/tests/template/m1027a.nim
@@ -0,0 +1 @@
+const version_str* = "mod a"
diff --git a/tests/template/m1027b.nim b/tests/template/m1027b.nim
new file mode 100644
index 000000000..5ff0b9714
--- /dev/null
+++ b/tests/template/m1027b.nim
@@ -0,0 +1 @@
+const version_str* = "mod b"
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/mcan_access_hidden_field.nim b/tests/template/mcan_access_hidden_field.nim
new file mode 100644
index 000000000..2c0026ec1
--- /dev/null
+++ b/tests/template/mcan_access_hidden_field.nim
@@ -0,0 +1,8 @@
+
+type
+  Foo* = object
+    fooa, foob: int
+
+proc createFoo*(a, b: int): Foo = Foo(fooa: a, foob: b)
+
+template geta*(f: Foo): untyped = f.fooa
diff --git a/tests/template/mdotcall.nim b/tests/template/mdotcall.nim
new file mode 100644
index 000000000..fecd8ee26
--- /dev/null
+++ b/tests/template/mdotcall.nim
@@ -0,0 +1,82 @@
+# issue #20073
+
+type Foo = object
+proc foo(f: Foo) = discard
+
+template works*() =
+  var f: Foo
+  foo(f)
+
+template boom*() =
+  var f: Foo
+  f.foo() # Error: attempting to call undeclared routine: 'foo'
+  f.foo # Error: undeclared field: 'foo' for type a.Foo
+
+# issue #7085
+
+proc bar(a: string): string =
+  return a & "bar"
+
+template baz*(a: string): string =
+  var b = a.bar()
+  b
+
+# issue #7223
+
+import mdotcall2
+
+type
+  Bytes* = seq[byte]
+  
+  BytesRange* = object
+    bytes*: Bytes
+    ibegin*, iend*: int
+
+proc privateProc(r: BytesRange): int = r.ibegin
+
+template rangeBeginAddr*(r: BytesRange): pointer =
+  r.bytes.baseAddr.shift(r.privateProc)
+
+# issue #11733
+
+type ObjA* = object
+
+proc foo2(o: var ObjA) = discard
+proc bar2(o: var ObjA, arg: Natural) = discard
+
+template publicTemplateObjSyntax*(o: var ObjA, arg: Natural, doStuff: untyped) =
+  o.foo2()
+  doStuff
+  o.bar2(arg)
+
+# issue #15246
+import os
+
+template sourceBaseName*(): string =
+  bind splitFile
+  instantiationInfo().filename.splitFile().name
+
+# issue #12683
+
+import unicode
+template toRune(s: string): Rune = s.runeAt(0)
+proc heh*[T](x: Slice[T], chars: string) = discard chars.toRune
+
+# issue #7889
+
+from streams import newStringStream, readData, writeData
+
+template bindmeTemplate*(): untyped =
+  var tst = "sometext"
+  var ss = newStringStream("anothertext")
+  ss.writeData(tst[0].addr, 2)
+  discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful
+
+from macros import quote, newIdentNode
+
+macro bindmeQuote*(): untyped =
+  quote do:
+    var tst = "sometext"
+    var ss = newStringStream("anothertext")
+    ss.writeData(tst[0].addr, 2)
+    discard ss.readData(tst[0].addr, 2) # <= comment this out to make compilation successful
diff --git a/tests/template/mdotcall2.nim b/tests/template/mdotcall2.nim
new file mode 100644
index 000000000..e906ac9d6
--- /dev/null
+++ b/tests/template/mdotcall2.nim
@@ -0,0 +1,7 @@
+# imported by mdotcall
+
+proc baseAddr*[T](x: openarray[T]): pointer =
+  cast[pointer](x)
+
+proc shift*(p: pointer, delta: int): pointer =
+  cast[pointer](cast[int](p) + delta)
diff --git a/tests/template/mgensym_generic_cross_module.nim b/tests/template/mgensym_generic_cross_module.nim
new file mode 100644
index 000000000..ea88f67e6
--- /dev/null
+++ b/tests/template/mgensym_generic_cross_module.nim
@@ -0,0 +1,14 @@
+
+template makeDomElement(x: untyped, name: string = "") =
+  const tag {.gensym.} = if name.len == 0: astToStr(x) else: name
+
+  proc x*(p: int|float) =
+    echo tag, p
+
+  proc x*(p: string|cstring) =
+    echo tag, p
+
+#proc wrappedUp[T](x: T) =
+#  mixin foo, bar
+makeDomElement(foo, "foo")
+makeDomElement(bar)
diff --git a/tests/template/mlt.nim b/tests/template/mlt.nim
new file mode 100644
index 000000000..e567cf085
--- /dev/null
+++ b/tests/template/mlt.nim
@@ -0,0 +1,3 @@
+
+type Point* = ref object of RootObj
+proc `>`*(p1, p2: Point): bool = false
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/mtempl5.nim b/tests/template/mtempl5.nim
new file mode 100644
index 000000000..2cc6f91bc
--- /dev/null
+++ b/tests/template/mtempl5.nim
@@ -0,0 +1,24 @@
+
+var
+  gx = 88
+  gy = 44
+
+template templ*(): int =
+  bind gx, gy
+  gx + gy
+
+import json
+
+const
+  codeField = "foobar"
+  messageField = "more"
+
+template trap*(path: string, body: untyped): untyped =
+  #bind codeField, messageField
+  try:
+    body
+  except:
+    let msg = getCurrentExceptionMsg()
+    #debug "Error occurred within RPC ", path = path, errorMessage = msg
+    result = %*{codeField: "SERVER_ERROR", messageField: msg}
+
diff --git a/tests/template/otests.nim b/tests/template/otests.nim
new file mode 100644
index 000000000..9cb9d7fcb
--- /dev/null
+++ b/tests/template/otests.nim
@@ -0,0 +1,219 @@
+# Fields
+const x = 5
+
+
+# Test substring
+static:
+    assert "test".substring(3)   == "t"
+    assert "test".substring(2,1) == "s"
+    assert "test".substring(3,2) == "t"
+    assert "test".substring(1,2) == "es"
+
+
+# Various parsing tests
+when true:
+
+    block: #no_substitution
+        proc actual: string = tmpli html"""
+            <p>Test!</p>
+        """
+        const expected = html"""
+            <p>Test!</p>
+        """
+        doAssert actual() == expected
+
+    block: #basic
+        proc actual: string = tmpli html"""
+            <p>Test $$x</p>
+            $x
+        """
+        const expected = html"""
+            <p>Test $x</p>
+            5
+        """
+        doAssert actual() == expected
+
+    block: #expression
+        proc actual: string = tmpli html"""
+            <p>Test $$(x * 5)</p>
+            $(x * 5)
+        """
+        const expected = html"""
+            <p>Test $(x * 5)</p>
+            25
+        """
+        doAssert actual() == expected
+
+    block: #escape
+        proc actual: string = tmpli js"""
+            [{
+                "hello world"
+            }]
+        """
+        const expected = js"""
+            [{
+                "hello world"
+            }]
+        """
+        doAssert actual() == expected
+
+    block: #forIn
+        proc actual: string = tmpli html"""
+            <p>Test for</p>
+            <ul>
+                $for y in 0..2 {
+                    <li>$y</li>
+                }
+            </ul>
+        """
+        const expected = html"""
+            <p>Test for</p>
+            <ul>
+                <li>0</li>
+                <li>1</li>
+                <li>2</li>
+            </ul>
+        """
+        doAssert actual() == expected
+
+    block: #while
+        proc actual: string = tmpli html"""
+            <p>Test while/stmt</p>
+            <ul>
+                ${ var y = 0 }
+                $while y < 4 {
+                    <li>$y</li>
+                    ${ inc(y) }
+                }
+            </ul>
+        """
+        const expected = html"""
+            <p>Test while/stmt</p>
+            <ul>
+                <li>0</li>
+                <li>1</li>
+                <li>2</li>
+                <li>3</li>
+            </ul>
+        """
+        doAssert actual() == expected
+
+    block: #ifElifElse
+        proc actual: string = tmpli html"""
+            <p>Test if/elif/else</p>
+            $if x == 8 {
+                <div>x is 8!</div>
+            }
+            $elif x == 7 {
+                <div>x is 7!</div>
+            }
+            $else {
+                <div>x is neither!</div>
+            }
+        """
+        const expected = html"""
+            <p>Test if/elif/else</p>
+            <div>x is neither!</div>
+        """
+        doAssert actual() == expected
+
+    block: #multiLineStatements
+        proc actual: string = tmpli html"""
+            <p>Test multiline statements</p>
+            ${
+                var x = 5
+                var y = 7
+            }
+            <span>$x</span><span>$y</span>
+        """
+        const expected = html"""
+            <p>Test multiline statements</p>
+            <span>5</span><span>7</span>
+        """
+        doAssert actual() == expected
+
+    block: #caseOfElse
+        proc actual: string = tmpli html"""
+            <p>Test case</p>
+            $case x
+            $of 5 {
+                <div>x == 5</div>
+            }
+            $of 6 {
+                <div>x == 6</div>
+            }
+            $else {}
+        """
+        const expected = html"""
+            <p>Test case</p>
+            <div>x == 5</div>
+        """
+        doAssert actual() == expected
+
+
+
+when true: #embeddingTest
+    proc no_substitution: string = tmpli html"""
+        <h1>Template test!</h1>
+    """
+
+    # # Single variable substitution
+    proc substitution(who = "nobody"): string = tmpli html"""
+        <div id="greeting">hello $who!</div>
+    """
+
+    # Expression template
+    proc test_expression(nums: openArray[int] = []): string =
+        var i = 2
+        tmpli html"""
+            $(no_substitution())
+            $(substitution("Billy"))
+            <div id="age">Age: $($nums[i] & "!!")</div>
+        """
+
+    proc test_statements(nums: openArray[int] = []): string =
+        tmpli html"""
+            $(test_expression(nums))
+            $if true {
+                <ul>
+                    $for i in nums {
+                        <li>$(i * 2)</li>
+                    }
+                </ul>
+            }
+        """
+
+    var actual = test_statements([0,1,2])
+    const expected = html"""
+        <h1>Template test!</h1>
+        <div id="greeting">hello Billy!</div>
+        <div id="age">Age: 2!!</div>
+        <ul>
+            <li>0</li>
+            <li>2</li>
+            <li>4</li>
+        </ul>
+    """
+    doAssert actual == expected
+
+
+when defined(future):
+    block: #tryCatch
+        proc actual: string = tmpli html"""
+            <p>Test try/catch</p>
+            <div>
+                $try {
+                    <div>Lets try this!</div>
+                }
+                $except {
+                    <div>Uh oh!</div>
+                }
+            </div>
+        """
+        const expected = html"""
+            <p>Test try/catch</p>
+            <div>
+                    <div>Lets try this!</div>
+            </div>
+        """
+        doAssert actual() == expected
diff --git a/tests/sunset.tmpl b/tests/template/sunset.nimf
index 08fa50f56..bd57bb8e1 100755..100644
--- a/tests/sunset.tmpl
+++ b/tests/template/sunset.nimf
@@ -1,5 +1,6 @@
+#? stdtmpl
 #proc sunsetTemplate*(current, ticker, content: string,
-#                     tabs: openarray[array[0..1, string]]): string = 
+#                     tabs: openArray[array[0..1, string]]): string = 
 #  result = ""
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
diff --git a/tests/template/t1027.nim b/tests/template/t1027.nim
new file mode 100644
index 000000000..fe03c4ea9
--- /dev/null
+++ b/tests/template/t1027.nim
@@ -0,0 +1,22 @@
+discard """
+  cmd: "nim check --hints:off $file"
+  errormsg: ""
+  nimout: '''
+t1027.nim(20, 19) Error: ambiguous identifier: 'version_str' -- use one of the following:
+  m1027a.version_str: string
+  m1027b.version_str: string
+'''
+"""
+
+
+
+
+
+
+import m1027a, m1027b
+
+# bug #1027
+template wrap_me(stuff): untyped =
+  echo "Using " & version_str
+
+wrap_me("hey")
diff --git a/tests/template/t11705.nim b/tests/template/t11705.nim
new file mode 100644
index 000000000..65ddc7e6c
--- /dev/null
+++ b/tests/template/t11705.nim
@@ -0,0 +1,17 @@
+type RefObj = ref object
+
+proc `[]`(val: static[int]) = # works with different name/overload or without static arg
+  discard
+
+template noRef*(T: typedesc): typedesc = # works without template indirection
+  typeof(default(T)[])
+
+proc `=destroy`(x: var noRef(RefObj)) =
+  discard
+
+proc foo =
+  var x = new RefObj
+  doAssert $(x[]) == "()"
+
+# bug #11705
+foo()
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/t17433.nim b/tests/template/t17433.nim
new file mode 100644
index 000000000..053d33ff0
--- /dev/null
+++ b/tests/template/t17433.nim
@@ -0,0 +1,16 @@
+# Inside template bodies, ensure return types referencing a param are replaced.
+# This helps guarantee that return parameter analysis happens after argument
+# analysis.
+ 
+# bug #17433
+
+from std/macros import expandMacros
+
+proc bar(a: typedesc): a = default(a)
+doAssert bar(float) == 0.0
+doAssert bar(string) == ""
+
+template main =
+  proc baz(a: typedesc): a = default(a)
+  doAssert baz(float) == 0.0
+main()
diff --git a/tests/template/t18113.nim b/tests/template/t18113.nim
new file mode 100644
index 000000000..a84b3fd0e
--- /dev/null
+++ b/tests/template/t18113.nim
@@ -0,0 +1,14 @@
+# ensure template pragma handling doesn't eagerly attempt to add an implicit
+# 'pushed' pragma to the evaluation of any intermediate AST prior to
+# substitution.
+ 
+# bug #18113
+
+import sequtils
+
+{.push raises: [Defect].}
+
+var a = toSeq([1, 2, 3, 5, 10]).filterIt(it > 5)
+
+doAssert a.len == 1
+doAssert a[0] == 10
diff --git a/tests/template/t19149.nim b/tests/template/t19149.nim
new file mode 100644
index 000000000..631e8fc30
--- /dev/null
+++ b/tests/template/t19149.nim
@@ -0,0 +1,19 @@
+type Foo = tuple[active: bool, index: int]
+
+
+var f: Foo
+
+# template result type during match stage
+# f:var Foo
+# a:Foo
+# tyVar
+# tyTuple
+# after change to proc
+# f:Foo
+# a:Foo
+# tyTuple
+# tyTuple
+
+template cursor(): var Foo = f
+discard cursor()
+
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/t19700.nim b/tests/template/t19700.nim
new file mode 100644
index 000000000..cc2944944
--- /dev/null
+++ b/tests/template/t19700.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "type mismatch: got <Obj, Obj, template (x: untyped, y: untyped): untyped>"
+"""
+
+type Obj = object
+
+proc apply[T, R](a, b: T; f: proc(x, y: T): R): R = f(a, b)
+
+let a, b = Obj()
+discard apply(a, b, `!=`)
diff --git a/tests/template/t21231.nim b/tests/template/t21231.nim
new file mode 100644
index 000000000..51e96cdd6
--- /dev/null
+++ b/tests/template/t21231.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "undeclared identifier: 'x'"
+"""
+
+var x: int
+# bug #21231
+template f(y: untyped) = echo y.x
+for i in 1 .. 10:
+  x = i
+  f(system)
diff --git a/tests/template/t21532.nim b/tests/template/t21532.nim
new file mode 100644
index 000000000..3193b0dc3
--- /dev/null
+++ b/tests/template/t21532.nim
@@ -0,0 +1,8 @@
+
+template elementType(a: untyped): typedesc =
+  typeof(block: (for ai in a: ai))
+
+func fn[T](a: T) =
+  doAssert elementType(a) is int
+
+@[1,2,3].fn
\ No newline at end of file
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/t6217.nim b/tests/template/t6217.nim
new file mode 100644
index 000000000..b27b61881
--- /dev/null
+++ b/tests/template/t6217.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''
+start
+side effect!
+end
+'''
+"""
+
+# bug #6217
+
+template optMul{`*`(a, 2)}(a: int{noSideEffect}): int = a+a
+
+proc f(): int =
+  echo "side effect!"
+  result = 55
+
+echo "start"
+doAssert f() * 2 == 110
+echo "end"
diff --git a/tests/template/t9534.nim b/tests/template/t9534.nim
new file mode 100644
index 000000000..8d66f42a0
--- /dev/null
+++ b/tests/template/t9534.nim
@@ -0,0 +1,21 @@
+discard """
+  targets: "c cpp"
+"""
+
+# bug #9534
+type
+  Object = object
+    data: int
+
+template test() =
+  proc methodName(o: Object): int =
+    var p: pointer
+    doAssert o.data == 521
+    let f {.used.} = cast[proc (o: int): int {.nimcall.}](p)
+    doAssert o.data == 521
+    result = 1314
+
+  var a = Object(data: 521)
+  doAssert methodName(a) == 1314
+
+test()
diff --git a/tests/template/t_otemplates.nim b/tests/template/t_otemplates.nim
new file mode 100644
index 000000000..b278bea0f
--- /dev/null
+++ b/tests/template/t_otemplates.nim
@@ -0,0 +1,345 @@
+discard """
+  output: "Success"
+"""
+
+# Ref:
+# http://nim-lang.org/macros.html
+# http://nim-lang.org/parseutils.html
+
+
+# Imports
+import tables, parseutils, macros, strutils
+import annotate
+export annotate
+
+
+# Fields
+const identChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
+
+
+# Procedure Declarations
+proc parse_template(node: NimNode, value: string) {.compiletime.}
+
+
+# Procedure Definitions
+proc substring(value: string, index: int, length = -1): string {.compiletime.} =
+    ## Returns a string at most `length` characters long, starting at `index`.
+    return if length < 0:    value.substr(index)
+           elif length == 0: ""
+           else:             value.substr(index, index + length-1)
+
+
+proc parse_thru_eol(value: string, index: int): int {.compiletime.} =
+    ## Reads until and past the end of the current line, unless
+    ## a non-whitespace character is encountered first
+    var remainder: string
+    var read = value.parseUntil(remainder, {0x0A.char}, index)
+    if remainder.skipWhitespace() == read:
+        return read + 1
+
+
+proc trim_after_eol(value: var string) {.compiletime.} =
+    ## Trims any whitespace at end after \n
+    var toTrim = 0
+    for i in countdown(value.len-1, 0):
+        # If \n, return
+        if value[i] in [' ', '\t']: inc(toTrim)
+        else: break
+
+    if toTrim > 0:
+        value = value.substring(0, value.len - toTrim)
+
+
+proc trim_eol(value: var string) {.compiletime.} =
+    ## Removes everything after the last line if it contains nothing but whitespace
+    for i in countdown(value.len - 1, 0):
+        # If \n, trim and return
+        if value[i] == 0x0A.char:
+            value = value.substr(0, i)
+            break
+
+        # This is the first character
+        if i == 0:
+            value = ""
+            break
+
+        # Skip change
+        if not (value[i] in [' ', '\t']): break
+
+
+proc detect_indent(value: string, index: int): int {.compiletime.} =
+    ## Detects how indented the line at `index` is.
+    # Seek to the beginning of the line.
+    var lastChar = index
+    for i in countdown(index, 0):
+        if value[i] == 0x0A.char:
+            # if \n, return the indentation level
+            return lastChar - i
+        elif not (value[i] in [' ', '\t']):
+            # if non-whitespace char, decrement lastChar
+            dec(lastChar)
+
+
+proc parse_thru_string(value: string, i: var int, strType = '"') {.compiletime.} =
+    ## Parses until ending " or ' is reached.
+    inc(i)
+    if i < value.len-1:
+        inc(i, value.skipUntil({'\\', strType}, i))
+
+
+proc parse_to_close(value: string, index: int, open='(', close=')', opened=0): int {.compiletime.} =
+    ## Reads until all opened braces are closed
+    ## ignoring any strings "" or ''
+    var remainder   = value.substring(index)
+    var open_braces = opened
+    result = 0
+
+    while result < remainder.len:
+        var c = remainder[result]
+
+        if   c == open:  inc(open_braces)
+        elif c == close: dec(open_braces)
+        elif c == '"':   remainder.parse_thru_string(result)
+        elif c == '\'':  remainder.parse_thru_string(result, '\'')
+
+        if open_braces == 0: break
+        else: inc(result)
+
+
+iterator parse_stmt_list(value: string, index: var int): string =
+    ## Parses unguided ${..} block
+    var read        = value.parse_to_close(index, open='{', close='}')
+    var expressions = value.substring(index + 1, read - 1).split({ ';', 0x0A.char })
+
+    for expression in expressions:
+        let value = expression.strip
+        if value.len > 0:
+            yield value
+
+    #Increment index & parse thru EOL
+    inc(index, read + 1)
+    inc(index, value.parse_thru_eol(index))
+
+
+iterator parse_compound_statements(value, identifier: string, index: int): string =
+    ## Parses through several statements, i.e. if {} elif {} else {}
+    ## and returns the initialization of each as an empty statement
+    ## i.e. if x == 5 { ... } becomes if x == 5: nil.
+
+    template get_next_ident(expected) =
+        var nextIdent: string
+        discard value.parseWhile(nextIdent, {'$'} + identChars, i)
+
+        var next: string
+        var read: int
+
+        if nextIdent == "case":
+            # We have to handle case a bit differently
+            read = value.parseUntil(next, '$', i)
+            inc(i, read)
+            yield next.strip(leading=false) & "\n"
+
+        else:
+            read = value.parseUntil(next, '{', i)
+
+            if nextIdent in expected:
+                inc(i, read)
+                # Parse until closing }, then skip whitespace afterwards
+                read = value.parse_to_close(i, open='{', close='}')
+                inc(i, read + 1)
+                inc(i, value.skipWhitespace(i))
+                yield next & ": nil\n"
+
+            else: break
+
+
+    var i = index
+    while true:
+        # Check if next statement would be valid, given the identifier
+        if identifier in ["if", "when"]:
+            get_next_ident([identifier, "$elif", "$else"])
+
+        elif identifier == "case":
+            get_next_ident(["case", "$of", "$elif", "$else"])
+
+        elif identifier == "try":
+            get_next_ident(["try", "$except", "$finally"])
+
+
+proc parse_complex_stmt(value, identifier: string, index: var int): NimNode {.compiletime.} =
+    ## Parses if/when/try /elif /else /except /finally statements
+
+    # Build up complex statement string
+    var stmtString = newString(0)
+    var numStatements = 0
+    for statement in value.parse_compound_statements(identifier, index):
+        if statement[0] == '$': stmtString.add(statement.substr(1))
+        else:                   stmtString.add(statement)
+        inc(numStatements)
+
+    # Parse stmt string
+    result = parseExpr(stmtString)
+
+    var resultIndex = 0
+
+    # Fast forward a bit if this is a case statement
+    if identifier == "case":
+        inc(resultIndex)
+
+    while resultIndex < numStatements:
+
+        # Detect indentation
+        let indent = detect_indent(value, index)
+
+        # Parse until an open brace `{`
+        var read = value.skipUntil('{', index)
+        inc(index, read + 1)
+
+        # Parse through EOL
+        inc(index, value.parse_thru_eol(index))
+
+        # Parse through { .. }
+        read = value.parse_to_close(index, open='{', close='}', opened=1)
+
+        # Add parsed sub-expression into body
+        var body       = newStmtList()
+        var stmtString = value.substring(index, read)
+        trim_after_eol(stmtString)
+        stmtString = reindent(stmtString, indent)
+        parse_template(body, stmtString)
+        inc(index, read + 1)
+
+        # Insert body into result
+        var stmtIndex = result[resultIndex].len-1
+        result[resultIndex][stmtIndex] = body
+
+        # Parse through EOL again & increment result index
+        inc(index, value.parse_thru_eol(index))
+        inc(resultIndex)
+
+
+proc parse_simple_statement(value: string, index: var int): NimNode {.compiletime.} =
+    ## Parses for/while
+
+    # Detect indentation
+    let indent = detect_indent(value, index)
+
+    # Parse until an open brace `{`
+    var splitValue: string
+    var read = value.parseUntil(splitValue, '{', index)
+    result   = parseExpr(splitValue & ":nil")
+    inc(index, read + 1)
+
+    # Parse through EOL
+    inc(index, value.parse_thru_eol(index))
+
+    # Parse through { .. }
+    read = value.parse_to_close(index, open='{', close='}', opened=1)
+
+    # Add parsed sub-expression into body
+    var body       = newStmtList()
+    var stmtString = value.substring(index, read)
+    trim_after_eol(stmtString)
+    stmtString = reindent(stmtString, indent)
+    parse_template(body, stmtString)
+    inc(index, read + 1)
+
+    # Insert body into result
+    var stmtIndex = result.len-1
+    result[stmtIndex] = body
+
+    # Parse through EOL again
+    inc(index, value.parse_thru_eol(index))
+
+
+proc parse_until_symbol(node: NimNode, value: string, index: var int): bool {.compiletime.} =
+    ## Parses a string until a $ symbol is encountered, if
+    ## two $$'s are encountered in a row, a split will happen
+    ## removing one of the $'s from the resulting output
+    var splitValue: string
+    var read = value.parseUntil(splitValue, '$', index)
+    var insertionPoint = node.len
+
+    inc(index, read + 1)
+    if index < value.len:
+
+        case value[index]
+        of '$':
+            # Check for duplicate `$`, meaning this is an escaped $
+            node.add newCall("add", ident("result"), newStrLitNode("$"))
+            inc(index)
+
+        of '(':
+            # Check for open `(`, which means parse as simple single-line expression.
+            trim_eol(splitValue)
+            read = value.parse_to_close(index) + 1
+            node.add newCall("add", ident("result"),
+                newCall(bindSym"strip", parseExpr("$" & value.substring(index, read)))
+            )
+            inc(index, read)
+
+        of '{':
+            # Check for open `{`, which means open statement list
+            trim_eol(splitValue)
+            for s in value.parse_stmt_list(index):
+                node.add parseExpr(s)
+
+        else:
+            # Otherwise parse while valid `identChars` and make expression w/ $
+            var identifier: string
+            read = value.parseWhile(identifier, identChars, index)
+
+            if identifier in ["for", "while"]:
+                ## for/while means open simple statement
+                trim_eol(splitValue)
+                node.add value.parse_simple_statement(index)
+
+            elif identifier in ["if", "when", "case", "try"]:
+                ## if/when/case/try means complex statement
+                trim_eol(splitValue)
+                node.add value.parse_complex_stmt(identifier, index)
+
+            elif identifier.len > 0:
+                ## Treat as simple variable
+                node.add newCall("add", ident("result"), newCall("$", ident(identifier)))
+                inc(index, read)
+
+        result = true
+
+    # Insert
+    if splitValue.len > 0:
+        node.insert insertionPoint, newCall("add", ident("result"), newStrLitNode(splitValue))
+
+
+proc parse_template(node: NimNode, value: string) =
+    ## Parses through entire template, outputting valid
+    ## Nim code into the input `node` AST.
+    var index = 0
+    while index < value.len and
+          parse_until_symbol(node, value, index): discard
+
+
+macro tmpli*(body: untyped): untyped =
+    result = newStmtList()
+
+    result.add parseExpr("result = \"\"")
+
+    var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal
+                else: body[1].strVal
+
+    parse_template(result, reindent(value))
+
+
+macro tmpl*(body: untyped): untyped =
+    result = newStmtList()
+
+    var value = if body.kind in nnkStrLit..nnkTripleStrLit: body.strVal
+                else: body[1].strVal
+
+    parse_template(result, reindent(value))
+
+
+# Run tests
+when true:
+    include otests
+    echo "Success"
diff --git a/tests/template/taliassyntax.nim b/tests/template/taliassyntax.nim
new file mode 100644
index 000000000..2d8237d93
--- /dev/null
+++ b/tests/template/taliassyntax.nim
@@ -0,0 +1,74 @@
+type Foo = object
+  bar: int
+
+var foo = Foo(bar: 10)
+template bar: int = foo.bar
+doAssert bar == 10
+bar = 15
+doAssert bar == 15
+var foo2 = Foo(bar: -10)
+doAssert bar == 15
+# works in generics
+proc genericProc[T](x: T): string =
+  $(x, bar)
+doAssert genericProc(true) == "(true, 15)"
+# redefine
+template bar: int {.redefine.} = foo2.bar
+doAssert bar == -10
+
+block: # subscript
+  var bazVal = @[1, 2, 3]
+  template baz: seq[int] = bazVal
+  doAssert baz[1] == 2
+  proc genericProc2[T](x: T): string =
+    result = $(x, baz[1])
+    baz[1] = 7
+  doAssert genericProc2(true) == "(true, 2)"
+  doAssert baz[1] == 7
+  baz[1] = 14
+  doAssert baz[1] == 14
+
+block: # type alias
+  template Int2: untyped = int
+  let x: Int2 = 123
+  proc generic[T](): string =
+    template U: untyped = T
+    var x: U
+    result = $typeof(x)
+    doAssert result == $U
+    doAssert result == $T
+  doAssert generic[int]() == "int"
+  doAssert generic[Int2]() == "int"
+  doAssert generic[string]() == "string"
+  doAssert generic[seq[int]]() == "seq[int]"
+  doAssert generic[seq[Int2]]() == "seq[int]"
+  discard generic[123]()
+  proc genericStatic[X; T: static[X]](): string =
+    template U: untyped = T
+    result = $U
+    doAssert result == $T
+  doAssert genericStatic[int, 123]() == "123"
+  doAssert genericStatic[Int2, 123]() == "123"
+  doAssert genericStatic[(string, bool), ("a", true)]() == "(\"a\", true)"
+
+block: # issue #13515
+  template test: bool = true
+  # compiles:
+  if not test:
+    doAssert false
+  # does not compile:
+  template x =
+    if not test:
+      doAssert false
+  x
+
+import macros
+
+block: # issue #21727
+  template debugAnnotation(s: typed): string =
+    astToStr s
+
+  macro cpsJump(x: int): untyped =
+    result = newLit(debugAnnotation(cpsJump))
+  
+  doAssert cpsJump(13) == "cpsJump"
diff --git a/tests/template/taliassyntaxerrors.nim b/tests/template/taliassyntaxerrors.nim
new file mode 100644
index 000000000..f16acaf91
--- /dev/null
+++ b/tests/template/taliassyntaxerrors.nim
@@ -0,0 +1,28 @@
+discard """
+  cmd: "nim check --hints:off $file"
+"""
+
+block: # with params
+  type Foo = object
+    bar: int
+
+  var foo = Foo(bar: 10)
+  template bar(x: int): int = x + foo.bar
+  let a = bar #[tt.Error
+      ^ invalid type: 'template (x: int): int' for let. Did you mean to call the template with '()'?]#
+  bar = 15 #[tt.Error
+  ^ 'bar' cannot be assigned to]#
+
+block: # generic template
+  type Foo = object
+    bar: int
+
+  var foo = Foo(bar: 10)
+  template bar[T]: T = T(foo.bar)
+  let a = bar #[tt.Error
+      ^ invalid type: 'template (): T' for let. Did you mean to call the template with '()'?; tt.Error
+          ^ 'bar' has unspecified generic parameters]#
+  let b = bar[float]()
+  doAssert b == 10.0
+  bar = 15 #[tt.Error
+  ^ 'bar' cannot be assigned to]#
diff --git a/tests/template/tcallsitelineinfo.nim b/tests/template/tcallsitelineinfo.nim
new file mode 100644
index 000000000..5fed93363
--- /dev/null
+++ b/tests/template/tcallsitelineinfo.nim
@@ -0,0 +1,17 @@
+discard """
+  nimout: '''
+tcallsitelineinfo.nim(17, 4) Warning: abc [User]
+'''
+  exitcode: 1
+  outputsub: '''
+tcallsitelineinfo.nim(17) tcallsitelineinfo
+Error: unhandled exception: def [ValueError]
+'''
+"""
+
+template foo(): untyped {.callsite.} =
+  {.warning: "abc".}
+  raise newException(ValueError, "def")
+  echo "hello"
+
+foo()
diff --git a/tests/template/tcallsitelineinfo2.nim b/tests/template/tcallsitelineinfo2.nim
new file mode 100644
index 000000000..d5f257474
--- /dev/null
+++ b/tests/template/tcallsitelineinfo2.nim
@@ -0,0 +1,20 @@
+discard """
+  nimout: '''
+tcallsitelineinfo2.nim(18, 1) Warning: abc [User]
+tcallsitelineinfo2.nim(19, 12) Warning: def [User]
+'''
+  exitcode: 1
+  outputsub: '''
+tcallsitelineinfo2.nim(20) tcallsitelineinfo2
+Error: unhandled exception: ghi [ValueError]
+'''
+"""
+
+template foo(a: untyped): untyped {.callsite.} =
+  {.warning: "abc".}
+  a
+  echo "hello"
+
+foo: # with `{.line.}:`, the following do not keep their line information:
+  {.warning: "def".}
+  raise newException(ValueError, "ghi")
diff --git a/tests/template/tconfusinglocal.nim b/tests/template/tconfusinglocal.nim
new file mode 100644
index 000000000..9f641e2bf
--- /dev/null
+++ b/tests/template/tconfusinglocal.nim
@@ -0,0 +1,21 @@
+discard """
+output: "0"
+"""
+
+
+# bug #5135
+proc fail*[E](e: E): void =
+  raise newException(Exception, e)
+
+# bug #4875
+type Bar = object
+    mFoo: int
+
+template foo(a: Bar): int = a.mFoo
+
+proc main =
+    let foo = 5 # Rename this to smth else to make it work
+    var b: Bar
+    echo b.foo
+
+main()
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/tdefined_overload.nim b/tests/template/tdefined_overload.nim
new file mode 100644
index 000000000..bcc83e414
--- /dev/null
+++ b/tests/template/tdefined_overload.nim
@@ -0,0 +1,46 @@
+discard """
+  output: "Valid and not defined"
+"""
+# test for issue #7997
+# checking for `when not defined` in a template for some compile time symbol
+# results in a compilation error of:
+# Error: obsolete usage of 'defined', use 'declared' instead
+# if the symbol is 'overloaded' by some variable or procedure, because in
+# that case the argument of `defined` is of kind `nkSym` instead of `nkIdent`
+# (for which was checked in `semexprs.semDefined`).
+
+block:
+  # check whether a proc with the same name as the argument to `defined`
+  # compiles
+  proc overloaded() =
+    discard
+
+  template definedCheck(): untyped =
+    when not defined(overloaded): true
+    else: false
+  doAssert definedCheck == true
+
+block:
+  # check whether a variable with the same name as the argument to `defined`
+  # compiles
+  var overloaded: int
+
+  template definedCheck(): untyped =
+    when not defined(overloaded): true
+    else: false
+  doAssert definedCheck == true
+
+block:
+  # check whether a non overloaded when check still works properly
+  when not defined(validIdentifier):
+    echo "Valid and not defined"
+
+block:
+  # now check that invalid identifiers cause a compilation error
+  # by using reject template.
+  template reject(b) =
+    static: doAssert(not compiles(b))
+
+  reject:
+    when defined(123):
+      echo "Invalid identifier! Will not be echoed"
diff --git a/tests/template/tdotcall.nim b/tests/template/tdotcall.nim
new file mode 100644
index 000000000..dc97fd52e
--- /dev/null
+++ b/tests/template/tdotcall.nim
@@ -0,0 +1,32 @@
+import mdotcall
+
+block: # issue #20073
+  works()
+  boom()
+
+block: # issue #7085
+  doAssert baz("hello") == "hellobar"
+  doAssert baz"hello" == "hellobar"
+  doAssert "hello".baz == "hellobar"
+
+block: # issue #7223
+  var r = BytesRange(bytes: @[1.byte, 2, 3], ibegin: 0, iend: 2)
+  var a = r.rangeBeginAddr
+
+block: # issue #11733
+  var a: ObjA
+  var evaluated = false
+  a.publicTemplateObjSyntax(42): evaluated = true
+  doAssert evaluated
+
+block: # issue #15246
+  doAssert sourceBaseName() == "tdotcall"
+
+block: # issue #12683
+  heh(0..40, "|")
+
+block: # issue #7889
+  if false:
+    bindmeQuote()
+  if false:
+    bindmeTemplate()
diff --git a/tests/template/template_issues.nim b/tests/template/template_issues.nim
new file mode 100644
index 000000000..58c40941d
--- /dev/null
+++ b/tests/template/template_issues.nim
@@ -0,0 +1,304 @@
+discard """
+output: '''
+@[]
+5
+0
+a
+hi
+Hello, World!
+(e: 42)
+hey
+foo
+foo
+foo
+false
+true
+'''
+"""
+
+
+import macros, json
+
+
+block t2057:
+  proc mpf_get_d(x: int): float = float(x)
+  proc mpf_cmp_d(a: int; b: float): int = 0
+
+  template toFloatHelper(result, tooSmall, tooLarge: untyped) =
+    result = mpf_get_d(a)
+    if result == 0.0 and mpf_cmp_d(a,0.0) != 0:
+      tooSmall
+    if result == Inf:
+      tooLarge
+
+  proc toFloat(a: int): float =
+    toFloatHelper(result) do:
+      raise newException(ValueError, "number too small")
+    do:
+      raise newException(ValueError, "number too large")
+
+  doAssert toFloat(8) == 8.0
+
+
+
+import sequtils, os
+block t2629:
+  template glob_rst(basedir: string = ""): untyped =
+    if baseDir.len == 0:
+      to_seq(walk_files("*.rst"))
+    else:
+      to_seq(walk_files(basedir/"*.rst"))
+
+  let rst_files = concat(glob_rst(), glob_rst("docs"))
+
+  when true: echo rst_files
+
+
+block t5417:
+  macro genBody: untyped =
+    let sbx = genSym(nskLabel, "test")
+    when true:
+      result = quote do:
+        block `sbx`:
+          break `sbx`
+    else:
+      template foo(s1, s2) =
+        block s1:
+          break s2
+      result = getAst foo(sbx, sbx)
+
+  proc test() =
+    genBody()
+
+
+
+block t909:
+  template baz() =
+    proc bar() =
+      var x = 5
+      iterator foo(): int {.closure.} =
+        echo x
+      var y = foo
+      discard y()
+
+  macro test(): untyped =
+    result = getAst(baz())
+
+  test()
+  bar()
+
+
+
+block t993:
+  type PNode = ref object of RootObj
+
+  template litNode(name, ty)  =
+    type name = ref object of PNode
+      val: ty
+  litNode PIntNode, int
+
+  template withKey(j: JsonNode; key: string; varname,
+                    body: untyped): typed =
+    if j.hasKey(key):
+      let varname{.inject.}= j[key]
+      block:
+        body
+
+  var j = parsejson("{\"zzz\":1}")
+  withkey(j, "foo", x):
+    echo(x)
+
+
+
+
+block t1337:
+  template someIt(a, pred): untyped =
+    var it {.inject.} = 0
+    pred
+
+  proc aProc(n: auto) =
+    n.someIt(echo(it))
+
+  aProc(89)
+
+
+
+import mlt
+block t4564:
+  type Bar = ref object of RootObj
+  proc foo(a: Bar): int = 0
+  var a: Bar
+  let b = a.foo() > 0
+
+
+
+block t8052:
+  type
+    UintImpl[N: static[int], T: SomeUnsignedInt] = object
+      raw_data: array[N, T]
+
+  template genLoHi(TypeImpl: untyped): untyped =
+    template loImpl[N: static[int], T: SomeUnsignedInt](dst: TypeImpl[N div 2, T], src: TypeImpl[N, T]) =
+      let halfSize = N div 2
+      for i in 0 ..< halfSize:
+        dst.raw_data[i] = src.raw_data[i]
+
+    proc lo[N: static[int], T: SomeUnsignedInt](x: TypeImpl[N,T]): TypeImpl[N div 2, T] {.inline.}=
+      loImpl(result, x)
+
+  genLoHi(UintImpl)
+
+  var a: UintImpl[4, uint32]
+
+  a.raw_data = [1'u32, 2'u32, 3'u32, 4'u32]
+  doAssert a.lo.raw_data.len == 2
+  doAssert a.lo.raw_data[0] == 1
+  doAssert a.lo.raw_data[1] == 2
+
+
+
+block t2585:
+  type
+    RenderPass = object
+       state: ref int
+    RenderData = object
+        fb: int
+        walls: seq[RenderPass]
+    Mat2 = int
+    Vector2[T] = T
+    Pixels=int
+
+  template use(fb: int, st: untyped): untyped =
+      echo "a ", $fb
+      st
+      echo "a ", $fb
+
+  proc render(rdat: var RenderData; passes: var openArray[RenderPass]; proj: Mat2;
+              indexType = 1) =
+      for i in 0 ..< len(passes):
+          echo "blah ", repr(passes[i])
+
+  proc render2(rdat: var RenderData; screenSz: Vector2[Pixels]; proj: Mat2) =
+      use rdat.fb:
+          render(rdat, rdat.walls, proj, 1)
+
+
+
+block t4292:
+  template foo(s: string): string = s
+  proc variadicProc(v: varargs[string, foo]) = echo v[0]
+  variadicProc("a")
+
+
+
+block t2670:
+  template testTemplate(b: bool): typed =
+    when b:
+        var a = "hi"
+    else:
+        var a = 5
+    echo a
+  testTemplate(true)
+
+
+
+block t4097:
+  var i {.compileTime.} = 2
+
+  template defineId(t: typedesc) =
+    const id {.genSym.} = i
+    static: inc(i)
+    proc idFor(T: typedesc[t]): int {.inline, raises: [].} = id
+
+  defineId(int8)
+  defineId(int16)
+
+  doAssert idFor(int8) == 2
+  doAssert idFor(int16) == 3
+
+
+
+block t5235:
+  template outer(body: untyped) =
+    template test(val: string) =
+      const SomeConst: string = val
+      echo SomeConst
+    body
+
+  outer:
+    test("Hello, World!")
+
+
+# bug #11941
+type X = object
+  e: int
+
+proc works(T: type X, v: auto): T = T(e: v)
+template fails(T: type X, v: auto): T = T(e: v)
+
+var
+  w = X.works(42)
+  x = X.fails(42)
+
+echo x
+
+import mtempl5
+
+
+proc foo(): auto =
+  trap "foo":
+    echo "hey"
+
+discard foo()
+
+
+# bug #4722
+type
+  IteratorF*[In] = iterator() : In {.closure.}
+
+template foof(In: untyped) : untyped =
+  proc ggg*(arg: IteratorF[In]) =
+    for i in arg():
+      echo "foo"
+
+
+iterator hello() : int {.closure.} =
+  for i in 1 .. 3:
+    yield i
+
+foof(int)
+ggg(hello)
+
+
+# bug #2586
+var z = 10'u8
+echo z < 9 # Works
+echo z > 9 # Error: type mismatch
+
+
+# bug #5993
+template foo(p: proc) =
+  var bla = 5
+  p(bla)
+
+foo() do(t: var int):
+  discard
+  t = 5
+
+proc bar(t: var int) =
+  t = 5
+
+foo(bar)
+
+block: # bug #12595
+  template test() =
+    let i = 42
+    discard {i: ""}
+
+  test()
+
+block: # bug #21920
+  template t[T](): T =
+    discard
+
+  t[void]() # Error: expression has no type: discard
diff --git a/tests/template/template_pragmas.nim b/tests/template/template_pragmas.nim
new file mode 100644
index 000000000..da532b010
--- /dev/null
+++ b/tests/template/template_pragmas.nim
@@ -0,0 +1,9 @@
+proc output_x:string {.compileTime.} = "x"
+
+template t =
+  const x = output_x()
+  let
+    bar {.exportc:"bar" & x.} = 100
+
+static:
+  doAssert(compiles (t()))
diff --git a/tests/template/template_various.nim b/tests/template/template_various.nim
new file mode 100644
index 000000000..2088b1739
--- /dev/null
+++ b/tests/template/template_various.nim
@@ -0,0 +1,406 @@
+discard """
+output: '''
+i2416
+33
+foo55
+foo8.0
+fooaha
+bar7
+10
+4true
+132
+20
+1
+-1
+4
+11
+26
+57
+-1-1-1
+  4
+4
+  4
+  11
+11
+  4
+  11
+  26
+26
+  4
+  11
+  26
+  57
+57
+-1-1-1
+'''
+"""
+
+import macros
+
+
+
+
+import i2416
+i2416()
+
+
+import mcan_access_hidden_field
+var myfoo = createFoo(33, 44)
+echo myfoo.geta
+
+
+import mgensym_generic_cross_module
+foo(55)
+foo 8.0
+foo "aha"
+bar 7
+
+
+
+block generic_templates:
+  type
+    SomeObj = object of RootObj
+    Foo[T, U] = object
+      x: T
+      y: U
+
+  template someTemplate[T](): tuple[id: int32, obj: T] =
+    var result: tuple[id: int32, obj: T] = (0'i32, T())
+    result
+
+  let ret = someTemplate[SomeObj]()
+
+  # https://github.com/nim-lang/Nim/issues/7829
+  proc inner[T](): int =
+    discard
+
+  template outer[A](): untyped =
+    inner[A]()
+
+  template outer[B](x: int): untyped =
+    inner[B]()
+
+  var i1 = outer[int]()
+  var i2 = outer[int](i1)
+
+  # https://github.com/nim-lang/Nim/issues/7883
+  template t1[T: int|int64](s: string): T =
+     var t: T
+     t
+
+  template t1[T: int|int64](x: int, s: string): T =
+     var t: T
+     t
+
+  var i3: int = t1[int]("xx")
+
+from strutils import contains
+
+block tgetast_typeliar:
+  proc error(s: string) = quit s
+
+  macro assertOrReturn2(condition: bool; message: string) =
+    var line = condition.lineInfo()
+    result = quote do:
+      block:
+        if not likely(`condition`):
+          error("Assertion failed: " & $(`message`) & "\n" & `line`)
+          return
+
+  macro assertOrReturn(condition: bool) =
+    var message : NimNode = newLit(condition.repr)
+    # echo message
+    result = getAst assertOrReturn2(condition, message)
+    # echo result.repr
+    let s = result.repr
+    doAssert """error("Assertion failed:""" in s
+
+  proc point(size: int16): tuple[x, y: int16] =
+    # returns random point in square area with given `size`
+    assertOrReturn size > 0
+
+
+
+type
+  MyFloat = object
+    val: float
+converter to_myfloat(x: float): MyFloat {.inline.} =
+  MyFloat(val: x)
+
+block pattern_with_converter:
+  proc `+`(x1, x2: MyFloat): MyFloat =
+    MyFloat(val: x1.val + x2.val)
+
+  proc `*`(x1, x2: MyFloat): MyFloat =
+      MyFloat(val: x1.val * x2.val)
+
+  template optMul{`*`(a, 2.0)}(a: MyFloat): MyFloat =
+    a + a
+
+  func floatMyFloat(x: MyFloat): MyFloat =
+    result = x * 2.0
+
+  func floatDouble(x: float): float =
+    result = x * 2.0
+
+  doAssert floatDouble(5) == 10.0
+
+
+
+
+block procparshadow:
+  template something(name: untyped) =
+    proc name(x: int) =
+      var x = x # this one should not be rejected by the compiler (#5225)
+      echo x
+
+  something(what)
+  what(10)
+
+  # bug #4750
+  type
+    O = object
+      i: int
+    OP = ptr O
+
+  template alf(p: pointer): untyped =
+    cast[OP](p)
+
+  proc t1(al: pointer) =
+    var o = alf(al)
+
+  proc t2(alf: pointer) =
+    var x = alf
+    var o = alf(x)
+
+
+
+block symchoicefield:
+  type Foo = object
+    len: int
+
+  var f = Foo(len: 40)
+
+  template getLen(f: Foo): int = f.len
+
+  doAssert f.getLen == 40
+  # This fails, because `len` gets the nkOpenSymChoice
+  # treatment inside the template early pass and then
+  # it can't be recognized as a field anymore
+
+
+
+import os, times
+include "sunset.nimf"
+block ttempl:
+  const
+    tabs = [["home", "index"],
+            ["news", "news"],
+            ["documentation", "documentation"],
+            ["download", "download"],
+            ["FAQ", "question"],
+            ["links", "links"]]
+
+
+  var i = 0
+  for item in items(tabs):
+    var content = $i
+    var file: File
+    if open(file, changeFileExt(item[1], "html"), fmWrite):
+      write(file, sunsetTemplate(current=item[1], ticker="", content=content,
+                                  tabs=tabs))
+      close(file)
+    else:
+      write(stdout, "cannot open file for writing")
+    inc(i)
+
+
+
+block ttempl4:
+  template `:=`(name, val: untyped) =
+    var name = val
+
+  ha := 1 * 4
+  hu := "ta-da" == "ta-da"
+  echo ha, hu
+
+
+
+
+import mtempl5
+block ttempl5:
+  echo templ()
+
+  #bug #892
+  proc parse_to_close(value: string, index: int, open='(', close=')'): int =
+      discard
+
+  # Call parse_to_close
+  template get_next_ident =
+      discard "{something}".parse_to_close(0, open = '{', close = '}')
+
+  get_next_ident()
+
+  #identifier expected, but found '(open|open|open)'
+  #bug #880 (also example in the manual!)
+  template typedef(name: untyped, typ: typedesc) =
+    type
+      `T name` {.inject.} = typ
+      `P name` {.inject.} = ref `T name`
+
+  typedef(myint, int)
+  var x: PMyInt
+
+
+
+block templreturntype:
+  template `=~` (a: int, b: int): bool = false
+  var foo = 2 =~ 3
+
+# bug #7117
+template parse9(body: untyped): untyped =
+
+  template val9(arg: string): int {.inject.} =
+    var b: bool
+    if b: 10
+    else: 20
+
+  body
+
+parse9:
+  echo val9("1")
+
+
+block gensym1:
+  template x: untyped = -1
+  template t1() =
+    template x: untyped {.gensym, redefine.} = 1
+    echo x()  # 1
+  template t2() =
+    template x: untyped {.redefine.} = 1  # defaults to {.inject.}
+    echo x()  # -1  injected x not available during template definition
+  t1()
+  t2()
+
+block gensym2:
+  let x,y,z = -1
+  template `!`(xx,yy: typed): untyped =
+    template x: untyped {.gensym.} = xx
+    template y: untyped {.gensym.} = yy
+    let z = x + x + y
+    z
+  var
+    a = 1
+    b = 2
+    c = 3
+    d = 4
+    e = 5
+  echo a ! b
+  echo a ! b ! c
+  echo a ! b ! c ! d
+  echo a ! b ! c ! d ! e
+  echo x,y,z
+
+block gensym3:
+  macro liftStmts(body: untyped): auto =
+    # convert
+    #   template x: untyped {.gensym.} =
+    #     let z = a + a + b
+    #     echo z
+    #     z
+    # to
+    #   let z = a + a + b
+    #   echo z
+    #   template x: untyped {.gensym.} =
+    #     z
+    #echo body.repr
+    body.expectKind nnkStmtList
+    result = newNimNode nnkStmtList
+    for s in body:
+      s.expectKind nnkTemplateDef
+      var sle = s[6]
+      while sle.kind == nnkStmtList:
+        doAssert(sle.len==1)
+        sle = sle[0]
+      if sle.kind == nnkStmtListExpr:
+        let n = sle.len
+        for i in 0..(n-2):
+          result.add sle[i]
+        var td = newNimNode nnkTemplateDef
+        for i in 0..5:
+          td.add s[i]
+        td.add sle[n-1]
+        result.add td
+      else:
+        result.add s
+    #echo result.repr
+  let x,y,z = -1
+  template `!`(xx,yy: typed): untyped =
+    liftStmts:
+      template x: untyped {.gensym.} = xx
+      template y: untyped {.gensym.} = yy
+    let z = x + x + y
+    echo "  ", z
+    z
+  var
+    a = 1
+    b = 2
+    c = 3
+    d = 4
+    e = 5
+  echo a ! b
+  echo a ! b ! c
+  echo a ! b ! c ! d
+  echo a ! b ! c ! d ! e
+  echo x,y,z
+
+block: # issue #2465
+  template t() =
+    template declX(str: string) {.gensym.} =
+      var x {.inject.} : string = str
+
+  t()
+  doAssert not declared(declX)
+  doAssert not compiles(declX("a string"))
+
+  template t2() =
+    template fooGensym() {.gensym.} =
+      echo 42
+
+  t2()
+  doAssert not declared(fooGensym)
+  doAssert not compiles(fooGensym())
+
+
+block identifier_construction_with_overridden_symbol:
+  # could use add, but wanna make sure it's an override no matter what
+  func examplefn = discard
+  func examplefn(x: int) = discard
+
+  # the function our template wants to use
+  func examplefn1 = discard
+
+  template exampletempl(n) =
+    # attempt to build a name using the overridden symbol "examplefn"
+    `examplefn n`()
+
+  exampletempl(1)
+
+import typetraits
+
+block: # issue #4596
+  type
+    T0 = object
+    T1 = object
+
+  template printFuncsT() =
+    proc getV[A](a: typedesc[A]): string =
+      var s {. global .} = name(A)
+      return s
+
+  printFuncsT()
+
+  doAssert getV(T1) == "T1"
+  doAssert getV(T0) == "T0"
+  doAssert getV(T0) == "T0"
+  doAssert getV(T1) == "T1"
diff --git a/tests/template/texponential_eval.nim b/tests/template/texponential_eval.nim
new file mode 100644
index 000000000..b4e3faefb
--- /dev/null
+++ b/tests/template/texponential_eval.nim
@@ -0,0 +1,51 @@
+# bug #1940
+
+discard """
+nimout: '''
+===
+merge (A) with (B)
+merge (A B) with (C)
+merge (A B C) with (D)
+merge (A B C D) with (E)
+merge (A B C D E) with (F)
+===
+'''
+
+output: "A B C D E F"
+"""
+
+type SqlStmt = tuple
+  sql: string
+  parts: int
+
+proc sql(q: string): SqlStmt =
+  result.sql = q
+  result.parts = 1
+
+template `&%%`(x, y: SqlStmt): SqlStmt =
+  const a = x
+  const b = y
+
+  static:
+    #echo "some merge"
+    echo "merge (", a.sql, ") with (", b.sql, ")"
+
+
+  const newSql = a.sql & " " & b.sql
+  const newParts = a.parts + b.parts
+
+  SqlStmt((sql: newSql, parts: newParts))
+
+static:
+  echo "==="
+
+let c =(sql("A") &%%
+        sql("B")) &%%
+        sql("C")  &%%
+        sql("D") &%%
+        sql("E") &%%
+        sql("F")
+echo c.sql
+
+static:
+  echo "==="
diff --git a/tests/template/tgenericparam.nim b/tests/template/tgenericparam.nim
new file mode 100644
index 000000000..becf75d36
--- /dev/null
+++ b/tests/template/tgenericparam.nim
@@ -0,0 +1,93 @@
+block: # basic template generic parameter substitution
+  block: # issue #13527
+    template typeNameTempl[T](a: T): string = $T
+    proc typeNameProc[T](a: T): string = $T
+    doAssert typeNameTempl(1) == typeNameProc(1)
+    doAssert typeNameTempl(true) == typeNameProc(true)
+    doAssert typeNameTempl(1.0) == typeNameProc(1.0)
+    doAssert typeNameTempl(1u8) == typeNameProc(1u8)
+
+    template isDefault[T](a: T): bool = a == default(T)
+    doAssert isDefault(0.0)
+
+  block: # issue #17240
+    func to(c: int, t: typedesc[float]): t = discard
+    template converted[I, T](i: seq[I], t: typedesc[T]): seq[T] =
+      var result = newSeq[T](2)
+      result[0] = i[0].to(T)
+      result
+    doAssert newSeq[int](3).converted(float) == @[0.0, 0.0]
+
+  block: # issue #6340
+    type A[T] = object
+      v: T
+    proc foo(x: int): string = "int"
+    proc foo(x: typedesc[int]): string = "typedesc[int]"
+    template fooT(x: int): string = "int"
+    template fooT(x: typedesc[int]): string = "typedesc[int]"
+    proc foo[T](x: A[T]): (string, string) =
+      (foo(T), fooT(T))
+    template fooT[T](x: A[T]): (string, string) =
+      (foo(T), fooT(T))
+    var x: A[int]
+    doAssert foo(x) == fooT(x)
+
+  block: # issue #20033
+    template run[T](): T = default(T)
+    doAssert run[int]() == 0
+
+import options, tables, typetraits
+
+block: # complex cases of above with imports
+  block: # issue #19576, complex case
+    type RegistryKey = object
+      key, val: string
+    var regKey = @[RegistryKey(key: "abc", val: "def")]
+    template findFirst[T](s: seq[T], pred: proc(x: T): bool): Option[T] =
+      var res = none(T) # important line
+      for x in s:
+        if pred(x):
+          res = some(x)
+          break
+      res
+    proc getval(searchKey: string): Option[string] =
+      let found = regKey.findFirst(proc (rk: RegistryKey): bool = rk.key == searchKey)
+      if found.isNone: none(string)
+      else: some(found.get().val)
+    doAssert getval("strange") == none(string)
+    doAssert getval("abc") == some("def")
+  block: # issue #19076
+    block: # case 1
+      var tested: Table[string,int]
+      template `[]`[V](t:Table[string,V],key:string):untyped =
+        $V
+      doAssert tested["abc"] == "int"
+      template `{}`[V](t:Table[string,V],key:string):untyped =
+        ($V, tables.`[]`(t, key))
+      doAssert (try: tested{"abc"} except KeyError: ("not there", 123)) == ("not there", 123)
+      tables.`[]=`(tested, "abc", 456)
+      doAssert tested["abc"] == "int"
+      doAssert tested{"abc"} == ("int", 456)
+    block: # case 2
+      type Foo[A,T] = object
+        t:T
+      proc init[A,T](f:type Foo,a:typedesc[A],t:T):Foo[A,T] = Foo[A,T](t:t)
+      template fromOption[A](o:Option[A]):auto =
+        when o.isSome:
+          Foo.init(A,35)
+        else:
+          Foo.init(A,"hi")
+      let op = fromOption(some(5))
+  block: # issue #7461
+    template p[T](): untyped = none(T)
+    doAssert p[int]() == none(int)
+  block: # issue #7995
+    var res: string
+    template copyRange[T](dest: seq[T], destOffset: int) =
+      when supportsCopyMem(T):
+        res = "A"
+      else:    
+        res = "B"
+    var a = @[1, 2, 3]
+    copyRange(a, 0)
+    doAssert res == "A"
diff --git a/tests/template/tgensym_instantiationinfo.nim b/tests/template/tgensym_instantiationinfo.nim
new file mode 100644
index 000000000..4b997ed6a
--- /dev/null
+++ b/tests/template/tgensym_instantiationinfo.nim
@@ -0,0 +1,24 @@
+discard """
+  action: "compile"
+"""
+
+# bug #7937
+
+template printError(error: typed) =
+  # Error: inconsistent typing for reintroduced symbol 'instInfo': previous type was: tuple[filename: string, line: int, column: int]; new type is: (string, int, int)
+  let instInfo {.gensym.} = instantiationInfo()
+  echo "Error at ", instInfo.filename, ':', instInfo.line, ": ", error
+
+# Removing this overload fixes the error
+template someTemplate(someBool: bool, body) =
+  discard
+
+template someTemplate(body) =
+  body
+
+proc main() =
+  someTemplate:
+    printError("ERROR 1")
+    printError("ERROR 2")
+
+main()
diff --git a/tests/template/tgensymhijack.nim b/tests/template/tgensymhijack.nim
new file mode 100644
index 000000000..72ff3d495
--- /dev/null
+++ b/tests/template/tgensymhijack.nim
@@ -0,0 +1,37 @@
+# issue #23326
+
+type Result*[E] = object
+  e*: E
+
+proc error*[E](v: Result[E]): E = discard
+
+template valueOr*[E](self: Result[E], def: untyped): int =
+  when E isnot void:
+    when false:
+      # Comment line below to make it work
+      template error(): E {.used, gensym.} = s.e
+      discard
+    else:
+      template error(): E {.used, inject.} =
+        self.e
+
+      def
+  else:
+    def
+
+
+block:
+  let rErr = Result[string](e: "a")
+  let rErrV = rErr.valueOr:
+    ord(error[0])
+
+block:
+  template foo(x: static bool): untyped =
+    when x:
+      let a = 123
+    else:
+      template a: untyped {.gensym.} = 456
+    a
+  
+  doAssert foo(false) == 456
+  doAssert foo(true) == 123
diff --git a/tests/template/tgensymregression.nim b/tests/template/tgensymregression.nim
new file mode 100644
index 000000000..2a5dca934
--- /dev/null
+++ b/tests/template/tgensymregression.nim
@@ -0,0 +1,88 @@
+discard """
+  output: '''[0.0, 0.0, 0.0]
+[0.0, 0.0, 0.0, 0.0]
+5050
+123'''
+"""
+
+template mathPerComponent(op: untyped): untyped =
+  proc op*[N,T](v,u: array[N,T]): array[N,T] {.inline.} =
+    for i in 0 ..< len(result):
+      result[i] = `*`(v[i], u[i])
+
+mathPerComponent(`***`)
+# bug #5285
+when true:
+  if true:
+    var v1: array[3, float64]
+    var v2: array[3, float64]
+    echo repr(v1 *** v2)
+
+
+proc foo(): void =
+  var v1: array[4, float64]
+  var v2: array[4, float64]
+  echo repr(v1 *** v2)
+
+foo()
+
+# bug #5383
+import sequtils
+
+proc zipWithIndex[A](ts: seq[A]): seq[(int, A)] =
+  toSeq(pairs(ts))
+
+proc main =
+  discard zipWithIndex(@["foo", "bar"])
+  discard zipWithIndex(@[1, 2])
+  discard zipWithIndex(@[true, false])
+
+main()
+
+# bug #5405
+
+proc main2() =
+  let s = toSeq(1..100).foldL(a + b)
+  echo s
+
+main2()
+
+# bug #5467
+import macros
+
+converter int2string(x: int): string = $x
+
+template wrap(body: typed): untyped =
+  body
+
+macro makeProc() =
+  # Make a template tree
+  result = quote do:
+    proc someProc* =
+      wrap do:
+        let x = 123
+        # Implicit conversion here
+        let s: string = x
+        echo s
+
+makeProc()
+
+someProc()
+
+# bug #12193
+import macros, strutils
+
+macro gen(T: typedesc): untyped =
+  let typeSym = getTypeImpl(T)[1]
+  let param = genSym(nskParam, "s")
+  let value = nnkBracketExpr.newTree(param, newIntLitNode(0))
+  result = newProc(
+    name = ident"pack",
+    params = [typeSym,
+      newIdentDefs(param, nnkBracketExpr.newTree(ident"seq", ident"string"))],
+    body = newStmtList(newCall(typeSym, newCall(bindSym"parseInt", value))),
+    procType = nnkTemplateDef)
+  echo repr result
+
+gen(int)
+let i = pack(@["2"])
diff --git a/tests/template/thygienictempl.nim b/tests/template/thygienictempl.nim
new file mode 100644
index 000000000..9020c3e28
--- /dev/null
+++ b/tests/template/thygienictempl.nim
@@ -0,0 +1,22 @@
+discard """
+action: compile
+"""
+
+
+var
+  e = "abc"
+
+raise newException(IOError, e & "ha!")
+
+template t() = echo(foo)
+
+var foo = 12
+t()
+
+
+template test_in(a, b, c: untyped): bool {.dirty.} =
+  var result {.gensym.}: bool = false
+  false
+
+when true:
+  assert test_in(ret2, "test", str_val)
diff --git a/tests/template/tidentconcatenations.nim b/tests/template/tidentconcatenations.nim
new file mode 100644
index 000000000..ddd2e49cc
--- /dev/null
+++ b/tests/template/tidentconcatenations.nim
@@ -0,0 +1,31 @@
+type
+  Hash*[bits: static[int]] = object
+    data*: array[bits div 8, uint8]
+
+{.emit: """
+
+void sha_256(void* input, int input_len, void* output, int output_len) {}
+void sha_512(void* input, int input_len, void* output, int output_len) {}
+
+void keccak_256(void* input, int input_len, void* output, int output_len) {}
+void keccak_512(void* input, int input_len, void* output, int output_len) {}
+
+""".}
+
+template defineKeccak(bits: untyped) =
+  proc `extKeccak bits`(output: pointer, outSize: csize_t, input: pointer, inputSize: csize_t) {.nodecl, importc: "keccak_" & astToStr(bits).}
+
+template defineSha(bits: static[int]) =
+  proc `extSha bits`(output: pointer, outSize: csize_t, input: pointer, inputSize: csize_t) {.nodecl, importc: "sha_" & astToStr(bits).}
+
+template defineHashProcs(bits) =
+  defineSha(bits)
+  defineKeccak(bits)
+
+defineHashProcs(256)
+defineHashProcs(512)
+
+extSha256(nil, 0, nil, 0)
+extSha512(nil, 0, nil, 0)
+extKeccak256(nil, 0, nil, 0)
+extKeccak512(nil, 0, nil, 0)
diff --git a/tests/template/tinnerouterproc.nim b/tests/template/tinnerouterproc.nim
new file mode 100644
index 000000000..56e0d02df
--- /dev/null
+++ b/tests/template/tinnerouterproc.nim
@@ -0,0 +1,20 @@
+block: # #20002
+  proc bar(x: int): int = 10
+  template foo =
+    proc bar(x: int): int {.gensym.} = x + 2
+    doAssert bar(3) == 5
+    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/tmethodcall.nim b/tests/template/tmethodcall.nim
new file mode 100644
index 000000000..d209443c8
--- /dev/null
+++ b/tests/template/tmethodcall.nim
@@ -0,0 +1,24 @@
+# bug #5909
+type
+  Vec2[T] = tuple
+    x,y: T
+  Vec2f = Vec2[float32]
+
+proc vec2f(x,y: float): Vec2f =
+  result.x = x
+  result.y = y
+
+proc `-`[T](a,b: Vec2[T]): Vec2[T] =
+  result.x = a.x - b.x
+  result.y = a.y - b.y
+
+proc foo[T](a: Vec2[T]): Vec2[T] =
+  result = a
+
+block:
+ # this being called foo is a problem when calling .foo()
+  var foo = true
+
+  let a = vec2f(1.0,0.0)
+  let b = vec2f(3.0,1.0)
+  let c = (a - b).foo() # breaks
diff --git a/tests/template/tmixin_in_proc.nim b/tests/template/tmixin_in_proc.nim
new file mode 100644
index 000000000..fede9290b
--- /dev/null
+++ b/tests/template/tmixin_in_proc.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''monkey'''
+"""
+# bug #5478
+template creature*(name: untyped) =
+  type
+    name*[T] = object
+      color: T
+
+  proc `init name`*[T](c: T): name[T] =
+    mixin transform
+    transform()
+
+creature(Lion)
+
+type Monkey* = object
+proc transform*() =
+  echo "monkey"
+
+var
+  m: Monkey
+  y = initLion(m)  #this one failed to compile
diff --git a/tests/template/tmodulealias.nim b/tests/template/tmodulealias.nim
new file mode 100644
index 000000000..79b5ec9c6
--- /dev/null
+++ b/tests/template/tmodulealias.nim
@@ -0,0 +1,19 @@
+discard """
+  disabled: true
+"""
+
+when defined(windows):
+  import winlean
+else:
+  import posix
+
+when defined(windows):
+  template orig: expr =
+    winlean
+else:
+  template orig: expr =
+    posix
+
+proc socket(domain, typ, protocol: int): int =
+  result = orig.socket(ord(domain), ord(typ), ord(protocol)))
+
diff --git a/tests/template/tmore_regressions.nim b/tests/template/tmore_regressions.nim
new file mode 100644
index 000000000..8b4b5fa4c
--- /dev/null
+++ b/tests/template/tmore_regressions.nim
@@ -0,0 +1,44 @@
+discard """
+output: '''0
+
+0.0'''
+"""
+
+# bug #11494
+import macros
+
+macro staticForEach(arr: untyped, body: untyped): untyped =
+    result = newNimNode(nnkStmtList)
+
+    arr.expectKind(nnkBracket)
+    for n in arr:
+        let b = copyNimTree(body)
+        result.add quote do:
+            block:
+                type it {.inject.} = `n`
+                `b`
+
+template forEveryMatchingEntity*() =
+    staticForEach([int, string, float]):
+        var a: it
+        echo a
+
+forEveryMatchingEntity()
+
+
+# bug #11483
+proc main =
+  template first(body) =
+    template second: var int =
+      var o: int
+      var i  = addr(o)
+      i[]
+
+    body
+
+  first:
+    second = 5
+    second = 6
+
+main()
+
diff --git a/tests/template/tnested.nim b/tests/template/tnested.nim
new file mode 100644
index 000000000..81e416a76
--- /dev/null
+++ b/tests/template/tnested.nim
@@ -0,0 +1,38 @@
+block: # issue #22775
+  proc h(c: int) = discard
+  template k(v: int) =
+    template p() = v.h()
+    p()
+  let a = @[0]
+  k(0 and not a[0])
+
+block: # issue #22775 case 2
+  proc h(c: int, q: int) = discard
+  template k(v: int) =
+    template p() = h(v, v)
+    p()
+  let a = [0]
+  k(0 and not a[0])
+
+block: # issue #22775 minimal cases
+  proc h(c: int) = discard
+  template k(v: int) =
+    template p() = h(v)
+    p()
+  let a = [0]
+  k(not a[0])
+  block:
+    k(-a[0])
+  block:
+    proc f(x: int): int = x
+    k(f a[0])
+
+block: # bracket assignment case of above tests
+  proc h(c: int) = discard
+  template k(v: int) =
+    template p() = h(v)
+    p()
+  var a = [0]
+  k(not (block:
+    a[0] = 1
+    1))
diff --git a/tests/template/tobjectdeclfield.nim b/tests/template/tobjectdeclfield.nim
new file mode 100644
index 000000000..afce2cae8
--- /dev/null
+++ b/tests/template/tobjectdeclfield.nim
@@ -0,0 +1,21 @@
+block: # issue #16005
+  var x = 0
+
+  block:
+    type Foo = object
+      x: float # ok
+
+  template main() =
+    block:
+      type Foo = object
+        x: float # Error: cannot use symbol of kind 'var' as a 'field'
+
+  main()
+
+block: # issue #19552
+  template test =
+    type
+      test2 = ref object
+        reset: int
+
+  test()
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/tparams_gensymed.nim b/tests/template/tparams_gensymed.nim
new file mode 100644
index 000000000..b559c2d9e
--- /dev/null
+++ b/tests/template/tparams_gensymed.nim
@@ -0,0 +1,405 @@
+discard """
+output: '''
+0
+1
+2
+3
+0
+1
+2
+3
+wth
+3
+2
+1
+0
+(total: 6)
+S1
+5
+abc
+'''
+"""
+# bug #1915
+
+import macros
+
+# Test that parameters are properly gensym'ed finally:
+
+template genNodeKind(kind, name: untyped) =
+  proc name*(children: varargs[NimNode]): NimNode {.compiletime.}=
+    result = newNimNode(kind)
+    for c in children:
+      result.add(c)
+
+genNodeKind(nnkNone, None)
+
+
+# Test that generics in templates still work (regression to fix #1915)
+
+# bug #2004
+
+type Something = object
+
+proc testA(x: Something) = discard
+
+template def(name: untyped) =
+  proc testB[T](reallyUniqueName: T) =
+    `test name`(reallyUniqueName)
+def A
+
+var x: Something
+testB(x)
+
+
+# bug #2215
+# Test that templates in generics still work (regression to fix the
+# regression...)
+
+template forStatic(index, slice, predicate: untyped) =
+  const a = slice.a
+  const b = slice.b
+  when a <= b:
+    template iteration(i: int) =
+      block:
+        const index = i
+        predicate
+    template iterateStartingFrom(i: int) =
+      when i <= b:
+        iteration i
+        iterateStartingFrom i + 1
+    iterateStartingFrom a
+
+proc concreteProc(x: int) =
+  forStatic i, 0..3:
+    echo i
+
+proc genericProc(x: auto) =
+  forStatic i, 0..3:
+    echo i
+
+concreteProc(7) # This works
+genericProc(7)  # This doesn't compile
+
+import tables
+
+# bug #9476
+proc getTypeInfo*(T: typedesc): pointer =
+  var dummy: T
+  getTypeInfo(dummy)
+
+
+macro implementUnary(op: untyped): untyped =
+  result = newStmtList()
+
+  template defineTable(tableSymbol) =
+    var tableSymbol = initTable[pointer, pointer]()
+  let tableSymbol = genSym(nskVar, "registeredProcs")
+  result.add(getAst(defineTable(tableSymbol)))
+
+  template defineRegisterInstantiation(tableSym, regTemplSym, instSym, op) =
+    template regTemplSym*(T: typedesc) =
+      let ti = getTypeInfo(T)
+
+      proc instSym(xOrig: int): int {.gensym, cdecl.} =
+        let x {.inject.} = xOrig
+        op
+
+      tableSym[ti] = cast[pointer](instSym)
+
+  let regTemplSymbol = ident("registerInstantiation")
+  let instSymbol = ident("instantiation")
+  result.add(getAst(defineRegisterInstantiation(
+    tableSymbol, regTemplSymbol, instSymbol, op
+  )))
+
+  echo result.repr
+
+
+implementUnary(): x*x
+
+registerInstantiation(int)
+registerInstantiation(float)
+
+# bug #10192
+template nest(body) {.dirty.} =
+  template p1(b1: untyped) {.dirty, used.} =
+    template implp1: untyped {.dirty.} = b1
+  template p2(b2: untyped) {.dirty, used.} =
+    template implp2: untyped {.dirty.} = b2
+
+  body
+  implp1
+  implp2
+
+template test() =
+  nest:
+    p1:
+      var foo = "bar"
+    p2:
+      doAssert(foo.len == 3)
+
+test()
+
+# regression found in PMunch's parser generator
+
+proc namedcall(arg: string) =
+  discard
+
+macro m(): untyped =
+  result = quote do:
+    (proc (arg: string) =
+      namedcall(arg = arg)
+      echo arg)
+
+let meh = m()
+meh("wth")
+
+
+macro foo(body: untyped): untyped =
+  result = body
+
+template baz(): untyped =
+  foo:
+    proc bar2(b: int): int =
+      echo b
+      if b > 0: b + bar2(b = b - 1)
+      else: 0
+  echo (total: bar2(3))
+
+baz()
+
+# bug #12121
+macro state_machine_enum(states: varargs[untyped]) =
+  result = nnkTypeSection.newTree(
+    nnkTypeDef.newTree(
+      nnkPragmaExpr.newTree(ident("State"), nnkPragma.newTree(ident("pure"))),
+      newEmptyNode(),
+      nnkEnumTy.newTree(newEmptyNode())
+    )
+  )
+
+  for s in states:
+    expectKind(s, nnkIdent)
+    result[0][2].add s
+
+template mystate_machine(body: untyped) =
+  state_machine_enum(S1, S2, S3)
+  var state_stack: seq[State]
+  template state_current(): State {.inject, used.} =
+    state_stack[^1]
+  template state_push(state_name) {.inject, used.} =
+    state_stack.add State.state_name
+  template state_pop(n = 1) {.inject, used.} =
+    state_stack.setLen(state_stack.len - n)
+  body
+
+mystate_machine:
+  state_push(S1)
+  echo state_current()
+  state_pop()
+
+# bug #15075
+block: #Doesn't work
+  template genGenTempl: untyped =
+    proc loop(locals: int)
+    proc loop(locals: int) = discard
+  genGenTempl()
+  let pool = loop
+
+block: #Doesn't work
+  macro genGenMacro: untyped =
+    quote do:
+      proc loop(locals: int)
+      proc loop(locals: int) = discard
+  genGenMacro()
+  let pool = loop
+
+block: #This works
+  proc loop(locals: int)
+  proc loop(locals: int) = discard
+  let pool = loop
+
+#Now somewhat recursive:
+type Cont = ref object of RootObj
+  fn*: proc(c: Cont): Cont {.nimcall.}
+
+block: #Doesn't work
+  template genGenTempl(): untyped =
+    proc loop(locals: Cont): Cont
+    proc loop(locals: Cont): Cont =
+      return Cont(fn: loop)
+    proc doServer(): Cont =
+      return Cont(fn: loop)
+  genGenTempl()
+  discard doServer()
+
+block: #Doesn't work
+  macro genGenMacro(): untyped =
+    quote:
+      proc loop(locals: Cont): Cont
+      proc loop(locals: Cont): Cont =
+        return Cont(fn: loop)
+      proc doServer(): Cont =
+        return Cont(fn: loop)
+  genGenMacro()
+  discard doServer()
+
+block: #This works
+  proc loop(locals: Cont): Cont
+  proc loop(locals: Cont): Cont =
+    return Cont(fn: loop)
+  proc doServer(): Cont =
+    return Cont(fn: loop)
+  discard doServer()
+
+#And fully recursive:
+block: #Doesn't work
+  template genGenTempl: untyped =
+    proc loop(locals: int)
+    proc loop(locals: int) = loop(locals)
+  genGenTempl()
+  let pool = loop
+
+block: #Doesn't work
+  macro genGenMacro: untyped =
+    quote do:
+      proc loop(locals: int)
+      proc loop(locals: int) = loop(locals)
+  genGenMacro()
+  let pool = loop
+
+block: #This works
+  proc loop(locals: int)
+  proc loop(locals: int) = loop(locals)
+  let pool = loop
+
+block:
+  template genAndCallLoop: untyped =
+    proc loop() {.gensym.}
+    proc loop() {.gensym.} =
+      discard
+    loop()
+  genAndCallLoop
+
+block: #Fully recursive and gensymmed:
+  template genGenTempl: untyped =
+    proc loop(locals: int) {.gensym.}
+    proc loop(locals: int) {.gensym.} = loop(locals)
+    let pool = loop
+  genGenTempl()
+
+block: #Make sure gensymmed symbol doesn't overwrite the forward decl
+  proc loop()
+  proc loop() = discard
+  template genAndCallLoop: untyped =
+    proc loop() {.gensym.} =
+      discard
+    loop()
+  genAndCallLoop()
+
+template genLoopDecl: untyped =
+  proc loop()
+template genLoopDef: untyped =
+  proc loop() = discard
+block:
+  genLoopDecl
+  genLoopDef
+  loop()
+block:
+  proc loop()
+  genLoopDef
+  loop()
+block:
+  genLoopDecl
+  proc loop() = discard
+  loop()
+
+block: #Gensymmed sym sharing forward decl
+  macro genGenMacro: untyped =
+    let sym = genSym(nskProc, "loop")
+    nnkStmtList.newTree(
+      newProc(sym, body = newEmptyNode()),
+      newCall(sym),
+      newProc(sym, body = newStmtList()),
+    )
+  genGenMacro
+
+# inject pragma on params
+
+template test(procname, body: untyped): untyped = 
+  proc procname(data {.inject.}: var int = 0) =
+    body
+
+test(hello):
+  echo data
+  data = 3
+
+var data = 5
+
+hello(data)
+
+# bug #5691
+
+template bar(x: typed) = discard
+macro barry(x: typed) = discard
+
+var a = 0
+
+bar:
+  var a = 10
+
+barry:
+  var a = 20
+
+bar:
+  var b = 10
+
+barry:
+  var b = 20
+
+var b = 30
+
+# template bar(x: static int) = discard
+#You may think that this should work:
+# bar((var c = 1; echo "hey"; c))
+# echo c
+#But it must not! Since this would be incorrect:
+# bar((var b = 3; const c = 1; echo "hey"; c))
+# echo b # <- b wouldn't exist
+
+discard not (let xx = 1; true)
+discard xx
+
+template barrel(a: typed): untyped = a
+
+barrel:
+  var aa* = 1
+  var bb = 3
+  export bb
+
+# Test declaredInScope within params
+template test1: untyped =
+  when not declaredInScope(thing):
+    var thing {.inject.}: int
+
+proc chunkedReadLoop =
+  test1
+  test1
+
+template test2: untyped =
+  when not not not declaredInScope(thing):
+    var thing {.inject.}: int
+
+proc chunkedReadLoop2 =
+  test2
+  test2
+
+test1(); test2()
+
+block: # bug #22846
+  template foo2(x: proc (y: string)) =
+    let f = x
+    f("abc")
+
+  foo2(proc (y: string) = echo y)
+
diff --git a/tests/template/tparamscope.nim b/tests/template/tparamscope.nim
new file mode 100644
index 000000000..177c682cf
--- /dev/null
+++ b/tests/template/tparamscope.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "undeclared identifier: 'a'"
+  line: 10
+"""
+
+
+template secondArg(a, b: typed): untyped =
+  b
+
+echo secondArg((var a = 1; 1), a)
diff --git a/tests/template/tqualifiedident.nim b/tests/template/tqualifiedident.nim
new file mode 100644
index 000000000..463b14ee7
--- /dev/null
+++ b/tests/template/tqualifiedident.nim
@@ -0,0 +1,8 @@
+block: # issue #19865
+  template f() = discard default(system.int)
+  f()
+
+# issue #21221, same as above
+type M = object
+template r() = discard default(tqualifiedident.M)
+r()
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/template/tredefinition.nim b/tests/template/tredefinition.nim
new file mode 100644
index 000000000..8efc5ae2f
--- /dev/null
+++ b/tests/template/tredefinition.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "redefinition of 'a`gensym"
+  line: 9
+"""
+# bug #10180
+proc f() =
+  template t() =
+    var a = 1
+    var a = 2
+    echo a
+  t()
+
+f()
diff --git a/tests/template/tredefinition_override.nim b/tests/template/tredefinition_override.nim
new file mode 100644
index 000000000..7ae232bba
--- /dev/null
+++ b/tests/template/tredefinition_override.nim
@@ -0,0 +1,33 @@
+{.push warningAsError[ImplicitTemplateRedefinition]: on.}
+
+doAssert not (compiles do:
+  template foo(): int = 1
+  template foo(): int = 2)
+doAssert (compiles do:
+  template foo(): int = 1
+  template foo(): int {.redefine.} = 2)
+doAssert not (compiles do:
+  block:
+    template foo() =
+      template bar: string {.gensym.} = "a"
+      template bar: string {.gensym.} = "b"
+    foo())
+doAssert (compiles do:
+  block:
+    template foo() =
+      template bar: string {.gensym.} = "a"
+      template bar: string {.gensym, redefine.} = "b"
+    foo())
+
+block:
+  template foo(): int = 1
+  template foo(): int {.redefine.} = 2
+  doAssert foo() == 2
+block:
+  template foo(): string =
+    template bar: string {.gensym.} = "a"
+    template bar: string {.gensym, redefine.} = "b"
+    bar()
+  doAssert foo() == "b"
+
+{.pop.}
diff --git a/tests/template/tscope.nim b/tests/template/tscope.nim
new file mode 100644
index 000000000..1eeebbdd4
--- /dev/null
+++ b/tests/template/tscope.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "redefinition of 'x'"
+"""
+
+var x = 1
+template quantity() =
+  # Causes internal error in compiler/sem.nim
+  proc unit*(x = 1.0): float = 12
+  # Throws the correct error: redefinition of 'x'
+  #proc unit*(y = 1.0): float = 12
+quantity()
+var x = 2
diff --git a/tests/template/tshadow.nim b/tests/template/tshadow.nim
new file mode 100644
index 000000000..a4de71592
--- /dev/null
+++ b/tests/template/tshadow.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''fish
+fish'''
+"""
+
+import macros
+
+block:
+  template init(initHook: proc(s: string)) =
+    proc dostuff =
+      var s = "fish"
+      initHook(s)
+    dostuff()
+
+  init do(s: string):
+    echo s
+
+block:
+  macro init(initHook: proc(s: string)) =
+    result = newStmtList(
+      newProc(name = ident("dostuff"), body = newStmtList(
+        newVarStmt(ident("s"), newStrLitNode("fish")),
+        newCall(initHook, ident("s"))
+      )),
+      newCall("dostuff")
+    )
+
+  init proc(s: string) =
+    echo s
diff --git a/tests/template/tsighash_regression.nim b/tests/template/tsighash_regression.nim
new file mode 100644
index 000000000..f3a6b4833
--- /dev/null
+++ b/tests/template/tsighash_regression.nim
@@ -0,0 +1,8 @@
+discard """
+exitcode: 1
+outputsub: "0"
+"""
+
+import tconfusinglocal
+
+fail "foo"
diff --git a/tests/template/tstempl.nim b/tests/template/tstempl.nim
new file mode 100644
index 000000000..649082041
--- /dev/null
+++ b/tests/template/tstempl.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''global = levB, arg = levA, test = false
+levB'''
+"""
+
+# tstempl.nim
+import strutils
+
+type
+  TLev = enum
+    levA,
+    levB
+
+var abclev = levB
+
+template tstLev(abclev: TLev) =
+  bind tstempl.abclev, `%`
+  writeLine(stdout, "global = $1, arg = $2, test = $3" % [
+    $tstempl.abclev, $abclev, $(tstempl.abclev == abclev)])
+  # evaluates to true, but must be false
+
+
+tstLev(levA)
+writeLine(stdout, $abclev)
diff --git a/tests/template/ttempl2.nim b/tests/template/ttempl2.nim
new file mode 100644
index 000000000..e84e0630b
--- /dev/null
+++ b/tests/template/ttempl2.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "undeclared identifier: \'b\'"
+  file: "ttempl2.nim"
+  line: 18
+"""
+template declareInScope(x: untyped, t: typeDesc): untyped =
+  var x: t
+
+template declareInNewScope(x: untyped, t: typeDesc): untyped =
+  # open a new scope:
+  block:
+    var x: t
+
+declareInScope(a, int)
+a = 42  # works, `a` is known here
+
+declareInNewScope(b, int)
+b = 42  #ERROR_MSG undeclared identifier: 'b'
diff --git a/tests/template/ttempl3.nim b/tests/template/ttempl3.nim
new file mode 100644
index 000000000..17421cd87
--- /dev/null
+++ b/tests/template/ttempl3.nim
@@ -0,0 +1,83 @@
+discard """
+action: compile
+"""
+
+
+template withOpenFile(f: untyped, filename: string, mode: FileMode,
+                      actions: untyped): untyped =
+  block:
+    # test that 'f' is implicitly 'injecting':
+    var f: File
+    if open(f, filename, mode):
+      try:
+        actions
+      finally:
+        close(f)
+    else:
+      quit("cannot open for writing: " & filename)
+
+withOpenFile(txt, "ttempl3.txt", fmWrite):
+  writeLine(txt, "line 1")
+  txt.writeLine("line 2")
+
+var
+  myVar: array[0..1, int]
+
+# Test zero argument template:
+template ha: untyped = myVar[0]
+
+ha = 1
+echo(ha)
+
+
+# Test identifier generation:
+template prefix(name): untyped = `"hu" name`
+
+var `hu "XYZ"` = "yay"
+
+echo prefix(XYZ)
+
+template typedef(name: untyped, typ: typeDesc) {.dirty.} =
+  type
+    `T name`* = typ
+    `P name`* = ref `T name`
+
+typedef(myint, int)
+var x: PMyInt
+
+
+# Test UFCS
+
+type
+  Foo = object
+    arg: int
+
+proc initFoo(arg: int): Foo =
+  result.arg = arg
+
+template create(typ: typeDesc, arg: untyped): untyped = `init typ`(arg)
+
+var ff = Foo.create(12)
+
+echo ff.arg
+
+
+import macros
+
+# bug #11494
+macro staticForEach(arr: untyped, body: untyped): untyped =
+  result = newNimNode(nnkStmtList)
+  arr.expectKind(nnkBracket)
+  for n in arr:
+    let b = copyNimTree(body)
+    result.add quote do:
+      block:
+        type it {.inject.} = `n`
+        `b`
+
+template forEveryMatchingEntity*() =
+  staticForEach([int, string, float]):
+    var a {.inject.}: it
+    echo a
+
+forEveryMatchingEntity()
diff --git a/tests/template/tunderscore1.nim b/tests/template/tunderscore1.nim
new file mode 100644
index 000000000..d74e5ba63
--- /dev/null
+++ b/tests/template/tunderscore1.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "the special identifier '_' is ignored in declarations and cannot be used"
+"""
+
+# issue #12094, #13804
+
+template foo =
+  let _ = 1
+  echo _
+
+foo()
diff --git a/tests/template/twhenintemplates.nim b/tests/template/twhenintemplates.nim
new file mode 100644
index 000000000..6fded856d
--- /dev/null
+++ b/tests/template/twhenintemplates.nim
@@ -0,0 +1,11 @@
+# bug #3670
+
+template someTempl(someConst: bool) =
+  when someConst:
+    var a : int
+  if true:
+    when not someConst:
+      var a : int
+    a = 5
+
+someTempl(true)
diff --git a/tests/template/twrong_getast.nim b/tests/template/twrong_getast.nim
new file mode 100644
index 000000000..1d158f7a5
--- /dev/null
+++ b/tests/template/twrong_getast.nim
@@ -0,0 +1,19 @@
+discard """
+  errormsg: "expected a template that takes 3 arguments"
+  line: 16
+"""
+
+import macros
+
+template grainBlock(proxyTypeName: untyped, proxyProcs: untyped): typed =
+  discard
+
+var
+  proxyTypeName: string
+  proxyProcs: string
+
+macro foo(): untyped =
+  let x = getAst grainBlock(proxyTypeName, proxyProcs, proxyTypeName)
+
+foo()
+
diff --git a/tests/template/twrongmapit.nim b/tests/template/twrongmapit.nim
new file mode 100644
index 000000000..2d53d03f5
--- /dev/null
+++ b/tests/template/twrongmapit.nim
@@ -0,0 +1,30 @@
+discard """
+  joinable: false
+"""
+
+# bug #1562
+type Foo* {.pure, final.} = object
+  elt: float
+
+template defineOpAssign(T, op: untyped) =
+  proc `op`*(v: var T, w: T) {.inline.} =
+    for i in 0..1:
+      `op`(v.elt, w.elt)
+
+const ATTEMPT = 0
+
+when ATTEMPT == 0:
+  # FAILS: defining `/=` with template calling template
+  # ERROR about sem.nim line 144
+  template defineOpAssigns(T: untyped) =
+    mixin `/=`
+    defineOpAssign(T, `/=`)
+
+  defineOpAssigns(Foo)
+
+# bug #1543
+import sequtils
+
+(var i = @[""];i).applyIt(it)
+# now works:
+doAssert i[0] == ""
diff --git a/tests/template/twrongopensymchoice.nim b/tests/template/twrongopensymchoice.nim
new file mode 100644
index 000000000..7a2bb48d3
--- /dev/null
+++ b/tests/template/twrongopensymchoice.nim
@@ -0,0 +1,24 @@
+discard """
+  output: '''10'''
+"""
+
+# bug #940
+
+type
+  Foo* = ref object
+    b*: int
+
+proc new*(this: var Foo) =
+  assert this != nil
+  this.b = 10
+
+proc new*(T: typedesc[Foo]): Foo =
+  system.new(result)
+  twrongopensymchoice.new(result)
+
+proc main =
+  var f = Foo.new()
+  echo f.b
+
+when true:
+  main()
diff --git a/tests/template/twrongsymkind.nim b/tests/template/twrongsymkind.nim
new file mode 100644
index 000000000..5fa618914
--- /dev/null
+++ b/tests/template/twrongsymkind.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "cannot use symbol of kind 'var' as a 'param'"
+  line: 20
+"""
+
+# bug #3158
+
+type
+  MyData = object
+      x: int
+
+template newDataWindow(data: ref MyData): untyped =
+    proc testProc(data: ref MyData) =
+        echo "Hello, ", data.x
+    testProc(data)
+
+var d: ref MyData
+new(d)
+d.x = 10
+newDataWindow(d)
diff --git a/tests/template/utemplates.nim b/tests/template/utemplates.nim
new file mode 100644
index 000000000..d70746578
--- /dev/null
+++ b/tests/template/utemplates.nim
@@ -0,0 +1,36 @@
+import unittest
+
+template t(a: int): string = "int"
+template t(a: string): string = "string"
+
+block: # templates can be overloaded
+  check t(10) == "int"
+  check t("test") == "string"
+
+block: # previous definitions can be further overloaded or hidden in local scopes
+  template t(a: bool): string = "bool"
+
+  check t(true) == "bool"
+  check t(10) == "int"
+
+  template t(a: int): string = "inner int"
+  check t(10) == "inner int"
+  check t("test") == "string"
+
+block: # templates can be redefined multiple times
+  template customAssert(cond: bool, msg: string): typed {.dirty.} =
+    if not cond: fail(msg)
+
+  template assertionFailed(body: untyped) {.dirty.} =
+    template fail(msg: string): typed {.redefine.} =
+      body
+
+  assertionFailed:
+    check(msg == "first fail path")
+
+  customAssert false, "first fail path"
+
+  assertionFailed:
+    check(msg == "second fail path")
+
+  customAssert false, "second fail path"
diff --git a/tests/tendian.nim b/tests/tendian.nim
deleted file mode 100755
index 256e2653c..000000000
--- a/tests/tendian.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-# test the new endian magic
-
-writeln(stdout, repr(system.cpuEndian))
diff --git a/tests/tenum.nim b/tests/tenum.nim
deleted file mode 100755
index 6e53b9c08..000000000
--- a/tests/tenum.nim
+++ /dev/null
@@ -1,8 +0,0 @@
-# Test enums

-

-type

-  E = enum a, b, c, x, y, z

-

-var

-  en: E

-en = a

diff --git a/tests/test_nimscript.nims b/tests/test_nimscript.nims
new file mode 100644
index 000000000..32b7d1416
--- /dev/null
+++ b/tests/test_nimscript.nims
@@ -0,0 +1,138 @@
+# This nimscript is used to test if the following modules can be imported
+# http://nim-lang.org/docs/nims.html
+
+{.warning[UnusedImport]: off.}
+
+from stdtest/specialpaths import buildDir
+
+when defined(nimPreviewSlimSystem):
+  import std/[
+    syncio, assertions, formatfloat, objectdollar, widestrs
+  ]
+
+import std/[
+  # Core:
+  bitops, typetraits, lenientops, macros, volatile,
+  # fails due to FFI: typeinfo
+  # fails due to cstring cast/copyMem: endians
+  # works but uses FFI: cpuinfo, rlocks, locks
+
+  # Algorithms:
+  algorithm, enumutils, sequtils, setutils,
+
+  # Collections:
+  critbits, deques, heapqueue, intsets, lists, options, sets,
+  tables, packedsets,
+
+  # Strings:
+  editdistance, wordwrap, parseutils, ropes,
+  pegs, strformat, strmisc, strscans, strtabs,
+  strutils, unicode, unidecode, cstrutils,
+  # works but uses FFI: encodings
+
+  # Time handling:
+  # fails due to FFI: monotimes, times
+  # but times.getTime() implemented for VM
+
+  # Generic operator system services:
+  os, streams, distros,
+  # fails due to FFI: memfiles, osproc, terminal
+  # works but uses FFI: dynlib
+  # intentionally fails: marshal
+
+  # Math libraries:
+  complex, math, random, rationals, stats, sums,
+  # works but uses FFI: fenv, sysrand
+
+  # Internet protocols:
+  httpcore, mimetypes, uri,
+  # fails due to FFI: asyncdispatch, asyncfile, asyncftpclient, asynchttpserver,
+  # asyncnet, cgi, cookies, httpclient, nativesockets, net, selectors, smtp
+  # works but no need to test: asyncstreams, asyncfutures
+
+  # Threading:
+  # fails due to FFI: threadpool
+
+  # Parsers:
+  htmlparser, json, lexbase, parsecfg, parsecsv, parsesql, parsexml,
+  parseopt, jsonutils,
+
+  # XML processing:
+  xmltree, xmlparser,
+
+  # Generators:
+  htmlgen,
+
+  # Hashing:
+  base64, hashes,
+  # fails due to cstring cast/times import/endians import: oids
+  # fails due to copyMem/endians import: sha1
+
+  # Miscellaneous:
+  colors, sugar, varints, enumerate, with,
+  # fails due to FFI: browsers, coro, segfaults
+  # fails due to times import/methods: logging
+  # fails due to methods: unittest
+
+  # Modules for JS backend:
+  # fails intentionally: asyncjs, dom, jsconsole, jscore, jsffi, jsbigints,
+  # jsfetch, jsformdata, jsheaders
+
+  # Unlisted in lib.html:
+  decls, compilesettings, wrapnils, effecttraits, genasts,
+  importutils, isolation
+]
+
+# non-std imports
+import stdtest/testutils
+# tests (increase coverage via code reuse)
+import stdlib/trandom
+import stdlib/tosenv
+
+echo "Nimscript imports are successful."
+
+block:
+  doAssert "./foo//./bar/".normalizedPath == "foo/bar".unixToNativePath
+block:
+  doAssert $3'u == "3"
+  doAssert $3'u64 == "3"
+
+block: # #14142
+  discard dirExists("/usr")
+  discard fileExists("/usr/foo")
+  discard findExe("nim")
+
+block:
+  doAssertRaises(AssertionDefect): doAssert false
+  try: doAssert false
+  except Exception as e:
+    discard
+
+block:  # cpDir, cpFile, dirExists, fileExists, mkDir, mvDir, mvFile, rmDir, rmFile
+  const dname = buildDir/"D20210121T175016"
+  const subDir = dname/"sub"
+  const subDir2 = dname/"sub2"
+  const fpath = subDir/"f"
+  const fpath2 = subDir/"f2"
+  const fpath3 = subDir2/"f"
+  mkDir(subDir)
+  writeFile(fpath, "some text")
+  cpFile(fpath, fpath2)
+  doAssert fileExists(fpath2)
+  rmFile(fpath2)
+  cpDir(subDir, subDir2)
+  doAssert fileExists(fpath3)
+  rmDir(subDir2)
+  mvFile(fpath, fpath2)
+  doAssert not fileExists(fpath)
+  doAssert fileExists(fpath2)
+  mvFile(fpath2, fpath)
+  mvDir(subDir, subDir2)
+  doAssert not dirExists(subDir)
+  doAssert dirExists(subDir2)
+  mvDir(subDir2, subDir)
+  rmDir(dname)
+
+block:
+  # check parseopt can get command line:
+  discard initOptParser()
diff --git a/tests/testament/t16576.nim b/tests/testament/t16576.nim
new file mode 100644
index 000000000..8d0dd57e3
--- /dev/null
+++ b/tests/testament/t16576.nim
@@ -0,0 +1,7 @@
+discard """
+  matrix:"-d:nimTest_t16576"
+"""
+
+# bug #16576
+doAssert defined(nimTest_t16576)
+doAssert not defined(nimMegatest)
diff --git a/tests/testament/tinlinemsg.nim b/tests/testament/tinlinemsg.nim
new file mode 100644
index 000000000..199c263e9
--- /dev/null
+++ b/tests/testament/tinlinemsg.nim
@@ -0,0 +1,8 @@
+discard """
+  matrix: "--errorMax:0 --styleCheck:error"
+"""
+
+proc generic_proc*[T](a_a: int) = #[tt.Error
+     ^ 'generic_proc' should be: 'genericProc'; tt.Error
+                      ^ 'a_a' should be: 'aA' ]#
+  discard
diff --git a/tests/testament/tjoinable.nim b/tests/testament/tjoinable.nim
new file mode 100644
index 000000000..c651780de
--- /dev/null
+++ b/tests/testament/tjoinable.nim
@@ -0,0 +1,9 @@
+discard """
+  output: "ok"
+"""
+
+# checks that this is joinable
+# checks that megatest allows duplicate names, see also `tests/misc/tjoinable.nim`
+doAssert defined(testing)
+doAssert defined(nimMegatest)
+echo "ok" # intentional to make sure this doesn't prevent `isJoinableSpec`
diff --git a/tests/testament/treject.nim b/tests/testament/treject.nim
new file mode 100644
index 000000000..be2db86a9
--- /dev/null
+++ b/tests/testament/treject.nim
@@ -0,0 +1,6 @@
+discard """
+action: "reject"
+"""
+
+# this line does not compile, so the test should pass, since action="reject"
+let x: int = "type mismatch"
diff --git a/tests/testament/tshould_not_work.nim b/tests/testament/tshould_not_work.nim
new file mode 100644
index 000000000..8c99510a0
--- /dev/null
+++ b/tests/testament/tshould_not_work.nim
@@ -0,0 +1,53 @@
+discard """
+  joinable: false
+"""
+
+const expected = """
+FAIL: tests/shouldfail/tccodecheck.nim
+Failure: reCodegenFailure
+Expected:
+baz
+FAIL: tests/shouldfail/tcolumn.nim
+Failure: reLinesDiffer
+FAIL: tests/shouldfail/terrormsg.nim
+Failure: reMsgsDiffer
+FAIL: tests/shouldfail/texitcode1.nim
+Failure: reExitcodesDiffer
+FAIL: tests/shouldfail/tfile.nim
+Failure: reFilesDiffer
+FAIL: tests/shouldfail/tline.nim
+Failure: reLinesDiffer
+FAIL: tests/shouldfail/tmaxcodesize.nim
+Failure: reCodegenFailure
+max allowed size: 1
+FAIL: tests/shouldfail/tnimout.nim
+Failure: reMsgsDiffer
+FAIL: tests/shouldfail/tnimoutfull.nim
+Failure: reMsgsDiffer
+FAIL: tests/shouldfail/toutput.nim
+Failure: reOutputsDiffer
+FAIL: tests/shouldfail/toutputsub.nim
+Failure: reOutputsDiffer
+FAIL: tests/shouldfail/treject.nim
+Failure: reFilesDiffer
+FAIL: tests/shouldfail/tsortoutput.nim
+Failure: reOutputsDiffer
+FAIL: tests/shouldfail/ttimeout.nim
+Failure: reTimeout
+FAIL: tests/shouldfail/tvalgrind.nim
+Failure: reExitcodesDiffer
+"""
+
+import std/[os,strformat,osproc]
+import stdtest/testutils
+
+proc main =
+  const nim = getCurrentCompilerExe()
+  let testamentExe = "bin/testament"
+  let cmd = fmt"{testamentExe} --directory:testament --colors:off --backendLogging:off --nim:{nim} category shouldfail"
+  let (outp, status) = execCmdEx(cmd)
+  doAssert status == 1, $status
+
+  let ok = greedyOrderedSubsetLines(expected, outp, allowPrefixMatch = true)
+  doAssert ok, &"\nexpected:\n{expected}\noutp:\n{outp}"
+main()
diff --git a/tests/testament/tspecialpaths.nim b/tests/testament/tspecialpaths.nim
new file mode 100644
index 000000000..3c97dc88a
--- /dev/null
+++ b/tests/testament/tspecialpaths.nim
@@ -0,0 +1,9 @@
+import stdtest/specialpaths
+import std/os
+block: # splitTestFile
+  doAssert splitTestFile("tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath)
+  doAssert splitTestFile("/pathto/tests/fakedir/tfakename.nim") == ("fakedir", "/pathto/tests/fakedir/tfakename.nim".unixToNativePath)
+  doAssert splitTestFile(getCurrentDir() / "tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath)
+  doAssert splitTestFile(getCurrentDir() / "sub/tests/fakedir/tfakename.nim") == ("fakedir", "sub/tests/fakedir/tfakename.nim".unixToNativePath)
+  doAssertRaises(AssertionDefect): discard splitTestFile("testsbad/fakedir/tfakename.nim")
+  doAssertRaises(AssertionDefect): discard splitTestFile("tests/tfakename.nim")
diff --git a/tests/csvtest.csv b/tests/testdata/csvtest.csv
index 6e7e14103..6e7e14103 100755..100644
--- a/tests/csvtest.csv
+++ b/tests/testdata/csvtest.csv
diff --git a/tests/data.csv b/tests/testdata/data.csv
index ea73f7387..ea73f7387 100755..100644
--- a/tests/data.csv
+++ b/tests/testdata/data.csv
diff --git a/tests/testdata/doc1.xml b/tests/testdata/doc1.xml
new file mode 100644
index 000000000..07cbceeb7
--- /dev/null
+++ b/tests/testdata/doc1.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<root>
+  <tag>
+    <test arg="blah" arg2="test"/>
+    <test2>
+      bla ah absy hsh
+      hsh
+      &woohoo;
+      sjj
+    </test2>
+    <test><teh>bla</teh></test>
+  </tag>
+</root>
+
+
diff --git a/tests/testdata/jsontest.json b/tests/testdata/jsontest.json
new file mode 100644
index 000000000..3a815e50f
--- /dev/null
+++ b/tests/testdata/jsontest.json
@@ -0,0 +1,26 @@
+// Simple JSON test file
+// (c) 2011 Andreas Rumpf
+
+/* a long comment */
+
+{
+  "key1": null,
+  "obj": {"1": 2, "5": 4},
+  
+  "key2": [
+    {},
+    {   },
+    [],
+    
+    [ // empty array
+    ],
+    
+    -1e10 // another comment
+    
+  
+  ]        ,
+  "keyÄÖöoß\u00DF": false
+}
+
+// [{}, {899: 12, "x": "y"}, [], 123, 89, 89, "xyz", null, [], [], [1, 2, 3]]
+
diff --git a/tests/testdata/jsontest2.json b/tests/testdata/jsontest2.json
new file mode 100644
index 000000000..3a2294474
--- /dev/null
+++ b/tests/testdata/jsontest2.json
@@ -0,0 +1,80 @@
+{
+  "after": "b85008345e2faa23024b222e2e6b17f7ef8b6270", 
+  "before": "f469a6fba9a81ac06d813761e346673fbc8a6ef6", 
+  "commits": [
+    {
+      "added": [], 
+      "author": {
+        "email": "dominikpicheta@googlemail.com", 
+        "name": "dom96", 
+        "username": "dom96"
+      }, 
+      "id": "9e887b88a633c432d8e6859d7fab5429128aea7e", 
+      "message": "Added getPort and fixed a problem with the Disconnect event.", 
+      "modified": [
+        "Network\/SimpleIRC\/Core.hs"
+      ], 
+      "removed": [], 
+      "timestamp": "2010-10-24T03:16:30-07:00", 
+      "url": "https:\/\/github.com\/dom96\/SimpleIRC\/commit\/9e887b88a633c432d8e6859d7fab5429128aea7e"
+    }, 
+    {
+      "added": [
+        "tests\/channelNickTracking.hs"
+      ], 
+      "author": {
+        "email": "dominikpicheta@googlemail.com", 
+        "name": "dom96", 
+        "username": "dom96"
+      }, 
+      "id": "001c4a1834a95fa3cb4c6fefc3df9508c6e6b58a", 
+      "message": "Channel and nick tracking fully work now.", 
+      "modified": [
+        "Network\/SimpleIRC\/Core.hs", 
+        "Network\/SimpleIRC\/Messages.hs"
+      ], 
+      "removed": [], 
+      "timestamp": "2010-10-24T04:01:28-07:00", 
+      "url": "https:\/\/github.com\/dom96\/SimpleIRC\/commit\/001c4a1834a95fa3cb4c6fefc3df9508c6e6b58a"
+    }, 
+    {
+      "added": [], 
+      "author": {
+        "email": "dominikpicheta@googlemail.com", 
+        "name": "dom96", 
+        "username": "dom96"
+      }, 
+      "id": "b85008345e2faa23024b222e2e6b17f7ef8b6270", 
+      "message": "Forgot to export getPort.", 
+      "modified": [
+        "Network\/SimpleIRC\/Core.hs"
+      ], 
+      "removed": [], 
+      "timestamp": "2010-10-24T04:18:38-07:00", 
+      "url": "https:\/\/github.com\/dom96\/SimpleIRC\/commit\/b85008345e2faa23024b222e2e6b17f7ef8b6270"
+    }
+  ], 
+  "compare": "https:\/\/github.com\/dom96\/SimpleIRC\/compare\/f469a6f...b850083", 
+  "forced": false, 
+  "ref": "refs\/heads\/master", 
+  "repository": {
+    "created_at": "2010\/08\/13 10:24:57 -0700", 
+    "description": "IRC Library for Haskell", 
+    "fork": false, 
+    "forks": 1, 
+    "has_downloads": true, 
+    "has_issues": true, 
+    "has_wiki": true, 
+    "homepage": "http:\/\/hackage.haskell.org\/package\/simpleirc", 
+    "name": "SimpleIRC", 
+    "open_issues": 1, 
+    "owner": {
+      "email": "dominikpicheta@googlemail.com", 
+      "name": "dom96"
+    }, 
+    "private": false, 
+    "pushed_at": "2010\/10\/24 04:18:48 -0700", 
+    "url": "https:\/\/github.com\/dom96\/SimpleIRC", 
+    "watchers": 7
+  }
+}
diff --git a/tests/testdata/jsonwithextradata.json b/tests/testdata/jsonwithextradata.json
new file mode 100644
index 000000000..f6b6e7c80
--- /dev/null
+++ b/tests/testdata/jsonwithextradata.json
@@ -0,0 +1,6 @@
+{
+    "foo": 123,
+    "bar": 456
+}
+
+"foobar"
diff --git a/tests/testdata/mycert.pem b/tests/testdata/mycert.pem
new file mode 100644
index 000000000..61dcb685c
--- /dev/null
+++ b/tests/testdata/mycert.pem
@@ -0,0 +1,81 @@
+-----BEGIN PRIVATE KEY-----
+MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDgpWhnNdNSUbwJ
+39mKf+PA879K1wyT23LC3Ipo5g5vaRjB4vrSh5vzrjK5Q/z42yRDLQ2ojEdUne19
+1xMaM+WqTXnfkf9sou4VJ0HsdQ6jOU1LDRPrPvCjHLZjyMu18sGvQf4FATBwWN3n
+QhmvcbleTeyv2pgMNeQDfjuIhRJ/aCIi/WYQ466+Rcj0y3/udYX1yPYf2mszXnSE
+i2iWgdsjx0qkDU/nJhnKXhKfucAm9Ds0YfQdZYN3rEzfGkJzZUhDG1n30ghu+vUg
+qqLi6HU/HqBxKxBlJf2HdMNK4VLkJuFC+wCI0JfF6VYhcNmtZzlQy3M9WjYvbXUY
+nvMkQzUECaSaAtmbhFFfgey1Q3IEQS/j1lsVxtuGUE3YaoyaK22/CkVInDz0aka9
+CKq77x7S/V5PP/wwPV4s8XsbT6/34KemuY3oU84+bf5SBuWdzBY0hnDO9c/FaOnZ
+4yjLMQi285HLpK417Z32DmzIkb7GjKtP9WLvsWGgbgquEjcFaIT+erkN09cDjsG/
+URWbKcsQkz8v9E4zj0rxdanXoJEtg1gm+dPsiXokZOLTeaMVtDoTkWeCM/VAp25J
+MTc656QRUTSzUODK5tXQ3JgE2XIPGV/PsMi7T/q9xFBQmhUk5kfLNlQ1cy/aiTWK
+8pjHcmxbyD121AimuTtv9CFYnYtzyQIDAQABAoICAAMYZFrfs/yzYZrlObMd1f6H
+nUAjvGmhIXCr50BQwywnz46EWR5jffOal9pTpH2tT0+ZpFGJNUZmMqqENyAqTOTO
+0noRIerWR9+EvfTLHBuFo5oAISEhqeEleSHg12W3ZZHLn/tjq84we0Y/c+kl8P7q
+pfM6WNP6Ph0KNTnJU5rrzWScBzb+XB8FCSLOVwHrHqBnV3TS5p07lPFqllNUkLdq
+fI3MHSi7LqnKKAmJXqtqvBIZs2pgRrJ0bk64pue+IoPCMbgnbbRRwuTjVQE5YLww
+6NcGV+B86IRgSHyUpDa+jmYE3VoFPcIdV/F4A5fPD0wcsYbL4mk+4dkn/4OlZWqV
+NZILp2IGejKaKtM1fr7fV2IRUbGUBN/+rX4I0SRnuq6Q4Ipx8VASbpgXQPBo9XTg
+SHHsFbEu2DL8BHVgXdOy4PW6jQ0Ux2LhuJk6AQ5nIlFBYA+c8rSlZQXJbEbk1VZu
+1i7iSOn/kx3ULMjUfhI/Ddm6rQqtiLbXSubXCzu1HMPT1FG9LUfAbq6EpiVkpAk1
+TqlciBHsyz//mk2RmIEx0Bt+0bX8FFGTIUiGyrp5s4hAHbgQZbXBAUYMRzWxhZ2Q
+G0KBXx46bv3hJUb0GOgbNVxcaPnyrXaS/Hafcbx2LXlEtKiwGnC/yKJ7Hmcrt+AQ
+RTaqNU1o/bkSYC7vHMZdAoIBAQD79uYPZPv5GLCKPZ64gc3+tbFXNqkmL7qv14yD
+Gr3VubRbJe3Fx+T1cS+t9cjgOofhjFnwsDaFRoyWOYqRV/znwFsvvsDhHOLBr1u6
+qWQiF2CT1uMdXR3P6KD8h2DUVNNccxKqqIJNCR5oD/ngnnByWkQobzlsnoIdXgZm
+ozBZjGr2XUMO5dJqUxaXZwY3j4I2hk/Ka9uroApyptl+DTVbPHvjk3MzU9QKUNor
+vXEtQ8EmM8Oy6v/33HBmNs6cF5fMpgWz6u+B357OTxAfu8B42jZ18OeLrvkHFxzu
+phOB1uXvqtQ0tdksSHHWj3IIZRK7GDGudnDEZ23vbCaxH4zbAoIBAQDkPn+5N3px
+7UAECWrvT10TD3xKeqMkFhqRA9gmDE4N9AdoN6T6PzD7Tr3gOgGLq1tXjCjBqAlx
+ZIDTnih3IK3xoRk2zmhq5+LfM8LQRAxAC8IsoQMXAsmW1KlS6MR70m50pFR8NK6r
+UmOdrwVUKp3K6Mecid3LmMVLXGMUKwIJc1k7LJHtwrfi0i5xfBtiqQeaR0lJg4Zr
++zEL/4rHfcq06/P3k0+4uLKZ1LGOvwLPiTA3DADPWZbzUXo7McKOFWF/ycGQBrJq
+AJikx15dVLnB16bnHXdxrlrd0LON2R+XfT4+dfRymqZLzrBI3L39t/elTmVYnD3P
+punkmZuVwNErAoIBAQD5xOiOPibh6S2n/CmI8XQImIgx0kefSRUhFuV9WVbxtOMq
+r9CijONUw1zmb40vahYk6gKGa8fAGg1nJadNKRHVkoNSMx/0h7PpGDIwOZa/jLj6
+FLyS8SmKXiqn6nN8SJI1RQUuE1kHkJCJy7yCg80oLn7+LjOYjxCgmAJ0YDSfsGif
+zBebfws0xyTP9RrenO4RqtcR7BWYbk+tE+Tp5aIMzUpqcFJ0gRbjGv8K+QJmQpIH
+kqzegcI4LFdnm9D4PxMFlVZ14eCGt+wuy4VKT84efwIZrDN77nmCI9FUaWFRBnxt
+NsShc9rS4QWoEg6Sb88/lF47ecGTkIwUGPvJ/WKdAoIBAQClF7/zDPn4Zg+j29wJ
+dXJxUwYoKUTP2V0l/43dF5Ft7lFdRMKEcCjR3kbhZZOwnyXW0X65dP4/kt7MMt46
+LN0kpc5DIlHM4iXsJNiJJG9n9BljhqNhhZajDvfbDJrypWdX33Vs0f511YZQjERi
+eODh4DZiOCbCGaK7u/u+ns0+YLzuXHLBc9Lmsfj+BTMZzgG9ykpsbkJQ4MS9VP3h
+BlAVRYaWUWucxZwKQRqdkfRKgYTqjDgZw0e4f/rVzkxX0YdQk3L65p0up3fB2KOd
+BqfGWmJTUbEP/XmkcE0wERkUznazX0aNjucydjJ0wZZ7axIp8+bCjWD4TldoDuPH
+Ek05AoIBAECgPfBHLQTAsI+wHbFsu/are28BOiJCSEXjRv88CbUbj/qgAppFuXbx
+900WwJ1rVWd5x3LFa3VfyuAqYMi5jzmX9kWgEsC0WhgfyIRFiynw45LlcT4u3fWg
+vJEx01lGgFVjnYfFUDS9d1MuiXGxIHrNhzHOP2x2CsS5vrFHav7iwG9YULEk8tJr
+My0wzjF3UJ2/5DjGK56WuzauLYKrQ6Faw8dWUy4e/bNYId8wglhQQW548JwJEGmq
+nq+EzTfEupXH57Bw7MGEOfdlhv98zNT9VcvBAN09vHeF3Hh6AM4aiGSUIt2HIkto
+zvw+fqZ2Sk9O5qva+KE1QMVtY1EICI8=
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIFCTCCAvGgAwIBAgIUKqDcJ71wiMObIQ5sga2sZItNseowDQYJKoZIhvcNAQEL
+BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIyMDUwNDExMzAwN1oXDTIyMDYw
+MzExMzAwN1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA4KVoZzXTUlG8Cd/Zin/jwPO/StcMk9tywtyKaOYOb2kY
+weL60oeb864yuUP8+NskQy0NqIxHVJ3tfdcTGjPlqk1535H/bKLuFSdB7HUOozlN
+Sw0T6z7woxy2Y8jLtfLBr0H+BQEwcFjd50IZr3G5Xk3sr9qYDDXkA347iIUSf2gi
+Iv1mEOOuvkXI9Mt/7nWF9cj2H9prM150hItoloHbI8dKpA1P5yYZyl4Sn7nAJvQ7
+NGH0HWWDd6xM3xpCc2VIQxtZ99IIbvr1IKqi4uh1Px6gcSsQZSX9h3TDSuFS5Cbh
+QvsAiNCXxelWIXDZrWc5UMtzPVo2L211GJ7zJEM1BAmkmgLZm4RRX4HstUNyBEEv
+49ZbFcbbhlBN2GqMmittvwpFSJw89GpGvQiqu+8e0v1eTz/8MD1eLPF7G0+v9+Cn
+prmN6FPOPm3+UgblncwWNIZwzvXPxWjp2eMoyzEItvORy6SuNe2d9g5syJG+xoyr
+T/Vi77FhoG4KrhI3BWiE/nq5DdPXA47Bv1EVmynLEJM/L/ROM49K8XWp16CRLYNY
+JvnT7Il6JGTi03mjFbQ6E5FngjP1QKduSTE3OuekEVE0s1DgyubV0NyYBNlyDxlf
+z7DIu0/6vcRQUJoVJOZHyzZUNXMv2ok1ivKYx3JsW8g9dtQIprk7b/QhWJ2Lc8kC
+AwEAAaNTMFEwHQYDVR0OBBYEFEZcUeqH6MfIzC56BlD3NSs2mCgGMB8GA1UdIwQY
+MBaAFEZcUeqH6MfIzC56BlD3NSs2mCgGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBADGc7WONP6I6Trb7ici9fQ9qT3wh/RGDcmUDmDtARn9SFtOF
+hsbszOMZg1Flj10fuD6OYDonKz4rv+Ieo5VkAYXxxd3J+bx2x1pqd1YSIsvugTwv
+pnx39uBR9cjOmt4W7RyzhFnXoVfuSBE6LpkBUjcrqi5xwrQ31mOSCPwe8uDZYEWS
+pX49MiHXGTyjQ481QLiOtTBZJa5igfnHUJbJbyZMa86zBQ/clS7+OeDwkvaEpjov
+2VQf3QouVLghfLZYWSxWdEKD9+IWHn8rV6qksEb/Ogu4ZtzDRGqJow4j0DeSSEu7
+ns1YeT2mVTFwHjGXCWS+0iE885NDVX/b5YptlwH5PW7aqeXyCS9Hrd1C1GnXoXGp
+NHltYRTyNWm974xWg7eu2gbbB8Ng02chXysdkBq7l+7OyA0a2EfX3Cbz3/49+Mqn
+viqwNO5toSHVCdfV9Jd0p0CcqryYgyt2YNpJB+2nUQpiW4jviAs49PZg2PpCVw/2
+0cqtaPeUh26Si8UzDOuT697PIuGkZ9Q9QVwccVXtCyA0UpJ13P0fMrA+yEMhtwSs
+k1tRm0pUQa6t3v26/cAy+kMhviHBJFwi5dx+y3OMvqQqpQJrgfZawm/o2ZQHy1KP
+8m4ngrJzb13evKf216qCwllmQo6Ts4yeI1Ddx8UpdX7RUWpD8Uw4zSi7Th4r
+-----END CERTIFICATE-----
diff --git a/tests/testdata/string.txt b/tests/testdata/string.txt
new file mode 100644
index 000000000..102374bdb
--- /dev/null
+++ b/tests/testdata/string.txt
@@ -0,0 +1 @@
+Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
diff --git a/tests/testdata/wildhtml.html b/tests/testdata/wildhtml.html
new file mode 100644
index 000000000..dfab7ba95
--- /dev/null
+++ b/tests/testdata/wildhtml.html
@@ -0,0 +1,25 @@
+<!DOCTYPE some doctype >
+  
+<html>
+  <head>
+    <title>Test title!</title>
+  </head>
+
+  <body>
+    Ein Text mit vielen Zeichenumbr&uuml;chen. <br />
+    <br><br>
+    
+    <ul>
+      <li>first <span class = "34" >Item.</span>
+      <li>second Item.
+      <li>third item. Mit &auml;.
+    </ul>
+    
+    Para 0.
+    
+    <p>Para1. </p>
+    <p>Para 2.
+    
+  </body>
+</html>
+
diff --git a/tests/xmltest.html b/tests/testdata/xmltest.html
index 862a91d24..ca4abc4eb 100755..100644
--- a/tests/xmltest.html
+++ b/tests/testdata/xmltest.html
@@ -104,5 +104,8 @@ sh build.sh</pre>
     </div>
   </div>
 </body>
+
+  <bugtest att="value" />
+
 </html>
 
diff --git a/tests/tester.nim b/tests/tester.nim
deleted file mode 100755
index b09200aea..000000000
--- a/tests/tester.nim
+++ /dev/null
@@ -1,177 +0,0 @@
-#
-#
-#            Nimrod Tester
-#        (c) Copyright 2009 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-## This program verifies Nimrod against the testcases.
-## The testcases may contain the directives '#ERROR' or '#ERROR_IN'.
-## '#ERROR' is used to indicate that the compiler should report
-## an error in the marked line (the line that contains the '#ERROR'
-## directive.)
-## The format for '#ERROR_IN' is:
-##      #ERROR_IN filename linenumber
-## One can omit the extension of the filename ('.nim' is then assumed).
-## Tests which contain none of the two directives should compile. Thus they
-## are executed after successful compilation and their output is verified
-## against the results specified with the '#OUT' directive.
-## (Tests which require user interaction are not possible.)
-## Tests can have an #ERROR_MSG directive specifiying the error message
-## Nimrod shall produce.
-
-import
-  strutils, pegs, os, osproc, streams
-
-const
-  cmdTemplate = r"nimrod cc --hints:on $options $filename"
-
-type
-  TSpec = object of TObject ## specification object
-    line: int    ## line number where compiler should throw an error
-    file: string ## file where compiler should throw an error
-    err: bool    ## true if the specification says there should be an error
-    outp: string ## output that should be produced
-    puremsg: string ## pure message of compiler
-
-proc myExec(cmd: string): string =
-  #echo("Executing: " & cmd)
-  result = osproc.execProcess(cmd)
-  #echo("Received: " & result)
-
-proc parseTest(filename: string): TSpec =
-  var i = 0 # the line counter
-  var matches: array [0..2, string]
-  result.outp = ""
-  result.puremsg = ""
-  result.file = filename
-  for s in lines(filename):
-    inc(i)
-    if contains(s, peg"'#OUT' \s+ {.*}", matches):
-      result.outp = matches[0]
-      break
-    if contains(s, peg"'#ERROR_IN' \s* {\S*} \s* {\d+}", matches):
-      result.file = matches[0]
-      result.line = parseInt(matches[1])
-      result.err = true
-      break
-    if contains(s, peg"'#ERROR_MSG' \s* {.*}", matches):
-      result.line = i
-      result.outp = matches[0]
-      result.err = True
-      break
-    if contains(s, peg"'#ERROR' \s* !.", matches):
-      result.line = i
-      result.err = true
-      break
-
-var
-  pegLineError = peg"{[^(]*} '(' {\d+} ', ' \d+ ') Error:' \s* {.*}"
-  pegOtherError = peg"'Error:' \s* {.*}"
-  pegSuccess = peg"'Hint: operation successful'.*"
-  pegOfInterest = pegLineError / pegOtherError / pegSuccess
-
-proc callCompiler(filename, options: string): TSpec =
-  var c = parseCmdLine(cmdTemplate % ["filename", filename, "options", options])
-  var a: seq[string] = @[] # slicing is not yet implemented :-(
-  for i in 1 .. c.len-1: add(a, c[i])
-  var p = startProcess(command=c[0], args=a,
-                       options={poStdErrToStdOut, poUseShell})
-  var outp = p.outputStream
-  var s = ""
-  while running(p) or not outp.atEnd(outp):
-    var x = outp.readLine()
-    if x =~ pegOfInterest:
-      # `s` should contain the last error message
-      s = x
-  result.outp = ""
-  result.puremsg = ""
-  result.file = ""
-  result.err = true
-  if s =~ pegLineError:
-    result.file = matches[0]
-    result.line = parseInt(matches[1])
-    result.outp = s
-    result.puremsg = matches[2]
-  elif s =~ pegOtherError:
-    result.puremsg = matches[0]
-    result.outp = s
-    result.line = 1
-  elif s =~ pegSuccess:
-    result.outp = s
-    result.err = false
-
-proc sameResults(filename: string, spec, comp: TSpec): bool =
-  # short filename for messages (better readability):
-  var shortfile = os.extractFilename(filename)
-
-  if comp.err and comp.outp == "":
-    # the compiler did not say "[Error]" nor "operation sucessful"
-    Echo("[Tester] $# -- FAILED; COMPILER BROKEN" % shortfile)
-  elif spec.err != comp.err:
-    Echo(("[Tester] $# -- FAILED\n" &
-         "Compiler says: $#\n" &
-         "But specification says: $#") %
-         [shortfile, comp.outp, spec.outp])
-  elif spec.err:
-    if extractFilename(comp.file) != extractFilename(spec.file):
-      Echo(("[Tester] $# -- FAILED: file names do not match:\n" &
-           "Compiler: $#\nSpec: $#") % [shortfile, comp.file, spec.file])
-    elif strip(spec.outp) notin strip(comp.puremsg):
-      Echo(("[Tester] $# -- FAILED: error messages do not match:\n" &
-           "Compiler: $#\nSpec: $#") % [shortfile, comp.pureMsg, spec.outp])
-    elif comp.line != spec.line:
-      Echo(("[Tester] $# -- FAILED: line numbers do not match:\n" &
-           "Compiler: $#\nSpec: $#") % [shortfile, $comp.line, $spec.line])
-    else:
-      Echo("[Tester] $# -- OK" % shortfile)
-      result = true
-  else:
-    # we have to run the executable and check its output:
-    var exeFile = changeFileExt(filename, ExeExt)
-    if ExistsFile(exeFile):
-      if len(spec.outp) == 0:
-        # we have no output to validate against, but compilation succeeded,
-        # so it's okay:
-        Echo("[Tester] $# -- OK" % shortfile)
-        result = true
-      else:
-        var buf = myExec(exeFile)
-        result = strip(buf) == strip(spec.outp)
-        if result:
-          Echo("[Tester] $# -- compiled program OK" % shortfile)
-        else:
-          Echo("[Tester] $# -- compiled program FAILED" % shortfile)
-    else:
-      Echo("[Tester] $# -- FAILED; executable not found" % shortfile)
-
-proc main(options: string) =
-  # runs the complete testsuite
-  var total = 0
-  var passed = 0
-  for filename in os.walkFiles("tests/t*.nim"):
-    if extractFilename(filename) == "tester.nim": continue
-    var spec = parseTest(filename)
-    var comp = callCompiler(filename, options)
-    if sameResults(filename, spec, comp): inc(passed)
-    inc(total)
-  # ensure that the examples at least compiles
-  for filename in os.walkFiles("examples/*.nim"):
-    var comp = callCompiler(filename, options)
-    var shortfile = os.extractFilename(filename)
-    if comp.err:
-      Echo("[Tester] Example '$#' -- FAILED" % shortfile)
-    else:
-      Echo("[Tester] Example $# -- OK" % shortfile)
-      inc(passed)
-    inc(total)
-  Echo("[Tester] $#/$# tests passed\n" % [$passed, $total])
-
-var
-  options = ""
-for i in 1.. paramCount():
-  add(options, " ")
-  add(options, paramStr(i))
-main(options)
diff --git a/tests/tformat.nim b/tests/tformat.nim
deleted file mode 100755
index aba35504b..000000000
--- a/tests/tformat.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Tests the new format proc (including the & and &= operators)

-

-import strutils

-

-echo("Hi $1! How do you feel, $2?\n" % ["Andreas", "Rumpf"])

-#OUT Hi Andreas! How do you feel, Rumpf?

diff --git a/tests/tgtk.nim b/tests/tgtk.nim
deleted file mode 100755
index cd9254e4f..000000000
--- a/tests/tgtk.nim
+++ /dev/null
@@ -1,61 +0,0 @@
-

-import

-  gtk2, glib2, atk, gdk2, gdk2pixbuf, libglade2, pango,

-  pangoutils

-

-proc hello(widget: PGtkWidget, data: pointer) {.cdecl.} =

-  write(stdout, "Hello World\n")

-

-proc delete_event(widget: PGtkWidget, event: PGdkEvent,

-                  data: pointer): bool {.cdecl.} =

-  # If you return FALSE in the "delete_event" signal handler,

-  # GTK will emit the "destroy" signal. Returning TRUE means

-  # you don't want the window to be destroyed.

-  # This is useful for popping up 'are you sure you want to quit?'

-  # type dialogs.

-  write(stdout, "delete event occurred\n")

-  # Change TRUE to FALSE and the main window will be destroyed with

-  # a "delete_event".

-  return false

-

-# Another callback

-proc destroy(widget: PGtkWidget, data: pointer) {.cdecl.} =

-  gtk_main_quit()

-

-proc main() =

-  # GtkWidget is the storage type for widgets

-  var

-    window: PGtkWindow 

-    button: PGtkButton

-

-  gtk_nimrod_init()

-  window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL))

-  discard g_signal_connect(window, "delete_event", 

-                           Gcallback(delete_event), nil)

-  discard g_signal_connect(window, "destroy", Gcallback(destroy), nil)

-  # Sets the border width of the window.

-  gtk_container_set_border_width(window, 10)

-

-  # Creates a new button with the label "Hello World".

-  button = GTK_BUTTON(gtk_button_new_with_label("Hello World"))

-

-  discard g_signal_connect(button, "clicked", Gcallback(hello), nil)

-

-  # This will cause the window to be destroyed by calling

-  # gtk_widget_destroy(window) when "clicked".  Again, the destroy

-  # signal could come from here, or the window manager.

-  discard g_signal_connect_swapped(button, "clicked", 

-    Gcallback(gtk_widget_destroy), window)

-

-  # This packs the button into the window (a gtk container).

-  gtk_container_add(window, button)

-

-  # The final step is to display this newly created widget.

-  gtk_widget_show(button)

-

-  # and the window

-  gtk_widget_show(window)

-

-  gtk_main()

-

-main()

diff --git a/tests/threads/nim.cfg b/tests/threads/nim.cfg
new file mode 100644
index 000000000..b81c89721
--- /dev/null
+++ b/tests/threads/nim.cfg
@@ -0,0 +1 @@
+threads:on
diff --git a/tests/threads/t7172.nim b/tests/threads/t7172.nim
new file mode 100644
index 000000000..87e89417b
--- /dev/null
+++ b/tests/threads/t7172.nim
@@ -0,0 +1,34 @@
+discard """
+  disabled: i386
+  output: '''
+In doStuff()
+In initProcess()
+TEST
+initProcess() done
+Crashes before getting here!
+'''
+  joinable: false
+"""
+
+import std/os
+import std/typedthreads
+
+proc whatever() {.thread, nimcall.} =
+  echo("TEST")
+
+proc initProcess(): void =
+  echo("In initProcess()")
+  var thread: Thread[void]
+  createThread(thread, whatever)
+  joinThread(thread)
+  echo("initProcess() done")
+
+proc doStuff(): void =
+  echo("In doStuff()")
+  # ...
+  initProcess()
+  sleep(500)
+  # ...
+  echo("Crashes before getting here!")
+
+doStuff()
diff --git a/tests/threads/t8535.nim b/tests/threads/t8535.nim
new file mode 100644
index 000000000..a4296df11
--- /dev/null
+++ b/tests/threads/t8535.nim
@@ -0,0 +1,30 @@
+discard """
+  disabled: i386
+  output: '''0
+hello'''
+"""
+
+type
+  CircAlloc*[Size: static[int], T] = tuple
+    baseArray: array[Size,T]
+    index: uint16
+
+type
+  Job = object of RootObj
+
+var foo {.threadvar.}: CircAlloc[1, Job]
+
+when true:
+  echo foo.index
+
+
+# bug #10795
+import asyncdispatch
+import threadpool
+
+proc f1() =
+  waitFor sleepAsync(20)
+  echo "hello"
+
+spawn f1()
+sync()
diff --git a/tests/threads/threadex.nim b/tests/threads/threadex.nim
new file mode 100644
index 000000000..90119aee7
--- /dev/null
+++ b/tests/threads/threadex.nim
@@ -0,0 +1,50 @@
+discard """
+  disabled: i386
+  outputsub: "Just a simple text for test"
+"""
+
+type
+  TMsgKind = enum
+    mLine, mEof
+  TMsg = object
+    case k: TMsgKind
+    of mEof: discard
+    of mLine: data: string
+
+var
+  producer, consumer: Thread[void]
+  chan: Channel[TMsg]
+  printedLines = 0
+  prodId: int
+  consId: int
+
+proc consume() {.thread.} =
+  consId = getThreadId()
+  while true:
+    var x = recv(chan)
+    if x.k == mEof: break
+    echo x.data
+    atomicInc(printedLines)
+
+proc produce() {.thread.} =
+  prodId = getThreadId()
+  var m: TMsg
+  var input = open("tests/dummy.txt")
+  var line = ""
+  while input.readLine(line):
+    m.data = line
+    chan.send(m)
+  close(input)
+  m = TMsg(k: mEof)
+  chan.send(m)
+
+open(chan)
+createThread[void](consumer, consume)
+createThread[void](producer, produce)
+joinThread(consumer)
+joinThread(producer)
+
+close(chan)
+doAssert prodId != consId
+echo printedLines
+
diff --git a/tests/threads/tjsthreads.nim b/tests/threads/tjsthreads.nim
new file mode 100644
index 000000000..5122c9cd6
--- /dev/null
+++ b/tests/threads/tjsthreads.nim
@@ -0,0 +1,6 @@
+discard """
+  targets: "js"
+  matrix: "--threads:on"
+"""
+
+echo 123
diff --git a/tests/threads/tmanyjoin.nim b/tests/threads/tmanyjoin.nim
new file mode 100644
index 000000000..af5bc460e
--- /dev/null
+++ b/tests/threads/tmanyjoin.nim
@@ -0,0 +1,31 @@
+discard """
+  disabled: i386
+  outputsub: "129"
+"""
+
+import os, locks
+
+type
+  MarkerObj = object
+    lock: Lock
+    counter: int
+  Marker = ptr MarkerObj
+
+const
+  ThreadsCount = 129
+  SleepTime = 250
+
+proc worker(p: Marker) {.thread.} =
+  acquire(p.lock)
+  inc(p.counter)
+  release(p.lock)
+  sleep(SleepTime)
+
+var p = cast[Marker](allocShared0(sizeof(MarkerObj)))
+initLock(p.lock)
+var ts = newSeq[Thread[Marker]](ThreadsCount)
+for i in 0..<ts.len:
+  createThread(ts[i], worker, p)
+
+joinThreads(ts)
+echo p.counter
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/threads/tonthreadcreation.nim b/tests/threads/tonthreadcreation.nim
new file mode 100644
index 000000000..61529477d
--- /dev/null
+++ b/tests/threads/tonthreadcreation.nim
@@ -0,0 +1,26 @@
+discard """
+  disabled: i386
+  matrix: "--mm:refc; --mm:orc --deepcopy:on"
+  output: '''some string here
+dying some string here'''
+"""
+
+var
+  someGlobal: string = "some string here"
+  perThread {.threadvar.}: string
+
+proc threadDied() {.gcsafe.} =
+  echo "dying ", perThread
+
+proc foo() {.thread.} =
+  onThreadDestruction threadDied
+  {.gcsafe.}:
+    deepCopy(perThread, someGlobal)
+  echo perThread
+
+proc main =
+  var t: Thread[void]
+  createThread[void](t, foo)
+  t.joinThread()
+
+main()
diff --git a/tests/threads/tracy_allocator.nim b/tests/threads/tracy_allocator.nim
new file mode 100644
index 000000000..f3b39f4dc
--- /dev/null
+++ b/tests/threads/tracy_allocator.nim
@@ -0,0 +1,26 @@
+discard """
+  disabled: i386
+  output: '''true'''
+"""
+
+var somethingElse {.threadvar.}: ref string
+
+type MyThread = Thread[void]
+
+proc asyncThread() {.thread.} =
+  new somethingElse
+
+var threads = newSeq[ptr Thread[void]](8)
+
+for c in 1..1_000:
+  #echo "Test " & $c
+  for i in 0..<threads.len:
+    var t = cast[ptr Thread[void]](alloc0(sizeof(MyThread)))
+    threads[i] = t
+    createThread(t[], asyncThread)
+
+  for t in threads:
+    joinThread(t[])
+    dealloc(t)
+
+echo "true"
diff --git a/tests/threads/treusetvar.nim b/tests/threads/treusetvar.nim
new file mode 100644
index 000000000..f0337801a
--- /dev/null
+++ b/tests/threads/treusetvar.nim
@@ -0,0 +1,29 @@
+discard """
+  disabled: i386
+  outputsub: "65"
+"""
+
+import locks
+
+type
+  MarkerObj = object
+    lock: Lock
+    counter: int
+  Marker = ptr MarkerObj
+
+const
+  ThreadsCount = 65
+
+proc worker(p: Marker) {.thread.} =
+  acquire(p.lock)
+  inc(p.counter)
+  release(p.lock)
+
+var p = cast[Marker](allocShared0(sizeof(MarkerObj)))
+initLock(p.lock)
+
+for i in 0..(ThreadsCount - 1):
+  var thread: Thread[Marker]
+  createThread(thread, worker, p)
+  joinThread(thread)
+echo p.counter
diff --git a/tests/threads/tthreadanalysis.nim b/tests/threads/tthreadanalysis.nim
new file mode 100644
index 000000000..7fc3593c8
--- /dev/null
+++ b/tests/threads/tthreadanalysis.nim
@@ -0,0 +1,52 @@
+discard """
+  errormsg: "'threadFunc' is not GC-safe"
+  line: 38
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+import os
+
+var
+  thr: array[0..5, Thread[tuple[a, b: int]]]
+
+proc doNothing() = discard
+
+type
+  PNode = ref TNode
+  TNode {.pure.} = object
+    le, ri: PNode
+    data: string
+
+var
+  root: PNode
+
+proc buildTree(depth: int): PNode =
+  if depth == 3: return nil
+  new(result)
+  result.le = buildTree(depth-1)
+  result.ri = buildTree(depth-1)
+  result.data = $depth
+
+proc echoLeTree(n: PNode) =
+  var it: PNode
+  it = nil
+  it = n
+  while it != nil:
+    echo it.data
+    it = it.le
+
+proc threadFunc(interval: tuple[a, b: int]) {.thread.} =
+  doNothing()
+  for i in interval.a..interval.b:
+    var r = buildTree(i)
+    echoLeTree(r) # for local data
+  echoLeTree(root) # and the same for foreign data :-)
+
+proc main =
+  root = buildTree(5)
+  for i in 0..high(thr):
+    createThread(thr[i], threadFunc, (i*3, i*3+2))
+  joinThreads(thr)
+
+main()
+
diff --git a/tests/threads/tthreadheapviolation1.nim b/tests/threads/tthreadheapviolation1.nim
new file mode 100644
index 000000000..379bd55e6
--- /dev/null
+++ b/tests/threads/tthreadheapviolation1.nim
@@ -0,0 +1,18 @@
+discard """
+  errormsg: "'horrible' is not GC-safe"
+  line: 11
+  cmd: "nim $target --hints:on --threads:on $options $file"
+"""
+
+var
+  global: string = "test string"
+  t: Thread[void]
+
+proc horrible() {.thread.} =
+  global = "string in thread local heap!"
+  var x = global
+  var mydata = (x, "my string too")
+  echo global
+
+createThread[void](t, horrible)
+joinThread(t)
diff --git a/tests/threads/tthreadvars.nim b/tests/threads/tthreadvars.nim
new file mode 100644
index 000000000..745e3562c
--- /dev/null
+++ b/tests/threads/tthreadvars.nim
@@ -0,0 +1,79 @@
+discard """
+disabled: i386
+output: '''
+10
+1111
+1222
+3030303
+3060606
+6060606
+6121212
+3030903
+3061206
+3031503
+3061806
+5050505
+5101010
+'''
+"""
+
+import typetraits
+
+var tls1 {.threadvar.}: int
+var g0: int
+var g1 {.global.}: int
+
+proc customInc(x: var int, delta: int) =
+  x += delta
+
+customInc(tls1, 10)
+echo tls1
+
+proc nonGenericProc: int =
+  var local: int
+  var nonGenericTls {.threadvar.}: int
+  var nonGenericGlobal {.global.}: int
+  var nonGenericMixedPragmas {.global, threadvar.}: int
+
+  customInc local, 1000
+  customInc nonGenericTls, 1
+  customInc nonGenericGlobal, 10
+  customInc nonGenericMixedPragmas, 100
+
+  return local + nonGenericTls + nonGenericGlobal + nonGenericMixedPragmas
+
+proc genericProc(T: typedesc): int =
+  var local: int
+  var genericTls {.threadvar.}: int
+  var genericGlobal {.global.}: int
+  var genericMixedPragmas {.global, threadvar.}: int
+
+  customInc local, T.name.len * 1000000
+  customInc genericTls, T.name.len * 1
+  customInc genericGlobal, T.name.len * 100
+  customInc genericMixedPragmas, T.name.len * 10000
+
+  return local + genericTls + genericGlobal + genericMixedPragmas
+
+echo nonGenericProc()
+echo nonGenericProc()
+
+echo genericProc(int)
+echo genericProc(int)
+
+echo genericProc(string)
+echo genericProc(string)
+
+proc echoInThread[T]() {.thread.} =
+  echo genericProc(T)
+  echo genericProc(T)
+
+proc newEchoThread(T: typedesc) =
+  var t: Thread[void]
+  createThread(t, echoInThread[T])
+  joinThreads(t)
+
+newEchoThread int
+newEchoThread int
+newEchoThread float
+
diff --git a/tests/threads/ttryrecv.nim b/tests/threads/ttryrecv.nim
new file mode 100644
index 000000000..fcff94e78
--- /dev/null
+++ b/tests/threads/ttryrecv.nim
@@ -0,0 +1,36 @@
+discard """
+  matrix: "--mm:refc"
+  outputsub: "channel is empty"
+"""
+
+# bug #1816
+
+from random import rand
+from os import sleep
+
+type PComm = ptr Channel[int]
+
+proc doAction(outC: PComm) {.thread.} =
+  for i in 0 ..< 5:
+    sleep(rand(50))
+    send(outC[], i)
+
+var
+  thr: Thread[PComm]
+  chan: Channel[int]
+
+open(chan)
+createThread[PComm](thr, doAction, addr(chan))
+
+while true:
+  let (flag, x) = tryRecv(chan)
+  if flag:
+    echo("received from chan: " & $x)
+  else:
+    echo "channel is empty"
+    break
+
+echo "Finished listening"
+
+joinThread(thr)
+close(chan)
diff --git a/tests/tinit.nim b/tests/tinit.nim
deleted file mode 100755
index 85475ce94..000000000
--- a/tests/tinit.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test the new init section in modules

-

-import minit

-

-write(stdout, "Hallo from main module!\n")

-#OUT Hallo from module! Hallo from main module!

diff --git a/tests/tints.nim b/tests/tints.nim
deleted file mode 100755
index f2b52c134..000000000
--- a/tests/tints.nim
+++ /dev/null
@@ -1,41 +0,0 @@
-# Test the different integer operations
-
-var testNumber = 0
-
-template test(opr, a, b, c: expr): stmt = 
-  # test the expression at compile and runtime
-  block:
-    const constExpr = opr(a, b)
-    when constExpr != c:
-      {.error: "Test failed " & $constExpr & " " & $c.}
-    inc(testNumber)
-    #Echo("Test: " & $testNumber)
-    var aa = a
-    var bb = b
-    var varExpr = opr(aa, bb)
-    assert(varExpr == c)
-
-test(`+`, 12'i8, -13'i16, -1'i16)
-test(`shl`, 0b11, 0b100, 0b110000)
-test(`shl`, 0b11'i32, 0b100'i64, 0b110000'i64)
-test(`shl`, 0b11'i32, 0b100'i32, 0b110000'i32)
-
-test(`or`, 0xf0f0'i16, 0x0d0d'i16, 0xfdfd'i16)
-test(`and`, 0xf0f0'i16, 0xfdfd'i16, 0xf0f0'i16)
-
-test(`shr`, 0xffffffffffffffff'i64, 0x4'i64, 0x0fffffffffffffff'i64)
-test(`shr`, 0xffff'i16, 0x4'i16, 0x0fff'i16)
-test(`shr`, 0xff'i8, 0x4'i8, 0x0f'i8)
-
-test(`shr`, 0xffffffff'i64, 0x4'i64, 0x0fffffff'i64)
-test(`shr`, 0xffffffff'i32, 0x4'i32, 0x0fffffff'i32)
-
-test(`shl`, 0xffffffffffffffff'i64, 0x4'i64, 0xfffffffffffffff0'i64)
-test(`shl`, 0xffff'i16, 0x4'i16, 0xfff0'i16)
-test(`shl`, 0xff'i8, 0x4'i8, 0xf0'i8)
-
-test(`shl`, 0xffffffff'i64, 0x4'i64, 0xffffffff0'i64)
-test(`shl`, 0xffffffff'i32, 0x4'i32, 0xfffffff0'i32)
-
-Echo("Success") #OUT Success
-
diff --git a/tests/tio.nim b/tests/tio.nim
deleted file mode 100755
index 014c32d9f..000000000
--- a/tests/tio.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-# test the file-IO

-

-proc main() =

-  for line in lines("thallo.nim"):

-    writeln(stdout, line)

-

-main()

diff --git a/tests/tisopr.nim b/tests/tisopr.nim
deleted file mode 100755
index d52859b09..000000000
--- a/tests/tisopr.nim
+++ /dev/null
@@ -1,20 +0,0 @@
-# Test is operator
-
-type
-  TMyType = object
-    len: int
-    data: string
-    
-  TOtherType = object of TMyType
-   
-proc p(x: TMyType): bool = 
-  return x is TOtherType
-    
-var
-  m: TMyType
-  n: TOtherType
-
-write(stdout, p(m))
-write(stdout, p(n))
-
-#OUT falsetrue
diff --git a/tests/titer.nim b/tests/titer.nim
deleted file mode 100755
index 19a11dc4e..000000000
--- a/tests/titer.nim
+++ /dev/null
@@ -1,44 +0,0 @@
-# Test the new iterators

-

-iterator xrange(fromm, to: int, step = 1): int =

-  var a = fromm

-  while a <= to:

-    yield a

-    inc(a, step)

-

-iterator interval[T](a, b: T): T =

-  var x = a

-  while x <= b:

-    yield x

-    inc(x)

-

-#

-#iterator lines(filename: string): (line: string) =

-#  var

-#    f: tTextfile

-#    shouldClose = open(f, filename)

-#  if shouldClose:

-#    setSpace(line, 256)

-#    while readTextLine(f, line):

-#      yield line

-#  finally:

-#    if shouldClose: close(f)

-#

-

-for i in xrange(0, 5):

-  for k in xrange(1, 7):

-    write(stdout, "test")

-

-for j in interval(45, 45):

-  write(stdout, "test2!")

-  write(stdout, "test3?")

-

-for x in items(["hi", "what's", "your", "name"]):

-  echo(x)

-  

-const

-  stringArray = ["hi", "what's", "your", "name"]

-

-for i in 0..len(stringArray)-1:

-  echo(stringArray[i])

-

diff --git a/tests/titer3.nim b/tests/titer3.nim
deleted file mode 100755
index d0e121445..000000000
--- a/tests/titer3.nim
+++ /dev/null
@@ -1,17 +0,0 @@
-
-iterator count1_3: int =
-  yield 1
-  yield 2
-  yield 3
-
-for x in count1_3():
-  write(stdout, $x)
-
-# yield inside an iterator, but not in a loop:
-iterator iter1(a: openArray[int]): int =
-  yield a[0]
-
-var x = [[1, 2, 3], [4, 5, 6]]
-for y in iter1(x[0]): write(stdout, $y)
-
-#OUT 1231
\ No newline at end of file
diff --git a/tests/tlastmod.nim b/tests/tlastmod.nim
deleted file mode 100755
index 75b047fc8..000000000
--- a/tests/tlastmod.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# test the new LastModificationTime() proc

-

-import

-  os, times, strutils

-

-proc main() =

-  var

-    a, b: TTime

-  a = getLastModificationTime(ParamStr(1))

-  b = getLastModificationTime(ParamStr(2))

-  writeln(stdout, $a)

-  writeln(stdout, $b)

-  if a < b:

-    Write(stdout, "$2 is newer than $1\n" % [ParamStr(1), ParamStr(2)])

-  else:

-    Write(stdout, "$1 is newer than $2\n" % [ParamStr(1), ParamStr(2)])

-

-main()

diff --git a/tests/tlibs.nim b/tests/tlibs.nim
deleted file mode 100755
index e3b6bd4c3..000000000
--- a/tests/tlibs.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-# Test wether the bindings at least compile...
-
-import
-  unicode, cgi, terminal, libcurl, web, 
-  parsexml, parseopt, parsecfg,
-  osproc,
-  sdl, smpeg, sdl_gfx, sdl_net, sdl_mixer, sdl_ttf,
-  sdl_image, sdl_mixer_nosmpeg,
-  cursorfont, xatom, xf86vmode, xkb, xrandr, xshm, xvlib, keysym, xcms, xi,
-  xkblib, xrender, xutil, x, xf86dga, xinerama, xlib, xresource, xv,
-  gtk2, glib2, pango, gdk2,
-  cairowin32, cairoxlib,
-  odbcsql,
-  gl, glut, glu, glx, glext, wingl,
-  lua, lualib, lauxlib, mysql, sqlite3, python, tcl
-  
-when defined(linux):
-  import
-    zlib, zipfiles
-
-writeln(stdout, "test compilation of binding modules")
diff --git a/tests/tlowhigh.nim b/tests/tlowhigh.nim
deleted file mode 100755
index 79f5c5b95..000000000
--- a/tests/tlowhigh.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# Test the magic low() and high() procs

-

-type

-  myEnum = enum e1, e2, e3, e4, e5

-

-var

-  a: array [myEnum, int]

-

-for i in low(a) .. high(a):

-  a[i] = 0

-

-proc sum(a: openarray[int]): int =

-  result = 0

-  for i in low(a)..high(a):

-    inc(result, a[i])

-

-write(stdout, sum([1, 2, 3, 4]))

-#OUT 10

diff --git a/tests/tmath.nim b/tests/tmath.nim
deleted file mode 100755
index 6a1dae54d..000000000
--- a/tests/tmath.nim
+++ /dev/null
@@ -1,85 +0,0 @@
-# tests for the interpreter

-

-proc loops(a: var int) =

-  nil

-  #var

-  #  b: int

-  #b = glob

-  #while b != 0:

-  #  b = b + 1

-  #a = b

-

-proc mymax(a, b: int): int =

-  #loops(result)

-  result = a

-  if b > a: result = b

-

-proc test(a, b: int) =

-  var

-    x, y: int

-  x = 0

-  y = 7

-  if x == a + b * 3 - 7 or

-      x == 8 or

-      x == y and y > -56 and y < 699:

-    y = 0

-  elif y == 78 and x == 0:

-    y = 1

-  elif y == 0 and x == 0:

-    y = 2

-  else:

-    y = 3

-

-type

-  TTokType = enum

-    tkNil, tkType, tkConst, tkVar, tkSymbol, tkIf,

-    tkWhile, tkFor, tkLoop, tkCase, tkLabel, tkGoto

-

-proc testCase(t: TTokType): int =

-  case t

-  of tkNil, tkType, tkConst: result = 0

-  of tkVar: result = 1

-  of tkSymbol: result = 2

-  of tkIf..tkFor: result = 3

-  of tkLoop: result = 56

-  else: result = -1

-  test(0, 9) # test the call

-

-proc TestLoops() =

-  var

-    i, j: int

-

-  while i >= 0:

-    if i mod 3 == 0:

-      break

-    i = i + 1

-    while j == 13:

-      j = 13

-      break

-    break

-

-  while True:

-    break

-

-

-var

-  glob: int

-  a: array [0..5, int]

-

-proc main() =

-  #glob = 0

-  #loops( glob )

-  var

-    res: int

-    s: string

-  #write(stdout, mymax(23, 45))

-  write(stdout, "Hallo! Wie heißt du? ")

-  s = readLine(stdin)

-  # test the case statement

-  case s

-  of "Andreas": write(stdout, "Du bist mein Meister!\n")

-  of "Rumpf": write(stdout, "Du bist in der Familie meines Meisters!\n")

-  else: write(stdout, "ich kenne dich nicht!\n")

-  write(stdout, "Du heisst " & s & "\n")

-

-main()

diff --git a/tests/tnamspc.nim b/tests/tnamspc.nim
deleted file mode 100755
index eddaacfd8..000000000
--- a/tests/tnamspc.nim
+++ /dev/null
@@ -1,5 +0,0 @@
-# Test17 - test correct handling of namespaces

-

-import mnamspc1

-

-global = 9 #ERROR

diff --git a/tests/tnestif.nim b/tests/tnestif.nim
deleted file mode 100755
index 558fe8d07..000000000
--- a/tests/tnestif.nim
+++ /dev/null
@@ -1,18 +0,0 @@
-# test nested ifs

-

-var

-    x, y: int

-x = 2

-if x == 0:

-    write(stdout, "i == 0")

-    if y == 0:

-        write(stdout, x)

-    else:

-        write(stdout, y)

-elif x == 1:

-    write(stdout, "i == 1")

-elif x == 2:

-    write(stdout, "i == 2")

-else:

-    write(stdout, "looks like Python")

-#OUT i == 2

diff --git a/tests/tnewuns.nim b/tests/tnewuns.nim
deleted file mode 100755
index 5181e467c..000000000
--- a/tests/tnewuns.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-# test the new unsigned operations:

-

-import

-  strutils

-

-var

-  x, y: int

-

-x = 1

-y = high(int)

-

-writeln(stdout, $ ( x +% y ) )

diff --git a/tests/tnoop.nim b/tests/tnoop.nim
deleted file mode 100755
index d097553e8..000000000
--- a/tests/tnoop.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Tests the new check in the semantic pass

-

-var

-  a: int

-

-a()  #ERROR_MSG expression 'a()' cannot be called

diff --git a/tests/tobject2.nim b/tests/tobject2.nim
deleted file mode 100755
index 8f69a6bac..000000000
--- a/tests/tobject2.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-# Tests the object implementation
-
-type
-  TPoint2d = object
-    x, y: int
-
-  TPoint3d = object of TPoint2d
-    z: int # added a field
-
-proc getPoint( p: var TPoint2d) =
-  {.breakpoint.}
-  writeln(stdout, p.x)
-
-var
-  p: TPoint3d
-
-TPoint2d(p).x = 34
-p.y = 98
-p.z = 343
-
-getPoint(p)
diff --git a/tests/tobjects.nim b/tests/tobjects.nim
deleted file mode 100755
index 8305e2838..000000000
--- a/tests/tobjects.nim
+++ /dev/null
@@ -1,42 +0,0 @@
-type

-  TBase = object

-    x, y: int

-

-  TSubclassKind = enum ka, kb, kc, kd, ke, kf

-  TSubclass = object of TBase

-    case c: TSubclassKind

-    of ka, kb, kc, kd:

-      a, b: int

-    of ke:

-      d, e, f: char

-    else: nil

-    n: bool

-

-var

-  global: int

-

-var

-  s: string

-  r: float = 0.0

-  i: int = 500 + 400

-

-case i

-of 500..999: write(stdout, "ha!\n")

-of 1000..3000, 12: write(stdout, "ganz schön groß\n")

-of 1, 2, 3: write(stdout, "1 2 oder 3\n")

-else: write(stdout, "sollte nicht passieren\n")

-

-case readLine(stdin)

-of "Rumpf": write(stdout, "Hallo Meister!\n")

-of "Andreas": write(stdout, "Hallo Meister!\n")

-else: write(stdout, "Nicht mein Meister!\n")

-

-global = global + 1

-write(stdout, "Hallo wie heißt du? \n")

-s = readLine(stdin)

-i = 0

-while i < len(s):

-  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")

-  i = i + 1

-

-write(stdout, "Du heißt " & s)

diff --git a/tests/tools/compile/config.nims b/tests/tools/compile/config.nims
new file mode 100644
index 000000000..a19545668
--- /dev/null
+++ b/tests/tools/compile/config.nims
@@ -0,0 +1 @@
+switch("path", "$lib/../")
\ No newline at end of file
diff --git a/tests/tools/compile/readme.md b/tests/tools/compile/readme.md
new file mode 100644
index 000000000..cb5058e02
--- /dev/null
+++ b/tests/tools/compile/readme.md
@@ -0,0 +1 @@
+Test whether the tools compile.
\ No newline at end of file
diff --git a/tests/tools/compile/tdeps.nim b/tests/tools/compile/tdeps.nim
new file mode 100644
index 000000000..971ca1b8e
--- /dev/null
+++ b/tests/tools/compile/tdeps.nim
@@ -0,0 +1,5 @@
+discard """
+  action: compile
+"""
+
+include tools/deps
diff --git a/tests/tools/compile/tdetect.nim b/tests/tools/compile/tdetect.nim
new file mode 100644
index 000000000..253fc0d39
--- /dev/null
+++ b/tests/tools/compile/tdetect.nim
@@ -0,0 +1,5 @@
+discard """
+  action: compile
+"""
+
+include tools/detect/detect
diff --git a/tests/tools/compile/tkoch.nim b/tests/tools/compile/tkoch.nim
new file mode 100644
index 000000000..008721dc0
--- /dev/null
+++ b/tests/tools/compile/tkoch.nim
@@ -0,0 +1,5 @@
+discard """
+  action: compile
+"""
+
+include koch
\ No newline at end of file
diff --git a/tests/tools/compile/tniminst.nim b/tests/tools/compile/tniminst.nim
new file mode 100644
index 000000000..78c736af0
--- /dev/null
+++ b/tests/tools/compile/tniminst.nim
@@ -0,0 +1,5 @@
+discard """
+  action: compile
+"""
+
+include tools/niminst/niminst
\ No newline at end of file
diff --git a/tests/tools/config.nims b/tests/tools/config.nims
new file mode 100644
index 000000000..0f0cba8b4
--- /dev/null
+++ b/tests/tools/config.nims
@@ -0,0 +1,3 @@
+--d:nimPreviewSlimSystem
+--d:nimPreviewCstringConversion
+--d:nimPreviewProcConversion
diff --git a/tests/tools/dontmentionme.nim b/tests/tools/dontmentionme.nim
new file mode 100644
index 000000000..218823aca
--- /dev/null
+++ b/tests/tools/dontmentionme.nim
@@ -0,0 +1,3 @@
+{.used.}
+
+proc nothing* = echo "nothing to see here"
diff --git a/tests/tools/second.nim b/tests/tools/second.nim
new file mode 100644
index 000000000..ee94af25f
--- /dev/null
+++ b/tests/tools/second.nim
@@ -0,0 +1,3 @@
+import tables
+
+let dataEx* = {1: 2, 3: 4}.toTable
diff --git a/tests/tools/tlinter.nim b/tests/tools/tlinter.nim
new file mode 100644
index 000000000..16f67905e
--- /dev/null
+++ b/tests/tools/tlinter.nim
@@ -0,0 +1,40 @@
+discard """
+  cmd: '''nim c --styleCheck:hint $file'''
+  nimout: '''
+tlinter.nim(25, 1) Hint: 'tyPE' should be: 'type' [Name]
+tlinter.nim(21, 14) Hint: 'nosideeffect' should be: 'noSideEffect' [Name]
+tlinter.nim(21, 28) Hint: 'myown' should be: 'myOwn' [template declared in tlinter.nim(19, 9)] [Name]
+tlinter.nim(21, 35) Hint: 'inLine' should be: 'inline' [Name]
+tlinter.nim(23, 1) Hint: 'foO' should be: 'foo' [proc declared in tlinter.nim(21, 6)] [Name]
+tlinter.nim(27, 14) Hint: 'Foo_bar' should be: 'FooBar' [type declared in tlinter.nim(25, 6)] [Name]
+tlinter.nim(29, 6) Hint: 'someVAR' should be: 'someVar' [var declared in tlinter.nim(27, 5)] [Name]
+tlinter.nim(32, 7) Hint: 'i_fool' should be: 'iFool' [Name]
+tlinter.nim(39, 5) Hint: 'meh_field' should be: 'mehField' [Name]
+'''
+  action: "compile"
+"""
+
+
+
+{.pragma: myOwn.}
+
+proc foo() {.nosideeffect, myown, inLine.} = debugEcho "hi"
+
+foO()
+
+tyPE FooBar = string
+
+var someVar: Foo_bar = "a"
+
+echo someVAR
+
+proc main =
+  var i_fool = 34
+  echo i_fool
+
+main()
+
+type
+  Foo = object
+    meh_field: int
+
diff --git a/tests/tools/tnimgrep.nim b/tests/tools/tnimgrep.nim
new file mode 100644
index 000000000..890a36e79
--- /dev/null
+++ b/tests/tools/tnimgrep.nim
@@ -0,0 +1,404 @@
+discard """
+  output: '''
+
+[Suite] nimgrep filesystem
+
+[Suite] nimgrep contents filtering
+'''
+"""
+## Authors: quantimnot, a-mr
+
+import std/[osproc, os, streams, unittest, strutils]
+
+import std/syncio
+
+#=======
+# setup
+#=======
+
+var process: Process
+var ngStdOut, ngStdErr: string
+var ngExitCode: int
+let previousDir = getCurrentDir()
+let tempDir = getTempDir()
+let testFilesRoot = tempDir / "nimgrep_test_files"
+
+template nimgrep(optsAndArgs): untyped =
+  process = startProcess(previousDir / "bin/nimgrep " & optsAndArgs,
+                         options = {poEvalCommand})
+  ngExitCode = process.waitForExit
+  ngStdOut = process.outputStream.readAll
+  ngStdErr = process.errorStream.readAll
+
+func fixSlash(s: string): string =
+  if DirSep == '/':
+    result = s
+  else:  # on Windows
+    result = s.replace('/', DirSep)
+
+func initString(len = 1000, val = ' '): string =
+  result = newString(len)
+  for i in 0..<len:
+    result[i] = val
+
+# Create test file hierarchy.
+createDir testFilesRoot
+setCurrentDir testFilesRoot
+createDir "a" / "b"
+createDir "c" / "b"
+createDir ".hidden"
+writeFile("do_not_create_another_file_with_this_pattern_KJKJHSFSFKASHFBKAF", "PATTERN")
+writeFile("a" / "b" / "only_the_pattern", "PATTERN")
+writeFile("c" / "b" / "only_the_pattern", "PATTERN")
+writeFile(".hidden" / "only_the_pattern", "PATTERN")
+writeFile("null_in_first_1k", "\0PATTERN")
+writeFile("null_after_first_1k", initString(1000) & "\0")
+writeFile("empty", "")
+writeFile("context_match_filtering", """
+-
+CONTEXTPAT
+-
+PATTERN
+-
+-
+-
+
+-
+-
+-
+PATTERN
+-
+-
+-
+""")
+writeFile("only_the_pattern.txt", "PATTERN")
+writeFile("only_the_pattern.ascii", "PATTERN")
+
+
+#=======
+# tests
+#=======
+
+suite "nimgrep filesystem":
+
+  test "`--filename` with matching file":
+    nimgrep "-r --filename:KJKJHSFSFKASHFBKAF PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == fixSlash dedent"""
+        ./do_not_create_another_file_with_this_pattern_KJKJHSFSFKASHFBKAF:1: PATTERN
+        1 matches
+        """
+
+
+  test "`--dirname` with matching dir":
+    nimgrep "-r --dirname:.hid PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == fixSlash dedent"""
+        .hidden/only_the_pattern:1: PATTERN
+        1 matches
+        """
+
+  let only_the_pattern = fixSlash dedent"""
+        a/b/only_the_pattern:1: PATTERN
+        c/b/only_the_pattern:1: PATTERN
+        2 matches
+        """
+
+  let only_a = fixSlash dedent"""
+        a/b/only_the_pattern:1: PATTERN
+        1 matches
+        """
+
+  test "`--dirname` with matching grandparent path segment":
+    nimgrep "-r --dirname:a PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == only_a
+
+  test "`--dirpath` with matching grandparent path segment":
+    nimgrep "-r --dirp:a PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == only_a
+
+  test "`--dirpath` with matching grandparent path segment":
+    nimgrep "-r --dirpath:a/b PATTERN".fixSlash
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == only_a
+
+
+  test "`--dirname` with matching parent path segment":
+    nimgrep "-r --dirname:b PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == only_the_pattern
+
+  test "`--dirpath` with matching parent path segment":
+    nimgrep "-r --dirpath:b PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == only_the_pattern
+
+
+  let patterns_without_directory_a_b = fixSlash dedent"""
+        ./context_match_filtering:4: PATTERN
+        ./context_match_filtering:12: PATTERN
+        ./do_not_create_another_file_with_this_pattern_KJKJHSFSFKASHFBKAF:1: PATTERN
+        ./null_in_first_1k:1: """ & "\0PATTERN\n" & dedent"""
+        ./only_the_pattern.ascii:1: PATTERN
+        ./only_the_pattern.txt:1: PATTERN
+        .hidden/only_the_pattern:1: PATTERN
+        c/b/only_the_pattern:1: PATTERN
+        8 matches
+        """
+
+  let patterns_without_directory_b = fixSlash dedent"""
+        ./context_match_filtering:4: PATTERN
+        ./context_match_filtering:12: PATTERN
+        ./do_not_create_another_file_with_this_pattern_KJKJHSFSFKASHFBKAF:1: PATTERN
+        ./null_in_first_1k:1: """ & "\0PATTERN\n" & dedent"""
+        ./only_the_pattern.ascii:1: PATTERN
+        ./only_the_pattern.txt:1: PATTERN
+        .hidden/only_the_pattern:1: PATTERN
+        7 matches
+        """
+
+  test "`--ndirname` not matching grandparent path segment":
+    nimgrep "-r --ndirname:a PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == patterns_without_directory_a_b
+
+  test "`--ndirname` not matching parent path segment":
+    nimgrep "-r --ndirname:b PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == patterns_without_directory_b
+
+  test "`--notdirpath` not matching grandparent path segment":
+    nimgrep "-r --notdirpath:a PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == patterns_without_directory_a_b
+
+  test "`--notdirpath` not matching parent path segment":
+    nimgrep "-r --ndirp:b PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == patterns_without_directory_b
+
+  test "`--notdirpath` with matching grandparent/parent path segment":
+    nimgrep "-r --ndirp:a/b PATTERN".fixSlash
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == patterns_without_directory_a_b
+
+
+  test "`--text`, `-t`, `--bin:off` with file containing a null in first 1k chars":
+    nimgrep "-r --text PATTERN null_in_first_1k"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == "0 matches\n"
+    checkpoint "`--text`"
+    nimgrep "-r -t PATTERN null_in_first_1k"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == "0 matches\n"
+    checkpoint "`-t`"
+    nimgrep "-r --bin:off PATTERN null_in_first_1k"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == "0 matches\n"
+    checkpoint "`--binary:off`"
+
+
+  test "`--bin:only` with file containing a null in first 1k chars":
+    nimgrep "--bin:only -@ PATTERN null_in_first_1k null_after_first_1k only_the_pattern.txt"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == dedent"""
+        null_in_first_1k:1: ^@PATTERN
+        1 matches
+        """
+
+
+  test "`--bin:only` with file containing a null after first 1k chars":
+    nimgrep "--bin:only PATTERN null_after_first_1k only_the_pattern.txt"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == "0 matches\n"
+
+
+  # TODO: we need to throw a warning if e.g. both extension was provided and
+  # inappropriate filename was directly provided via command line
+  #
+  #  test "`--ext:doesnotexist` without a matching file":
+  #    # skip() # FIXME: this test fails
+  #    nimgrep "--ext:doesnotexist PATTERN context_match_filtering only_the_pattern.txt"
+  #    check ngExitCode == 0
+  #    check ngStdErr.len == 0
+  #    check ngStdOut == """
+  #0 matches
+  #"""
+  #
+  #
+  #  test "`--ext:txt` with a matching file":
+  #    nimgrep "--ext:txt PATTERN context_match_filtering only_the_pattern.txt"
+  #    check ngExitCode == 0
+  #    check ngStdErr.len == 0
+  #    check ngStdOut == """
+  #only_the_pattern.txt:1: PATTERN
+  #1 matches
+  #"""
+  #
+  #
+  #  test "`--ext:txt|doesnotexist` with some matching files":
+  #    nimgrep "--ext:txt|doesnotexist PATTERN context_match_filtering only_the_pattern.txt only_the_pattern.ascii"
+  #    check ngExitCode == 0
+  #    check ngStdErr.len == 0
+  #    check ngStdOut == """
+  #only_the_pattern.txt:1: PATTERN
+  #1 matches
+  #"""
+  #
+  #
+  #  test "`--ext` with some matching files":
+  #    nimgrep "--ext PATTERN context_match_filtering only_the_pattern.txt only_the_pattern.ascii"
+  #    check ngExitCode == 0
+  #    check ngStdErr.len == 0
+  #    check ngStdOut == """
+  #context_match_filtering:4: PATTERN
+  #context_match_filtering:12: PATTERN
+  #2 matches
+  #"""
+  #
+  #
+  #  test "`--ext:txt --ext` with some matching files":
+  #    nimgrep "--ext:txt --ext PATTERN context_match_filtering only_the_pattern.txt only_the_pattern.ascii"
+  #    check ngExitCode == 0
+  #    check ngStdErr.len == 0
+  #    check ngStdOut == """
+  #context_match_filtering:4: PATTERN
+  #context_match_filtering:12: PATTERN
+  #only_the_pattern.txt:1: PATTERN
+  #3 matches
+  #"""
+
+
+suite "nimgrep contents filtering":
+
+  test "`--inFile` with matching file":
+    nimgrep "-r --inf:CONTEXTPAT PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == fixSlash dedent"""
+        ./context_match_filtering:4: PATTERN
+        ./context_match_filtering:12: PATTERN
+        2 matches
+        """
+
+
+  test "`--notinFile` with matching files":
+    nimgrep "-r --ninf:CONTEXTPAT PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == fixSlash dedent"""
+        ./do_not_create_another_file_with_this_pattern_KJKJHSFSFKASHFBKAF:1: PATTERN
+        ./null_in_first_1k:1: """ & "\0PATTERN\n" & dedent"""
+        ./only_the_pattern.ascii:1: PATTERN
+        ./only_the_pattern.txt:1: PATTERN
+        .hidden/only_the_pattern:1: PATTERN
+        a/b/only_the_pattern:1: PATTERN
+        c/b/only_the_pattern:1: PATTERN
+        7 matches
+        """
+
+
+  test "`--inContext` with missing context option":
+    # Using `--inContext` implies default -c:1 is used
+    nimgrep "-r --inContext:CONTEXTPAT PATTERN"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == "0 matches\n"
+
+
+  test "`--inContext` with PAT matching PATTERN":
+    # This tests the scenario where PAT always matches PATTERN and thus
+    # has the same effect as excluding the `inContext` option.
+    # I'm not sure of the desired behaviour here.
+    nimgrep "--context:2 --inc:PAT PATTERN context_match_filtering"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == dedent"""
+        context_match_filtering:2  CONTEXTPAT
+        context_match_filtering:3  -
+        context_match_filtering:4: PATTERN
+        context_match_filtering:5  -
+        context_match_filtering:6  -
+
+        context_match_filtering:10  -
+        context_match_filtering:11  -
+        context_match_filtering:12: PATTERN
+        context_match_filtering:13  -
+        context_match_filtering:14  -
+
+        2 matches
+        """
+
+
+  test "`--inContext` with PAT in context":
+    nimgrep "--context:2 --inContext:CONTEXTPAT PATTERN context_match_filtering"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == dedent"""
+        context_match_filtering:2  CONTEXTPAT
+        context_match_filtering:3  -
+        context_match_filtering:4: PATTERN
+        context_match_filtering:5  -
+        context_match_filtering:6  -
+
+        1 matches
+        """
+
+
+  test "`--notinContext` with PAT matching some contexts":
+    nimgrep "--context:2 --ninContext:CONTEXTPAT PATTERN context_match_filtering"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == dedent"""
+        context_match_filtering:10  -
+        context_match_filtering:11  -
+        context_match_filtering:12: PATTERN
+        context_match_filtering:13  -
+        context_match_filtering:14  -
+
+        1 matches
+        """
+
+
+  test "`--notinContext` with PAT not matching any of the contexts":
+    nimgrep "--context:1 --ninc:CONTEXTPAT PATTERN context_match_filtering"
+    check ngExitCode == 0
+    check ngStdErr.len == 0
+    check ngStdOut == dedent"""
+        context_match_filtering:3  -
+        context_match_filtering:4: PATTERN
+        context_match_filtering:5  -
+
+        context_match_filtering:11  -
+        context_match_filtering:12: PATTERN
+        context_match_filtering:13  -
+
+        2 matches
+        """
+
+
+#=========
+# cleanup
+#=========
+
+setCurrentDir previousDir
+removeDir testFilesRoot
diff --git a/tests/tools/tnimscriptwithmacro.nims b/tests/tools/tnimscriptwithmacro.nims
new file mode 100644
index 000000000..8b97f0769
--- /dev/null
+++ b/tests/tools/tnimscriptwithmacro.nims
@@ -0,0 +1,22 @@
+discard """
+cmd: "nim e $file"
+output: '''
+foobar
+nothing
+hallo
+"""
+
+# this test ensures that the mode is resetted correctly to repr
+
+import macros
+
+macro foobar(): void =
+  result = newCall(bindSym"echo", newLit("nothing"))
+
+echo "foobar"
+
+let x = 123
+
+foobar()
+
+exec "echo hallo"
diff --git a/tests/tools/tunused_imports.nim b/tests/tools/tunused_imports.nim
new file mode 100644
index 000000000..539608ad6
--- /dev/null
+++ b/tests/tools/tunused_imports.nim
@@ -0,0 +1,41 @@
+discard """
+  cmd: '''nim c --hint:Processing:off $file'''
+  nimout: '''
+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"
+"""
+
+{.warning: "BEGIN".}
+
+# bug #12885
+
+import tables, second
+
+template test(key: int): untyped =
+  `[]`(dataEx, key)
+
+echo test(1)
+
+import net, dontmentionme
+
+echo AF_UNIX
+
+import macros
+# bug #11809
+macro bar(): untyped =
+  template baz() = discard
+  result = getAst(baz())
+
+bar()
+
+import strutils
+import std/[strtabs, cstrutils]
+import std/macrocache
+
+{.warning: "END".}
diff --git a/tests/topena1.nim b/tests/topena1.nim
deleted file mode 100755
index 7351edf55..000000000
--- a/tests/topena1.nim
+++ /dev/null
@@ -1,5 +0,0 @@
-# Tests a special bug
-
-var
-  x: ref openarray[string] #ERROR_MSG invalid type
-
diff --git a/tests/toptions.nim b/tests/toptions.nim
deleted file mode 100755
index 95bb5cfbc..000000000
--- a/tests/toptions.nim
+++ /dev/null
@@ -1,22 +0,0 @@
-# Converted by Pas2mor v1.54

-# Used command line arguments:

-# -m -q -o bootstrap\options.mor options.pas

-#

-

-type

-  # please make sure we have under 32 options (improves code efficiency!)

-  TOption = enum

-    optNone, optForceFullMake, optBoehmGC, optRefcGC, optRangeCheck,

-    optBoundsCheck, optOverflowCheck, optNilCheck, optAssert, optLineDir,

-    optWarns, optHints, optDeadCodeElim, optListCmd, optCompileOnly,

-    optSafeCode,             # only allow safe code

-    optStyleCheck, optOptimizeSpeed, optOptimizeSize, optGenDynLib,

-    optGenGuiApp, optStackTrace

-

-  TOptionset = set[TOption]

-

-var

-  gOptions: TOptionset = {optRefcGC, optRangeCheck, optBoundsCheck,

-    optOverflowCheck, optAssert, optWarns, optHints, optLineDir, optStackTrace}

-  compilerArgs: int

-  gExitcode: int8

diff --git a/tests/tos.nim b/tests/tos.nim
deleted file mode 100755
index 9ab4295f8..000000000
--- a/tests/tos.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-# test some things of the os module
-
-import os
-
-proc walkDirTree(root: string) = 
-  for k, f in walkDir(root):
-    case k 
-    of pcFile, pcLinkToFile: echo(f)
-    of pcDirectory: walkDirTree(f)
-    of pcLinkToDirectory: nil
-
-walkDirTree(".")
diff --git a/tests/toverflw.nim b/tests/toverflw.nim
deleted file mode 100755
index c8f194e68..000000000
--- a/tests/toverflw.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-# Tests emc's ability to detect overflows

-

-{.push overflowChecks: on.}

-

-var

-  a, b: int

-a = high(int)

-b = -2

-try:

-  writeln(stdout, b - a)

-except EOverflow:

-  writeln(stdout, "the computation overflowed")

-

-{.pop.} # overflow check

-#OUT the computation overflowed

diff --git a/tests/toverlop.nim b/tests/toverlop.nim
deleted file mode 100755
index f11275644..000000000
--- a/tests/toverlop.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-# Test operator overloading

-

-proc `%` (a, b: int): int =

-  return a mod b

-

-var x, y: int

-x = 15

-y = 6

-write(stdout, x % y)

-#OUT 3

diff --git a/tests/toverwr.nim b/tests/toverwr.nim
deleted file mode 100755
index f2b42df15..000000000
--- a/tests/toverwr.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-# Test the overloading resolution in connection with a qualifier

-

-proc write(t: TFile, s: string) =

-  nil # a nop

-

-system.write(stdout, "hallo")

-#OUT hallo

diff --git a/tests/tparscfg.nim b/tests/tparscfg.nim
deleted file mode 100755
index 618ecadd6..000000000
--- a/tests/tparscfg.nim
+++ /dev/null
@@ -1,25 +0,0 @@
-
-import
-  os, parsecfg, strutils, streams
-  
-var f = newFileStream(paramStr(1), fmRead)
-if f != nil:
-  var p: TCfgParser
-  open(p, f, paramStr(1))
-  while true:
-    var e = next(p)
-    case e.kind
-    of cfgEof: 
-      echo("EOF!")
-      break
-    of cfgSectionStart:   ## a ``[section]`` has been parsed
-      echo("new section: " & e.section)
-    of cfgKeyValuePair:
-      echo("key-value-pair: " & e.key & ": " & e.value)
-    of cfgOption:
-      echo("command: " & e.key & ": " & e.value)
-    of cfgError:
-      echo(e.msg)
-  close(p)
-else:
-  echo("cannot open: " & paramStr(1))
diff --git a/tests/tparsopt.nim b/tests/tparsopt.nim
deleted file mode 100755
index 2b2da7e51..000000000
--- a/tests/tparsopt.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-# Test the new parseopt module
-
-import
-  parseopt
-
-proc writeHelp() = 
-  writeln(stdout, "Usage: tparsopt [options] filename [options]")
-
-proc writeVersion() = 
-  writeln(stdout, "Version: 1.0.0")
-  
-var
-  filename = ""
-for kind, key, val in getopt():
-  case kind
-  of cmdArgument: 
-    filename = key
-  of cmdLongOption, cmdShortOption:
-    case key
-    of "help", "h": writeHelp()
-    of "version", "v": writeVersion()
-    else: 
-      writeln(stdout, "Unknown command line option: ", key, ": ", val)
-  of cmdEnd: assert(false) # cannot happen
-if filename == "":
-  # no filename has been given, so we show the help:
-  writeHelp()
diff --git a/tests/tposix.nim b/tests/tposix.nim
deleted file mode 100755
index 87ea3acaf..000000000
--- a/tests/tposix.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-# Test Posix interface
-
-import posix
-
-var
-  u: Tutsname
-
-discard uname(u)
-
-writeln(stdout, u.sysname)
-writeln(stdout, u.nodename)
-writeln(stdout, u.release)
-writeln(stdout, u.machine)
diff --git a/tests/tprep.nim b/tests/tprep.nim
deleted file mode 100755
index 999b2f57f..000000000
--- a/tests/tprep.nim
+++ /dev/null
@@ -1,28 +0,0 @@
-# Test the features that used to belong to the preprocessor
-
-import
-  times
-
-{.warning: "This is only a test warning!".}
-
-{.define: case2.}
-{.define: case3.}
-when defined(case1):
-  {.hint: "Case 1".}
-  when defined(case3):
-    {.hint: "Case 1.3".}
-elif defined(case2):
-  {.hint: "Case 2".}
-  when defined(case3):
-    {.hint: "Case 2.3".}
-elif defined(case3):
-  {.hint: "Case 3".}
-else:
-  {.hint: "unknown case".}
-
-var
-  s: string
-write(stdout, "compiled at " & system.compileDate &
-              " " & compileTime & "\n")
-echo getDateStr()
-echo getClockStr()
diff --git a/tests/tprintf.nim b/tests/tprintf.nim
deleted file mode 100755
index 14687a937..000000000
--- a/tests/tprintf.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-# Test a printf proc

-

-proc printf(file: TFile, args: openarray[string]) =

-  var i = 0

-  while i < args.len:

-    write(file, args[i])

-    inc(i)

-

-printf(stdout, ["Andreas ", "Rumpf\n"])

-#OUT Andreas Rumpf

diff --git a/tests/tprocvar.nim b/tests/tprocvar.nim
deleted file mode 100755
index f51543dfa..000000000
--- a/tests/tprocvar.nim
+++ /dev/null
@@ -1,26 +0,0 @@
-# test variables of type proc

-
-proc pa() {.cdecl.} = write(stdout, "pa")
-proc pb() {.cdecl.} = write(stdout, "pb")
-proc pc() {.cdecl.} = write(stdout, "pc")
-proc pd() {.cdecl.} = write(stdout, "pd")
-proc pe() {.cdecl.} = write(stdout, "pe")
-
-const
-  algos = [pa, pb, pc, pd, pe]
-

-var

-  x: proc (a, b: int): int {.cdecl.}

-

-proc ha(c, d: int): int {.cdecl.} =

-  echo(c + d)

-  result = c + d

-
-for a in items(algos):
-  a()
-

-x = ha

-discard x(3, 4)

-

-#OUT papbpcpdpe7

-

diff --git a/tests/tpush.nim b/tests/tpush.nim
deleted file mode 100755
index 5fb411a79..000000000
--- a/tests/tpush.nim
+++ /dev/null
@@ -1,15 +0,0 @@
-# test the new pragmas

-

-{.push warnings: off, hints: off.}

-proc noWarning() =

-  var

-    x: int

-  echo(x)

-

-{.pop.}

-

-proc WarnMe() =

-  var

-    x: int

-  echo(x)

-

diff --git a/tests/tquit.nim b/tests/tquit.nim
deleted file mode 100755
index d4dc1522d..000000000
--- a/tests/tquit.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# Test the new beforeQuit variable: 

-

-proc myExit() {.noconv.} = 

-  write(stdout, "just exiting...\n")

-

-addQuitProc(myExit)

diff --git a/tests/tradix.nim b/tests/tradix.nim
deleted file mode 100755
index e7ca210e4..000000000
--- a/tests/tradix.nim
+++ /dev/null
@@ -1,319 +0,0 @@
-# implements and tests an efficient radix tree
-
-## another method to store an efficient array of pointers: 
-## We use a radix tree with node compression. 
-## There are two node kinds:
-
-const bitsPerUnit = 8*sizeof(int)
-
-type
-  TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear
-  PRadixNode = ptr TRadixNode
-  TRadixNode {.pure.} = object
-    kind: TRadixNodeKind
-  TRadixNodeLinear = object of TRadixNode
-    len: byte
-    keys: array [0..31, byte]
-    vals: array [0..31, PRadixNode]
-  
-  TRadixNodeFull = object of TRadixNode
-    b: array [0..255, PRadixNode]
-  TRadixNodeLeafBits = object of TRadixNode
-    b: array [0..7, int]
-  TRadixNodeLeafLinear = object of TRadixNode
-    len: byte
-    keys: array [0..31, byte]
-
-var
-  root: PRadixNode
-
-proc searchInner(r: PRadixNode, a: int): PRadixNode = 
-  case r.kind
-  of rnLinear:
-    var x = cast[ptr TRadixNodeLinear](r)
-    for i in 0..ze(x.len)-1: 
-      if ze(x.keys[i]) == a: return x.vals[i]
-  of rnFull: 
-    var x = cast[ptr TRadixNodeFull](r)
-    return x.b[a]
-  else: assert(false)
-
-proc testBit(w, i: int): bool {.inline.} = 
-  result = (w and (1 shl (i %% BitsPerUnit))) != 0
-
-proc setBit(w: var int, i: int) {.inline.} = 
-  w = w or (1 shl (i %% bitsPerUnit))
-
-proc resetBit(w: var int, i: int) {.inline.} = 
-  w = w and not (1 shl (i %% bitsPerUnit))
-
-proc testOrSetBit(w: var int, i: int): bool {.inline.} = 
-  var x = (1 shl (i %% bitsPerUnit))
-  if (w and x) != 0: return true
-  w = w or x
-
-proc searchLeaf(r: PRadixNode, a: int): bool = 
-  case r.kind
-  of rnLeafBits:
-    var x = cast[ptr TRadixNodeLeafBits](r)
-    return testBit(x.b[a /% BitsPerUnit], a)
-  of rnLeafLinear:
-    var x = cast[ptr TRadixNodeLeafLinear](r)
-    for i in 0..ze(x.len)-1: 
-      if ze(x.keys[i]) == a: return true
-  else: assert(false)
-
-proc exclLeaf(r: PRadixNode, a: int) = 
-  case r.kind
-  of rnLeafBits:
-    var x = cast[ptr TRadixNodeLeafBits](r)
-    resetBit(x.b[a /% BitsPerUnit], a)
-  of rnLeafLinear:
-    var x = cast[ptr TRadixNodeLeafLinear](r)
-    var L = ze(x.len)
-    for i in 0..L-1: 
-      if ze(x.keys[i]) == a: 
-        x.keys[i] = x.keys[L-1]
-        dec(x.len)
-        return
-  else: assert(false)
-
-proc in_Operator*(r: PRadixNode, a: TAddress): bool =
-  if r == nil: return false
-  var x = searchInner(r, a shr 24 and 0xff)
-  if x == nil: return false
-  x = searchInner(x, a shr 16 and 0xff)
-  if x == nil: return false
-  x = searchInner(x, a shr 8 and 0xff)
-  if x == nil: return false
-  return searchLeaf(x, a and 0xff)
-
-proc excl*(r: PRadixNode, a: TAddress): bool =
-  if r == nil: return false
-  var x = searchInner(r, a shr 24 and 0xff)
-  if x == nil: return false
-  x = searchInner(x, a shr 16 and 0xff)
-  if x == nil: return false
-  x = searchInner(x, a shr 8 and 0xff)
-  if x == nil: return false
-  exclLeaf(x, a and 0xff)
-
-proc addLeaf(r: var PRadixNode, a: int): bool = 
-  if r == nil:
-    # a linear node:
-    var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
-    x.kind = rnLeafLinear
-    x.len = 1'i8
-    x.keys[0] = toU8(a)
-    r = x
-    return false # not already in set
-  case r.kind 
-  of rnLeafBits: 
-    var x = cast[ptr TRadixNodeLeafBits](r)
-    return testOrSetBit(x.b[a /% BitsPerUnit], a)
-  of rnLeafLinear: 
-    var x = cast[ptr TRadixNodeLeafLinear](r)
-    var L = ze(x.len)
-    for i in 0..L-1: 
-      if ze(x.keys[i]) == a: return true
-    if L <= high(x.keys):
-      x.keys[L] = toU8(a)
-      inc(x.len)
-    else: 
-      # transform into a full node:
-      var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits)))
-      y.kind = rnLeafBits
-      for i in 0..ze(x.len)-1: 
-        var u = ze(x.keys[i])
-        setBit(y.b[u /% BitsPerUnit], u)
-      setBit(y.b[a /% BitsPerUnit], a)
-      dealloc(r)
-      r = y
-  else: assert(false)
-
-proc addInner(r: var PRadixNode, a: int, d: int): bool = 
-  if d == 0: 
-    return addLeaf(r, a and 0xff)
-  var k = a shr d and 0xff
-  if r == nil:
-    # a linear node:
-    var x = cast[ptr TRadixNodeLinear](alloc(sizeof(TRadixNodeLinear)))
-    x.kind = rnLinear
-    x.len = 1'i8
-    x.keys[0] = toU8(k)
-    r = x
-    return addInner(x.vals[0], a, d-8)
-  case r.kind
-  of rnLinear:
-    var x = cast[ptr TRadixNodeLinear](r)
-    var L = ze(x.len)
-    for i in 0..L-1: 
-      if ze(x.keys[i]) == k: # already exists
-        return addInner(x.vals[i], a, d-8)
-    if L <= high(x.keys):
-      x.keys[L] = toU8(k)
-      inc(x.len)
-      return addInner(x.vals[L], a, d-8)
-    else: 
-      # transform into a full node:
-      var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull)))
-      y.kind = rnFull
-      for i in 0..L-1: y.b[ze(x.keys[i])] = x.vals[i]
-      dealloc(r)
-      r = y
-      return addInner(y.b[k], a, d-8)
-  of rnFull: 
-    var x = cast[ptr TRadixNodeFull](r)
-    return addInner(x.b[k], a, d-8)
-  else: assert(false)
-
-proc incl*(r: var PRadixNode, a: TAddress) {.inline.} = 
-  discard addInner(r, a, 24)
-  
-proc testOrIncl*(r: var PRadixNode, a: TAddress): bool {.inline.} = 
-  return addInner(r, a, 24)
-      
-iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] = 
-  if r != nil:
-    case r.kind 
-    of rnFull: 
-      var r = cast[ptr TRadixNodeFull](r)
-      for i in 0..high(r.b):
-        if r.b[i] != nil: 
-          yield (i, r.b[i])
-    of rnLinear: 
-      var r = cast[ptr TRadixNodeLinear](r)
-      for i in 0..ze(r.len)-1: 
-        yield (ze(r.keys[i]), r.vals[i])
-    else: assert(false)
-
-iterator leafElements(r: PRadixNode): int = 
-  if r != nil:
-    case r.kind
-    of rnLeafBits: 
-      var r = cast[ptr TRadixNodeLeafBits](r)
-      # iterate over any bit:
-      for i in 0..high(r.b): 
-        if r.b[i] != 0: # test all bits for zero
-          for j in 0..BitsPerUnit-1: 
-            if testBit(r.b[i], j): 
-              yield i*BitsPerUnit+j
-    of rnLeafLinear: 
-      var r = cast[ptr TRadixNodeLeafLinear](r)
-      for i in 0..ze(r.len)-1: 
-        yield ze(r.keys[i])
-    else: assert(false)
-    
-iterator elements*(r: PRadixNode): TAddress {.inline.} = 
-  for p1, n1 in innerElements(r): 
-    for p2, n2 in innerElements(n1):
-      for p3, n3 in innerElements(n2):
-        for p4 in leafElements(n3): 
-          yield p1 shl 24 or p2 shl 16 or p3 shl 8 or p4
-  
-proc main() =
-  const
-    numbers = [128, 1, 2, 3, 4, 255, 17, -8, 45, 19_000]
-  var
-    r: PRadixNode = nil
-  for x in items(numbers):
-    echo testOrIncl(r, x)
-  for x in elements(r): echo(x)
-
-main()
-
-
-when false:
-  proc traverse(r: PRadixNode, prefix: int, d: int) = 
-    if r == nil: return
-    case r.kind 
-    of rnLeafBits: 
-      assert(d == 0)
-      var x = cast[ptr TRadixNodeLeafBits](r)
-      # iterate over any bit:
-      for i in 0..high(x.b): 
-        if x.b[i] != 0: # test all bits for zero
-          for j in 0..BitsPerUnit-1: 
-            if testBit(x.b[i], j): 
-              visit(prefix or i*BitsPerUnit+j)
-    of rnLeafLinear: 
-      assert(d == 0)
-      var x = cast[ptr TRadixNodeLeafLinear](r)
-      for i in 0..ze(x.len)-1: 
-        visit(prefix or ze(x.keys[i]))
-    of rnFull: 
-      var x = cast[ptr TRadixNodeFull](r)
-      for i in 0..high(r.b):
-        if r.b[i] != nil: 
-          traverse(r.b[i], prefix or (i shl d), d-8)
-    of rnLinear: 
-      var x = cast[ptr TRadixNodeLinear](r)
-      for i in 0..ze(x.len)-1: 
-        traverse(x.vals[i], prefix or (ze(x.keys[i]) shl d), d-8)
-
-  type
-    TRadixIter {.final.} = object
-      r: PRadixNode
-      p: int
-      x: int
-
-  proc init(i: var TRadixIter, r: PRadixNode) =
-    i.r = r
-    i.x = 0
-    i.p = 0
-    
-  proc nextr(i: var TRadixIter): PRadixNode = 
-    if i.r == nil: return nil
-    case i.r.kind 
-    of rnFull: 
-      var r = cast[ptr TRadixNodeFull](i.r)
-      while i.x <= high(r.b):
-        if r.b[i.x] != nil: 
-          i.p = i.x
-          return r.b[i.x]
-        inc(i.x)
-    of rnLinear: 
-      var r = cast[ptr TRadixNodeLinear](i.r)
-      if i.x < ze(r.len): 
-        i.p = ze(r.keys[i.x])
-        result = r.vals[i.x]
-        inc(i.x)
-    else: assert(false)
-
-  proc nexti(i: var TRadixIter): int = 
-    result = -1
-    case i.r.kind 
-    of rnLeafBits: 
-      var r = cast[ptr TRadixNodeLeafBits](i.r)
-      # iterate over any bit:    
-      for i in 0..high(r.b): 
-        if x.b[i] != 0: # test all bits for zero
-          for j in 0..BitsPerUnit-1: 
-            if testBit(x.b[i], j): 
-              visit(prefix or i*BitsPerUnit+j)
-    of rnLeafLinear: 
-      var r = cast[ptr TRadixNodeLeafLinear](i.r)
-      if i.x < ze(r.len): 
-        result = ze(r.keys[i.x])
-        inc(i.x)
-
-  iterator elements(r: PRadixNode): TAddress {.inline.} = 
-    var
-      a, b, c, d: TRadixIter
-    init(a, r)
-    while true: 
-      var x = nextr(a)
-      if x != nil: 
-        init(b, x)
-        while true: 
-          var y = nextr(b)
-          if y != nil: 
-            init(c, y)
-            while true:
-              var z = nextr(c)
-              if z != nil: 
-                init(d, z)
-                while true:
-                  var q = nexti(d)
-                  if q != -1: 
-                    yield a.p shl 24 or b.p shl 16 or c.p shl 8 or q
diff --git a/tests/treadln.nim b/tests/treadln.nim
deleted file mode 100755
index 7703d5a56..000000000
--- a/tests/treadln.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-# test the improved readline handling that does not care whether its
-# Macintosh, Unix or Windows text format.
-
-var
-  inp: TFile
-  line: string
-
-if openFile(inp, "readme.txt"):
-  while not EndOfFile(inp):
-    line = readLine(inp)
-    echo("#" & line & "#")
-  closeFile(inp)
diff --git a/tests/trecmod.nim b/tests/trecmod.nim
deleted file mode 100755
index 9d39d3ff7..000000000
--- a/tests/trecmod.nim
+++ /dev/null
@@ -1,2 +0,0 @@
-# recursive module

-import mrecmod

diff --git a/tests/tregex.nim b/tests/tregex.nim
deleted file mode 100755
index d9d22d603..000000000
--- a/tests/tregex.nim
+++ /dev/null
@@ -1,19 +0,0 @@
-# Test the new regular expression module

-# which is based on the PCRE library

-

-import

-  regexprs

-
-if "keyA = valueA" =~ r"\s*(\w+)\s*\=\s*(\w+)":
-  write(stdout, "key: ", matches[1])
-elif "# comment!" =~ r"\s*(\#.*)":
-  echo("comment: ", matches[1])
-else: 
-  echo("Bug!")
-

-if "Username".match("[A-Za-z]+"):

-  echo("Yes!")

-else:

-  echo("Bug!")

-

-#OUT key: keyAYes!

diff --git a/tests/treguse.nim b/tests/treguse.nim
deleted file mode 100755
index dc805fc70..000000000
--- a/tests/treguse.nim
+++ /dev/null
@@ -1,21 +0,0 @@
-# Test the register usage of the virtual machine and

-# the blocks in var statements

-

-proc main(a, b: int) =

-  var x = 0

-  write(stdout, x)

-  if x == 0:

-    var y = 55

-    write(stdout, y)

-    write(stdout, "this should be the case")

-    var input = "<no input>"

-    if input == "Andreas":

-      write(stdout, "wow")

-    else:

-      write(stdout, "hugh")

-  else:

-    var z = 66

-    write(stdout, z) # "bug!")

-

-main(45, 1000)

-#OUT 055this should be the casehugh

diff --git a/tests/trepr.nim b/tests/trepr.nim
deleted file mode 100755
index 4a56842f6..000000000
--- a/tests/trepr.nim
+++ /dev/null
@@ -1,32 +0,0 @@
-# test the new "repr" built-in proc

-

-type

-  TEnum = enum

-    en1, en2, en3, en4, en5, en6

-

-  TPoint {.final.} = object

-    x, y, z: int

-    s: array [0..1, string]

-    e: TEnum

-

-var

-  p: TPoint

-  q: ref TPoint

-  s: seq[ref TPoint]

-

-p.x = 0

-p.y = 13

-p.z = 45

-p.s[0] = "abc"

-p.s[1] = "xyz"

-p.e = en6

-

-new(q)

-q^ = p

-

-s = @[q, q, q, q]

-

-writeln(stdout, repr(p))

-writeln(stdout, repr(q))

-writeln(stdout, repr(s))

-writeln(stdout, repr(en4))

diff --git a/tests/trmacros/tdisallowif.nim b/tests/trmacros/tdisallowif.nim
new file mode 100644
index 000000000..8d83f6ddf
--- /dev/null
+++ b/tests/trmacros/tdisallowif.nim
@@ -0,0 +1,28 @@
+discard """
+  errormsg: "usage of 'disallowIf' is an {.error.} defined at tdisallowif.nim(10, 1)"
+  line: 24
+"""
+
+template optZero{x+x}(x: int): int = x*3
+template andthen{`*`(x,3)}(x: int): int = x*4
+template optSubstr1{x = substr(x, 0, b)}(x: string, b: int) = setlen(x, b+1)
+
+template disallowIf{
+  if cond: action
+  else: action2
+}(cond: bool, action, action2: typed) {.error.} = action
+
+var y = 12
+echo y+y
+
+var s: array[0..2, string]
+s[0] = "hello"
+s[0] = substr(s[0], 0, 2)
+
+echo s[0]
+
+if s[0] != "hi":
+  echo "do it"
+  echo "more branches"
+else:
+  discard
diff --git a/tests/trmacros/tnorewrite.nim b/tests/trmacros/tnorewrite.nim
new file mode 100644
index 000000000..e6769246f
--- /dev/null
+++ b/tests/trmacros/tnorewrite.nim
@@ -0,0 +1,20 @@
+block:
+  proc get(x: int): int = x
+
+  template t{get(a)}(a: int): int =
+    {.noRewrite.}:
+      get(a) + 1
+
+  doAssert get(0) == 1
+
+block:
+  var x: int
+
+  template asgn{a = b}(a: int{lvalue}, b: int) =
+    let newVal = b + 1
+    # ^ this is needed but should it be?
+    {.noRewrite.}:
+      a = newVal
+
+  x = 10
+  doAssert x == 11, $x
diff --git a/tests/trmacros/tor.nim b/tests/trmacros/tor.nim
new file mode 100644
index 000000000..9defc4d1b
--- /dev/null
+++ b/tests/trmacros/tor.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''
+3
+30
+true
+'''
+"""
+
+
+# bug #798
+template t012{(0|1|2){x}}(x: untyped): untyped = x+1
+let z = 1
+# outputs 3 thanks to fixpoint iteration:
+echo z
+
+
+template arithOps: untyped = (`+` | `-` | `*`)
+template testOr{ (arithOps{f})(a, b) }(a, b, f: untyped): untyped =
+  {.noRewrite.}:
+    f(a mod 10, b)
+
+let xx = 10
+echo 10*xx
+
+template t{x = (~x){y} and (~x){z}}(x, y, z: bool): typed =
+  x = y
+  if x: x = z
+
+var
+  a = true
+  b = true
+  c = false
+a = b and a
+echo a
diff --git a/tests/trmacros/trmacros_various.nim b/tests/trmacros/trmacros_various.nim
new file mode 100644
index 000000000..8fe51e548
--- /dev/null
+++ b/tests/trmacros/trmacros_various.nim
@@ -0,0 +1,111 @@
+discard """
+output: '''
+12false3ha
+21
+optimized
+'''
+"""
+
+import macros, pegs
+
+
+block arglist:
+  proc f(x: varargs[string, `$`]) = discard
+  template optF{f(x)}(x: varargs[untyped]) =
+    writeLine(stdout, x)
+
+  f 1, 2, false, 3, "ha"
+
+
+
+block tcse:
+  template cse{f(a, a, x)}(a: typed{(nkDotExpr|call|nkBracketExpr)&noSideEffect},
+                         f: typed, x: varargs[typed]): untyped =
+    let aa = a
+    f(aa, aa, x)+4
+
+  var
+    a: array[0..10, int]
+    i = 3
+  doAssert a[i] + a[i] == 4
+
+
+
+block hoist:
+  template optPeg{peg(pattern)}(pattern: string{lit}): Peg =
+    {.noRewrite.}:
+      var gl {.global, gensym.} = peg(pattern)
+    gl
+  doAssert match("(a b c)", peg"'(' @ ')'")
+  doAssert match("W_HI_Le", peg"\y 'while'")
+
+
+
+block tmatrix:
+  type
+    TMat = object
+      dummy: int
+
+  proc `*`(a, b: TMat): TMat = nil
+  proc `+`(a, b: TMat): TMat = nil
+  proc `-`(a, b: TMat): TMat = nil
+  proc `$`(a: TMat): string = result = $a.dummy
+  proc mat21(): TMat =
+    result.dummy = 21
+
+  macro optOps{ (`+`|`-`|`*`) ** a }(a: TMat): untyped =
+    result = newCall(bindSym"mat21")
+
+  #macro optPlus{ `+` * a }(a: varargs[TMat]): expr =
+  #  result = newIntLitNode(21)
+
+  var x, y, z: TMat
+  echo x + y * z - x
+
+
+
+block tnoalias:
+  template optslice{a = b + c}(a: untyped{noalias}, b, c: untyped): typed =
+    a = b
+    inc a, c
+  var
+    x = 12
+    y = 10
+    z = 13
+  x = y+z
+  doAssert x == 23
+
+
+
+block tnoendlessrec:
+  # test that an endless recursion is avoided:
+  template optLen{len(x)}(x: typed): int = len(x)
+
+  var s = "lala"
+  doAssert len(s) == 4
+
+
+
+block tstatic_t_bug:
+  # bug #4227
+  type Vector64[N: static[int]] = array[N, int]
+
+  proc `*`[N: static[int]](a: Vector64[N]; b: float64): Vector64[N] =
+    result = a
+
+  proc `+=`[N: static[int]](a: var Vector64[N]; b: Vector64[N]) =
+    echo "regular"
+
+  proc linearCombinationMut[N: static[int]](a: float64, v: var Vector64[N], w: Vector64[N])  {. inline .} =
+    echo "optimized"
+
+  template rewriteLinearCombinationMut{v += `*`(w, a)}(a: float64, v: var Vector64, w: Vector64): auto =
+    linearCombinationMut(a, v, w)
+
+  proc main() =
+    const scaleVal = 9.0
+    var a, b: Vector64[7]
+    a += b * scaleval
+
+  main()
+
diff --git a/tests/trmacros/trmacros_various2.nim b/tests/trmacros/trmacros_various2.nim
new file mode 100644
index 000000000..981df4ca6
--- /dev/null
+++ b/tests/trmacros/trmacros_various2.nim
@@ -0,0 +1,91 @@
+discard """
+output: '''
+0
+-2
+48
+hel
+lo
+my awesome concat
+'''
+"""
+
+
+block tnoalias2:
+  # bug #206
+  template optimizeOut{testFunc(a, b)}(a: int, b: int{alias}): untyped = 0
+
+  proc testFunc(a, b: int): int = result = a + b
+  var testVar = 1
+  echo testFunc(testVar, testVar)
+
+
+  template ex{a = b + c}(a : int{noalias}, b, c : int) =
+    a = b
+    inc a, b
+    echo "came here"
+
+  var x = 5
+  x = x + x
+
+
+
+block tpartial:
+  proc p(x, y: int; cond: bool): int =
+    result = if cond: x + y else: x - y
+
+  template optPTrue{p(x, y, true)}(x, y): untyped = x - y
+  template optPFalse{p(x, y, false)}(x, y): untyped = x + y
+
+  echo p(2, 4, true)
+
+
+
+block tpatterns:
+  template optZero{x+x}(x: int): int = x*3
+  template andthen{`*`(x,3)}(x: int): int = x*4
+  template optSubstr1{x = substr(x, a, b)}(x: string, a, b: int) = setlen(x, b+1)
+
+  var y = 12
+  echo y+y
+
+  var s: array[0..2, string]
+  s[0] = "hello"
+  s[0] = substr(s[0], 0, 2)
+
+  echo s[0]
+
+  # Test varargs matching
+  proc someVarargProc(k: varargs[string]) = doAssert(false) # this should not get called
+  template someVarargProcSingleArg{someVarargProc([a])}(a: string) = echo a
+  someVarargProc("lo")
+
+
+
+block tstar:
+  var
+    calls = 0
+
+  proc `&&`(s: varargs[string]): string =
+    result = s[0]
+    for i in 1..len(s)-1: result.add s[i]
+    inc calls
+
+  template optConc{ `&&` * a }(a: string): string =
+    {.noRewrite.}:
+      &&a
+
+  let space = " "
+  echo "my" && (space & "awe" && "some " ) && "concat"
+
+  # check that it's been optimized properly:
+  doAssert calls == 1
+
+# bug #7524
+template in_to_out(typIn, typOut: typedesc) =
+  proc to_out(x: typIn{lit}): typOut = result = ord(x)
+
+# Generating the proc via template doesn't work
+in_to_out(char, int)
+
+# This works
+proc to_out2(x: char{lit}): int = result = ord(x)
diff --git a/tests/trmacros/tstmtlist.nim b/tests/trmacros/tstmtlist.nim
new file mode 100644
index 000000000..8261e7c45
--- /dev/null
+++ b/tests/trmacros/tstmtlist.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''0
+|12|
+34
+'''
+"""
+
+template optWrite{
+  write(f, x)
+  ((write|writeLine){w})(f, y)
+}(x, y: varargs[untyped], f, w: untyped) =
+  w(f, "|", x, y, "|")
+
+if true:
+  echo "0"
+  write stdout, "1"
+  writeLine stdout, "2"
+  write stdout, "3"
+  echo "4"
+
+# bug #7972
+
+template optimizeLogWrites*{
+  write(f, x)
+  write(f, y)
+}(x, y: string{lit}, f: File) =
+  write(f, x & y)
+
+proc foo() =
+  const N = 1
+  stdout.write("")
+  stdout.write("")
+
+foo()
diff --git a/tests/tseq2.nim b/tests/tseq2.nim
deleted file mode 100755
index 03bdb3fab..000000000
--- a/tests/tseq2.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-
-  
-proc `*` *(a, b: seq[int]): seq[int] = 
-  # allocate a new sequence:
-  newSeq(result, len(a))
-  # multiply two int sequences:
-  for i in 0..len(a)-1: result[i] = a[i] * b[i]
-
-when isMainModule: 
-  # test the new ``*`` operator for sequences:
-  assert(@[1, 2, 3] * @[1, 2, 3] == @[1, 4, 9])
-
-
diff --git a/tests/tseqcon.nim b/tests/tseqcon.nim
deleted file mode 100755
index 935da86b5..000000000
--- a/tests/tseqcon.nim
+++ /dev/null
@@ -1,45 +0,0 @@
-# Test the add proc for sequences and strings

-

-const

-  nestedFixed = true

-

-type

-  TRec {.final.} = object

-    x, y: int

-    s: string

-    seq: seq[string]

-  TRecSeq = seq[TRec]

-

-proc test() =

-  var s, b: seq[string]

-  s = @[]

-  add(s, "Hi")

-  add(s, "there, ")

-  add(s, "what's your name?")

-

-  b = s # deep copying here!

-  b[0][1] = 'a'

-

-  for i in 0 .. len(s)-1:

-    write(stdout, s[i])

-  for i in 0 .. len(b)-1:

-    write(stdout, b[i])

-

-

-when nestedFixed:

-  proc nested() =

-    var

-      s: seq[seq[string]]

-    for i in 0..10_000: # test if the garbage collector

-      # now works with sequences

-      s = @[

-        @["A", "B", "C", "D"],

-        @["E", "F", "G", "H"],

-        @["I", "J", "K", "L"],

-        @["M", "N", "O", "P"]]

-

-test()

-when nestedFixed:

-  nested()

-

-#OUT Hithere, what's your name?Hathere, what's your name?

diff --git a/tests/tsets.nim b/tests/tsets.nim
deleted file mode 100755
index 08ab3e54b..000000000
--- a/tests/tsets.nim
+++ /dev/null
@@ -1,58 +0,0 @@
-# Test the handling of sets

-

-import

-  strutils

-

-proc testSets(s: var set[char]) =

-  s = {'A', 'B', 'C', 'E'..'G'} + {'Z'} + s

-

-# test sets if the first element is different from 0:

-type

-  TAZ = range['a'..'z']

-  TAZset = set[TAZ]

-

-  TTokType* = enum 

-    tkInvalid, tkEof,

-    tkSymbol,

-    tkAddr, tkAnd, tkAs, tkAsm, tkBlock, tkBreak, tkCase, tkCast, tkConst, 

-    tkContinue, tkConverter, tkDiscard, tkDiv, tkElif, tkElse, tkEnd, tkEnum, 

-    tkExcept, tkException, tkFinally, tkFor, tkFrom, tkGeneric, tkIf, tkImplies, 

-    tkImport, tkIn, tkInclude, tkIs, tkIsnot, tkIterator, tkLambda, tkMacro, 

-    tkMethod, tkMod, tkNil, tkNot, tkNotin, tkObject, tkOf, tkOr, tkOut, tkProc, 

-    tkPtr, tkRaise, tkRecord, tkRef, tkReturn, tkShl, tkShr, tkTemplate, tkTry, 

-    tkType, tkVar, tkWhen, tkWhere, tkWhile, tkWith, tkWithout, tkXor, tkYield,

-    tkIntLit, tkInt8Lit, tkInt16Lit, tkInt32Lit, tkInt64Lit, tkFloatLit, 

-    tkFloat32Lit, tkFloat64Lit, tkStrLit, tkRStrLit, tkTripleStrLit, tkCharLit, 

-    tkRCharLit, tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, 

-    tkCurlyRi, tkBracketDotLe, tkBracketDotRi, 

-    tkCurlyDotLe, tkCurlyDotRi, 

-    tkParDotLe, tkParDotRi,

-    tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot, tkHat, tkOpr, 

-    tkComment, tkAccent, tkInd, tkSad, tkDed,

-    tkSpaces, tkInfixOpr, tkPrefixOpr, tkPostfixOpr

-  TTokTypeRange = range[tkSymbol..tkDed]

-  TTokTypes* = set[TTokTypeRange]

-

-const

-  toktypes: TTokTypes = {TTokTypeRange(tkSymbol)..pred(tkIntLit), 
-                         tkStrLit..tkTripleStrLit}

-

-var

-  s: set[char]

-  a: TAZset

-s = {'0'..'9'}

-testSets(s)

-if 'F' in s: write(stdout, "Ha ein F ist in s!\n")

-else: write(stdout, "BUG: F ist nicht in s!\n")

-a = {} #{'a'..'z'}

-for x in low(TAZ) .. high(TAZ):

-  incl(a, x)

-  if x in a: nil

-  else: write(stdout, "BUG: something not in a!\n")

-

-for x in low(TTokTypeRange) .. high(TTokTypeRange):

-  if x in tokTypes:

-    nil
-    #writeln(stdout, "the token '$1' is in the set" % repr(x))

-

-#OUT Ha ein F ist in s!

diff --git a/tests/tsimmeth.nim b/tests/tsimmeth.nim
deleted file mode 100755
index 3f5f810e6..000000000
--- a/tests/tsimmeth.nim
+++ /dev/null
@@ -1,8 +0,0 @@
-# Test method simulation
-
-import strutils
-
-var x = "hallo world!".toLower.toUpper
-x.echo()
-#OUT HALLO WORLD!
-
diff --git a/tests/tsimtych.nim b/tests/tsimtych.nim
deleted file mode 100755
index b100c62e3..000000000
--- a/tests/tsimtych.nim
+++ /dev/null
@@ -1,5 +0,0 @@
-# Test 2

-# Simple type checking

-

-var a: string

-a = false #ERROR

diff --git a/tests/tsizeof.nim b/tests/tsizeof.nim
deleted file mode 100755
index f7b70dd4d..000000000
--- a/tests/tsizeof.nim
+++ /dev/null
@@ -1,10 +0,0 @@
-# Test the sizeof proc

-

-type

-  TMyRecord {.final.} = object

-    x, y: int

-    b: bool

-    r: float

-    s: string

-

-write(stdout, sizeof(TMyRecord))

diff --git a/tests/tstatret.nim b/tests/tstatret.nim
deleted file mode 100755
index ac93ac532..000000000
--- a/tests/tstatret.nim
+++ /dev/null
@@ -1,5 +0,0 @@
-# no statement after return

-proc main() =

-  return

-  echo("huch?") #ERROR_MSG statement not allowed after

-

diff --git a/tests/tstmtexp.nim b/tests/tstmtexp.nim
deleted file mode 100755
index f4d83e83f..000000000
--- a/tests/tstmtexp.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-# Test 3

-

-1+4 #ERROR_MSG value returned by statement has to be discarded

diff --git a/tests/tstrace.nim b/tests/tstrace.nim
deleted file mode 100755
index 56f20a0dd..000000000
--- a/tests/tstrace.nim
+++ /dev/null
@@ -1,16 +0,0 @@
-# Test the new stacktraces (great for debugging!)

-

-{.push stack_trace: on.}

-

-proc recTest(i: int) =

-  # enter

-  if i < 10:

-    recTest(i+1)

-  else: # should printStackTrace()

-    var p: ptr int = nil

-    p^ = 12

-  # leave

-

-{.pop.}

-

-recTest(0)

diff --git a/tests/tstrdesc.nim b/tests/tstrdesc.nim
deleted file mode 100755
index 1c2e85b4b..000000000
--- a/tests/tstrdesc.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-var

-  x: array [0..2, int]

-

-x = [0, 1, 2]

-

-type

-  TStringDesc {.final.} = object

-    len, space: int # len and space without counting the terminating zero

-    data: array [0..0, char] # for the '\0' character

-

-var

-  emptyString {.exportc: "emptyString".}: TStringDesc 

-

-

diff --git a/tests/tstreams.nim b/tests/tstreams.nim
deleted file mode 100755
index 68ca8eeeb..000000000
--- a/tests/tstreams.nim
+++ /dev/null
@@ -1,7 +0,0 @@
-import streams
-
-var outp = newFileStream(stdout)
-var inp = newFileStream(stdin)
-write(outp, "Hallo! What is your name?")
-var line = readLine(inp)
-write(outp, "nice name: " & line)
diff --git a/tests/tstrtabs.nim b/tests/tstrtabs.nim
deleted file mode 100755
index 299db609d..000000000
--- a/tests/tstrtabs.nim
+++ /dev/null
@@ -1,12 +0,0 @@
-import strtabs
-
-var tab = newStringTable(["key1", "val1", "key2", "val2"], 
-                         modeStyleInsensitive)
-for i in 0..80:
-  tab["key_" & $i] = "value" & $i
-  
-for key, val in pairs(tab):
-  writeln(stdout, key, ": ", val)
-writeln(stdout, "length of table ", $tab.len)
-
-writeln(stdout, `%`("$key1 = $key2; ${PATH}", tab, {useEnvironment}))
diff --git a/tests/tstrutil.nim b/tests/tstrutil.nim
deleted file mode 100755
index 0468dfa0c..000000000
--- a/tests/tstrutil.nim
+++ /dev/null
@@ -1,24 +0,0 @@
-# test the new strutils module

-

-import

-  strutils

-

-proc testStrip() =

-  write(stdout, strip("  ha  "))

-

-proc main() = 

-  testStrip()

-  for p in split("/home/a1:xyz:/usr/bin", {':'}):

-    write(stdout, p)

-    

-

-assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffix") == 0)

-assert(editDistance("prefix__hallo_suffix", "prefix__hallo_suffi1") == 1)

-assert(editDistance("prefix__hallo_suffix", "prefix__HALLO_suffix") == 5)

-assert(editDistance("prefix__hallo_suffix", "prefix__ha_suffix") == 3)

-assert(editDistance("prefix__hallo_suffix", "prefix") == 14)

-assert(editDistance("prefix__hallo_suffix", "suffix") == 14)

-assert(editDistance("prefix__hallo_suffix", "prefix__hao_suffix") == 2)

-

-main()

-#OUT ha/home/a1xyz/usr/bin

diff --git a/tests/ttempl.nim b/tests/ttempl.nim
deleted file mode 100755
index dcf096671..000000000
--- a/tests/ttempl.nim
+++ /dev/null
@@ -1,27 +0,0 @@
-# Test the new template file mechanism
-
-import
-  os, times
-
-include "sunset.tmpl"
-
-const
-  tabs = [["home", "index"],
-          ["news", "news"],
-          ["documentation", "documentation"],
-          ["download", "download"],
-          ["FAQ", "question"],
-          ["links", "links"]]
-
-
-var i = 0
-for item in items(tabs): 
-  var content = $i
-  var file: TFile
-  if openFile(file, changeFileExt(item[1], "html"), fmWrite): 
-    write(file, sunsetTemplate(current=item[1], ticker="", content=content,
-                               tabs=tabs))
-    closeFile(file)
-  else:
-    write(stdout, "cannot open file for writing")
-  inc(i)
diff --git a/tests/ttempl2.nim b/tests/ttempl2.nim
deleted file mode 100755
index fba6bd0cb..000000000
--- a/tests/ttempl2.nim
+++ /dev/null
@@ -1,14 +0,0 @@
-template declareInScope(x: expr, t: typeDesc): stmt = 
-  var x: t
-  
-template declareInNewScope(x: expr, t: typeDesc): stmt = 
-  # open a new scope:
-  block: 
-    var x: t
-
-declareInScope(a, int)
-a = 42  # works, `a` is known here
-
-declareInNewScope(b, int)
-b = 42  #ERROR_MSG undeclared identifier: 'b'
-
diff --git a/tests/ttempl3.nim b/tests/ttempl3.nim
deleted file mode 100755
index 0c8fa9a94..000000000
--- a/tests/ttempl3.nim
+++ /dev/null
@@ -1,26 +0,0 @@
-
-template withOpenFile(f: expr, filename: string, mode: TFileMode,
-                      actions: stmt): stmt =
-  block:
-    var f: TFile
-    if open(f, filename, mode):
-      try:
-        actions
-      finally:
-        close(f)
-    else:
-      quit("cannot open for writing: " & filename)
-    
-withOpenFile(txt, "ttempl3.txt", fmWrite):
-  writeln(txt, "line 1")
-  txt.writeln("line 2")
-  
-# Test zero argument template: 
-template ha: expr = myVar[0]
-  
-var
-  myVar: array[0..1, int]
-  
-ha = 1  
-echo(ha)
-
diff --git a/tests/ttime.nim b/tests/ttime.nim
deleted file mode 100755
index bad818816..000000000
--- a/tests/ttime.nim
+++ /dev/null
@@ -1,6 +0,0 @@
-# test the new time module

-

-import

-  times

-

-write(stdout, $getTime())

diff --git a/tests/tuples/mnimsconstunpack.nim b/tests/tuples/mnimsconstunpack.nim
new file mode 100644
index 000000000..65fafc12f
--- /dev/null
+++ b/tests/tuples/mnimsconstunpack.nim
@@ -0,0 +1,4 @@
+proc foo(): tuple[a, b: string] =
+  result = ("a", "b")
+
+const (a, b*) = foo()
diff --git a/tests/tuples/t12892.nim b/tests/tuples/t12892.nim
new file mode 100644
index 000000000..d69e99c7f
--- /dev/null
+++ b/tests/tuples/t12892.nim
@@ -0,0 +1,8 @@
+discard """
+  disabled: i386
+"""
+
+template works[T](): auto = T.high - 1
+template breaks[T](): auto = (T.high - 1, true)
+doAssert $works[uint]() == "18446744073709551614"
+doAssert $breaks[uint]() == "(18446744073709551614, true)"
diff --git a/tests/tuples/t18125_1.nim b/tests/tuples/t18125_1.nim
new file mode 100644
index 000000000..74fdfe8f5
--- /dev/null
+++ b/tests/tuples/t18125_1.nim
@@ -0,0 +1,14 @@
+# issue #18125 solved with type inference
+
+type
+  Parent = ref object of RootObj
+
+  Child = ref object of Parent
+    c: char
+
+func foo(c: char): (Parent, int) =
+  # Works if you use (Parent(Child(c: c)), 0)
+  (Child(c: c), 0)
+
+let x = foo('x')[0]
+doAssert Child(x).c == 'x'
diff --git a/tests/tuples/t18125_2.nim b/tests/tuples/t18125_2.nim
new file mode 100644
index 000000000..fe0a4a8bb
--- /dev/null
+++ b/tests/tuples/t18125_2.nim
@@ -0,0 +1,20 @@
+discard """
+  errormsg: "type mismatch: got <(Child, int)> but expected '(Parent, int)'"
+  line: 17
+"""
+
+# issue #18125 solved with correct type relation
+
+type
+  Parent = ref object of RootObj
+
+  Child = ref object of Parent
+    c: char
+
+func foo(c: char): (Parent, int) =
+  # Works if you use (Parent(Child(c: c)), 0)
+  let x = (Child(c: c), 0)
+  x
+
+let x = foo('x')[0]
+doAssert Child(x).c == 'x'
diff --git a/tests/tuples/t7012.nim b/tests/tuples/t7012.nim
new file mode 100644
index 000000000..32d441ddd
--- /dev/null
+++ b/tests/tuples/t7012.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "illegal recursion in type 'Node'"
+"""
+
+type Node[T] = tuple
+    next: ref Node[T]
+var n: Node[int]
\ No newline at end of file
diff --git a/tests/tuples/t9177.nim b/tests/tuples/t9177.nim
new file mode 100644
index 000000000..e6dd0cb1d
--- /dev/null
+++ b/tests/tuples/t9177.nim
@@ -0,0 +1,15 @@
+discard """
+  action: run
+"""
+
+block:
+  var x = (a: 5, b: 1)
+  x = (3 * x.a + 2 * x.b, x.a + x.b)
+  doAssert x.a == 17
+  doAssert x.b == 6
+block:
+  # Transformation of a tuple constructor with named arguments
+  var x = (a: 5, b: 1)
+  x = (a: 3 * x.a + 2 * x.b, b: x.a + x.b)
+  doAssert x.a == 17
+  doAssert x.b == 6
diff --git a/tests/tuples/tfortupleunpack.nim b/tests/tuples/tfortupleunpack.nim
new file mode 100644
index 000000000..e222a1ae6
--- /dev/null
+++ b/tests/tuples/tfortupleunpack.nim
@@ -0,0 +1,52 @@
+discard """
+output: '''
+123
+113283
+0
+123
+1
+113283
+@[(88, 99, 11), (88, 99, 11)]
+@[(7, 6, -28), (7, 6, -28)]
+12
+110100
+'''
+"""
+
+let t1 = (1, 2, 3)
+let t2 = (11, 32, 83)
+let s = @[t1, t2]
+
+for (a, b, c) in s:
+  echo a, b, c
+
+for i, (a, b, c) in s:
+  echo i
+  echo a, b, c
+
+var x = @[(1,2,3), (4,5,6)]
+
+for (a, b, c) in x.mitems:
+  a = 88
+  b = 99
+  c = 11
+echo x
+
+for i, (a, b, c) in x.mpairs:
+  a = 7
+  b = 6
+  c = -28
+echo x
+
+proc test[n]() =
+  for (a,b) in @[(1,2)]:
+    echo a,b
+test[string]()
+
+iterator tuples: (int, (int, int)) = yield (1,(10, 100))
+
+template t11164 =
+  for i, (a, b) in tuples():
+    echo i, a , b
+
+t11164()
diff --git a/tests/tuples/tinferred_generic_const.nim b/tests/tuples/tinferred_generic_const.nim
new file mode 100644
index 000000000..5ab730c38
--- /dev/null
+++ b/tests/tuples/tinferred_generic_const.nim
@@ -0,0 +1,14 @@
+discard """
+  action: run
+"""
+block:
+  proc something(a: string or int or float) =
+    const (c, d) = (default a.type, default a.type)
+
+block:
+  proc something(a: string or int) =
+    const c = default a.type
+
+block:
+  proc something(a: string or int) =
+    const (c, d, e) = (default a.type, default a.type, default a.type)
diff --git a/tests/tuples/tnimsconstunpack.nim b/tests/tuples/tnimsconstunpack.nim
new file mode 100644
index 000000000..7860fc0a4
--- /dev/null
+++ b/tests/tuples/tnimsconstunpack.nim
@@ -0,0 +1,8 @@
+discard """
+  action: compile
+  cmd: "nim e $file"
+"""
+
+import mnimsconstunpack
+
+doAssert b == "b"
diff --git a/tests/tuples/ttuples_issues.nim b/tests/tuples/ttuples_issues.nim
new file mode 100644
index 000000000..70defdfce
--- /dev/null
+++ b/tests/tuples/ttuples_issues.nim
@@ -0,0 +1,133 @@
+discard """
+  targets: "c cpp js"
+"""
+
+# targets include `cpp` because in the past, there were several cpp-specific bugs with tuples.
+
+import std/tables
+
+template main() =
+  block: # bug #4479
+    type
+      MyTuple = tuple
+        num: int
+        strings: seq[string]
+        ints: seq[int]
+
+    var foo = MyTuple((
+      num: 7,
+      strings: @[],
+      ints: @[],
+    ))
+
+    var bar = MyTuple (
+      num: 7,
+      strings: @[],
+      ints: @[],
+    )
+
+    var fooUnnamed = MyTuple((7, @[], @[]))
+    var n = 7
+    var fooSym = MyTuple((num: n, strings: @[], ints: @[]))
+
+  block: # bug #1910
+    var p = newOrderedTable[tuple[a:int], int]()
+    var q = newOrderedTable[tuple[x:int], int]()
+    for key in p.keys:
+      echo key.a
+    for key in q.keys:
+      echo key.x
+
+  block: # bug #2121
+    type
+      Item[K,V] = tuple
+        key: K
+        value: V
+
+    var q = newseq[Item[int,int]](1)
+    let (x,y) = q[0]
+
+  block: # bug #2369
+    type HashedElem[T] = tuple[num: int, storedVal: ref T]
+
+    proc append[T](tab: var seq[HashedElem[T]], n: int, val: ref T) =
+        #tab.add((num: n, storedVal: val))
+        var he: HashedElem[T] = (num: n, storedVal: val)
+        #tab.add(he)
+
+    var g: seq[HashedElem[int]] = @[]
+
+    proc foo() =
+        var x: ref int
+        new(x)
+        x[] = 77
+        g.append(44, x)
+
+  block: # bug #1986
+    proc test(): int64 =
+      return 0xdeadbeef.int64
+
+    const items = [
+      (var1: test(), var2: 100'u32),
+      (var1: test(), var2: 192'u32)
+    ]
+
+  block: # bug #14911
+    doAssert $(a: 1) == "(a: 1)" # works
+    doAssert $(`a`: 1) == "(a: 1)"  # works
+    doAssert $(`a`: 1, `b`: 2) == "(a: 1, b: 2)" # was: Error: named expression expected
+
+  block: # bug #16822
+    var scores: seq[(set[char], int)] = @{{'/'} : 10}
+
+    var x1: set[char]
+    for item in items(scores):
+      x1 = item[0]
+
+    doAssert x1 == {'/'}
+
+    var x2: set[char]
+    for (chars, value) in items(scores):
+      x2 = chars
+
+    doAssert x2 == {'/'}
+
+  block: # bug #14574
+    proc fn(): auto =
+      let a = @[("foo", (12, 13))]
+      for (k,v) in a:
+        return (k,v)
+    doAssert fn() == ("foo", (12, 13))
+
+  block: # bug #14574
+    iterator fn[T](a:T): lent T = yield a
+    let a = (10, (11,))
+    proc bar(): auto =
+      for (x,y) in fn(a):
+        return (x,y)
+    doAssert bar() == (10, (11,))
+
+  block: # bug #16331
+    type T1 = tuple[a, b: int]
+
+    proc p(b: bool): T1 =
+      var x: T1 = (10, 20)
+      x = if b: (x.b, x.a) else: (-x.b, -x.a)
+      x
+
+    doAssert p(false) == (-20, -10)
+    doAssert p(true) == (20, 10)
+
+
+proc mainProc() =
+  # other tests should be in `main`
+  block:
+    type A = tuple[x: int, y: int]
+    doAssert (x: 1, y: 2).A == A (x: 1, y: 2) # MCS => can't use a template
+
+static:
+  main()
+  mainProc()
+
+main()
+mainProc()
diff --git a/tests/tuples/ttuples_various.nim b/tests/tuples/ttuples_various.nim
new file mode 100644
index 000000000..e392731d2
--- /dev/null
+++ b/tests/tuples/ttuples_various.nim
@@ -0,0 +1,211 @@
+discard """
+output: '''
+it's nil
+@[1, 2, 3]
+'''
+"""
+
+import macros
+
+
+block anontuples:
+  proc `^` (a, b: int): int =
+    result = 1
+    for i in 1..b: result = result * a
+
+  var m = (0, 5)
+  var n = (56, 3)
+
+  m = (n[0] + m[1], m[1] ^ n[1])
+
+  doAssert m == (61, 125)
+
+  # also test we can produce unary anon tuples in a macro:
+  macro mm(): untyped =
+    result = newTree(nnkTupleConstr, newLit(13))
+
+  proc nowTuple(): (int,) =
+    result = (0,)
+
+  doAssert nowTuple() == (Field0: 0)
+  doAssert mm() == (Field0: 13)
+
+
+
+block unpack_asgn:
+  proc foobar(): (int, int) = (2, 4)
+
+  # test within a proc:
+  proc pp(x: var int) =
+    var y: int
+    (y, x) = foobar()
+
+  template pt(x) =
+    var y: int
+    (x, y) = foobar()
+
+  # test within a generic:
+  proc pg[T](x, y: var T) =
+    pt(x)
+
+  # test as a top level statement:
+  var x, y, a, b: int
+  # test for regression:
+  (x, y) = (1, 2)
+  (x, y) = fooBar()
+
+  doAssert x == 2
+  doAssert y == 4
+
+  pp(a)
+  doAssert a == 4
+
+  pg(a, b)
+  doAssert a == 2
+  doAssert b == 0
+
+
+
+block unpack_const:
+  const (a, ) = (1, )
+  doAssert a == 1
+
+  const (b, c) = (2, 3)
+  doAssert b == 2
+  doAssert c == 3
+
+  # bug #10098
+  const (x, y, z) = (4, 5, 6)
+  doAssert x == 4
+  doAssert y == 5
+  doAssert z == 6
+
+
+# bug #10724
+block unpack_const_named:
+  const (a, ) = (x: 1, )
+  doAssert a == 1
+
+  const (b, c) = (x: 2, y: 3)
+  doAssert b == 2
+  doAssert c == 3
+
+  const (d, e, f) = (x: 4, y: 5, z: 6)
+  doAssert d == 4
+  doAssert e == 5
+  doAssert f == 6
+
+block const_named:
+  const x = block:
+    (a: 1, b: 2, c: 3)
+  doAssert x.a == 1
+  doAssert x.b == 2
+  doAssert x.c == 3
+
+
+block tuple_subscript:
+  proc`[]` (t: tuple, key: string): string =
+    for name, field in fieldPairs(t):
+      if name == key:
+        return $field
+    return ""
+
+  proc`[]` [A,B](t: tuple, key: string, op: (proc(x: A): B)): B =
+    for name, field in fieldPairs(t):
+      when field is A:
+        if name == key:
+          return op(field)
+
+  proc`[]=`[T](t: var tuple, key: string, val: T) =
+    for name, field in fieldPairs(t):
+      when field is T:
+        if name == key:
+          field = val
+
+  var tt = (a: 1, b: "str1")
+
+  # test built in operator
+  tt[0] = 5
+
+  doAssert tt[0] == 5
+  doAssert `[]`(tt, 0) == 5
+
+  # test overloaded operator
+  tt["b"] = "str2"
+  doAssert tt["b"] == "str2"
+  doAssert `[]`(tt, "b") == "str2"
+  doAssert tt["b", proc(s: string): int = s.len] == 4
+
+
+
+block tuple_with_seq:
+  template foo(s: string = "") =
+    if s.len == 0:
+      echo "it's nil"
+    else:
+      echo s
+  foo
+
+  # bug #2632
+  proc takeTup(x: tuple[s: string;x: seq[int]]) =
+    discard
+  takeTup(("foo", @[]))
+
+  #proc foobar(): () =
+  proc f(xs: seq[int]) =
+    discard
+
+  proc g(t: tuple[n:int, xs:seq[int]]) =
+    discard
+
+  when true:
+    f(@[]) # OK
+    g((1,@[1])) # OK
+    g((0,@[])) # NG
+
+  # bug #2630
+  type T = tuple[a: seq[int], b: int]
+  var t: T = (@[1,2,3], 7)
+
+  proc test(s: seq[int]): T =
+    echo s
+    (s, 7)
+  t = test(t.a)
+
+block: # bug #22049
+  type A = object
+    field: tuple[a, b, c: seq[int]]
+
+  func value(v: var A): var tuple[a, b, c: seq[int]] =
+    v.field
+  template get(v: A): tuple[a, b, c: seq[int]] = v.value
+
+  var v = A(field: (@[1], @[2], @[3]))
+  var (a, b, c) = v.get()
+
+  doAssert a == @[1]
+  doAssert b == @[2]
+  doAssert c == @[3]
+
+block: # bug #22054
+  type A = object
+    field: tuple[a: int]
+
+  func value(v: var A): var tuple[a: int] =
+    v.field
+  template get(v: A): tuple[a: int] = v.value
+
+  var v = A(field: (a: 1314))
+  doAssert get(v)[0] == 1314
+
+block: # tuple unpacking assignment with underscore
+  var
+    a = 1
+    b = 2
+  doAssert (a, b) == (1, 2)
+  (a, _) = (3, 4)
+  doAssert (a, b) == (3, 2)
+  (_, a) = (5, 6)
+  doAssert (a, b) == (6, 2)
+  (b, _) = (7, 8)
+  doAssert (a, b) == (6, 7)
diff --git a/tests/tuples/ttypedesc_in_tuple_a.nim b/tests/tuples/ttypedesc_in_tuple_a.nim
new file mode 100644
index 000000000..7727bb35e
--- /dev/null
+++ b/tests/tuples/ttypedesc_in_tuple_a.nim
@@ -0,0 +1,5 @@
+discard """
+errormsg: "typedesc not allowed as tuple field."
+"""
+
+var bar = (a: int, b: 1)
diff --git a/tests/tuples/ttypedesc_in_tuple_b.nim b/tests/tuples/ttypedesc_in_tuple_b.nim
new file mode 100644
index 000000000..b393d877c
--- /dev/null
+++ b/tests/tuples/ttypedesc_in_tuple_b.nim
@@ -0,0 +1,5 @@
+discard """
+errormsg: "Mixing types and values in tuples is not allowed."
+"""
+
+var bar = (int, 1)
diff --git a/tests/tuples/tuple_with_nil.nim b/tests/tuples/tuple_with_nil.nim
new file mode 100644
index 000000000..9cad6eccd
--- /dev/null
+++ b/tests/tuples/tuple_with_nil.nim
@@ -0,0 +1,758 @@
+import macros
+import parseutils
+import unicode
+import math
+import pegs
+import streams
+
+type
+  FormatError = object of CatchableError ## Error in the format string.
+
+  Writer = concept W
+    ## Writer to output a character `c`.
+    write(W, 'c')
+
+  FmtAlign = enum ## Format alignment
+    faDefault  ## default for given format type
+    faLeft     ## left aligned
+    faRight    ## right aligned
+    faCenter   ## centered
+    faPadding  ## right aligned, fill characters after sign (numbers only)
+
+  FmtSign = enum ## Format sign
+    fsMinus    ## only unary minus, no reservered sign space for positive numbers
+    fsPlus     ## unary minus and unary plus
+    fsSpace    ## unary minus and reserved space for positive numbers
+
+  FmtType = enum ## Format type
+    ftDefault  ## default format for given parameter type
+    ftStr      ## string
+    ftChar     ## character
+    ftDec      ## decimal integer
+    ftBin      ## binary integer
+    ftOct      ## octal integer
+    ftHex      ## hexadecimal integer
+    ftFix      ## real number in fixed point notation
+    ftSci      ## real number in scientific notation
+    ftGen      ## real number in generic form (either fixed point or scientific)
+    ftPercent  ## real number multiplied by 100 and % added
+
+  Format = tuple ## Formatting information.
+    typ: FmtType     ## format type
+    precision: int    ## floating point precision
+    width: int        ## minimal width
+    fill: string      ## the fill character, UTF8
+    align: FmtAlign  ## alignment
+    sign: FmtSign    ## sign notation
+    baseprefix: bool  ## whether binary, octal, hex should be prefixed by 0b, 0x, 0o
+    upcase: bool      ## upper case letters in hex or exponential formats
+    comma: bool       ##
+    arysep: string    ## separator for array elements
+
+  PartKind = enum pkStr, pkFmt
+
+  Part = object
+    ## Information of a part of the target string.
+    case kind: PartKind ## type of the part
+    of pkStr:
+      str: string ## literal string
+    of pkFmt:
+      arg: int ## position argument
+      fmt: string ## format string
+      field: string ## field of argument to be accessed
+      index: int ## array index of argument to be accessed
+      nested: bool ## true if the argument contains nested formats
+
+const
+  DefaultPrec = 6 ## Default precision for floating point numbers.
+  DefaultFmt: Format = (ftDefault, -1, -1, "", faDefault, fsMinus, false, false, false, "")
+    ## Default format corresponding to the empty format string, i.e.
+    ##   `x.format("") == x.format(DefaultFmt)`.
+  round_nums = [0.5, 0.05, 0.005, 0.0005, 0.00005, 0.000005, 0.0000005, 0.00000005]
+    ## Rounding offset for floating point numbers up to precision 8.
+
+proc write(s: var string; c: char) =
+  s.add(c)
+
+proc has(c: Captures; i: range[0..pegs.MaxSubpatterns-1]): bool {.nosideeffect, inline.} =
+  ## Tests whether `c` contains a non-empty capture `i`.
+  let b = c.bounds(i)
+  result = b.first <= b.last
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: char): char {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str` cast
+  ## to `char`, otherwise return `def`.
+  result = if c.has(i): str[c.bounds(i).first] else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: string; begoff: int = 0): string {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str` as
+  ## string, otherwise return `def`.
+  let b = c.bounds(i)
+  result = if c.has(i): str.substr(b.first + begoff, b.last) else: def
+
+proc get(str: string; c: Captures; i: range[0..MaxSubpatterns-1]; def: int; begoff: int = 0): int {.nosideeffect, inline.} =
+  ## If capture `i` is non-empty return that portion of `str`
+  ## converted to int, otherwise return `def`.
+  if c.has(i):
+    discard str.parseInt(result, c.bounds(i).first + begoff)
+  else:
+    result = def
+
+proc parse(fmt: string): Format {.nosideeffect.} =
+  # Converts the format string `fmt` into a `Format` structure.
+  let p =
+    sequence(capture(?sequence(anyRune(), &charSet({'<', '>', '=', '^'}))),
+             capture(?charSet({'<', '>', '=', '^'})),
+             capture(?charSet({'-', '+', ' '})),
+             capture(?charSet({'#'})),
+             capture(?(+digits())),
+             capture(?charSet({','})),
+             capture(?sequence(charSet({'.'}), +digits())),
+             capture(?charSet({'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'n', 'o', 's', 'x', 'X', '%'})),
+             capture(?sequence(charSet({'a'}), *pegs.any())))
+  # let p=peg"{(_&[<>=^])?}{[<>=^]?}{[-+ ]?}{[#]?}{[0-9]+?}{[,]?}{([.][0-9]+)?}{[bcdeEfFgGnosxX%]?}{(a.*)?}"
+
+  var caps: Captures
+  if fmt.rawmatch(p, 0, caps) < 0:
+    raise newException(FormatError, "Invalid format string")
+
+  result.fill = fmt.get(caps, 0, "")
+
+  case fmt.get(caps, 1, 0.char)
+  of '<': result.align = faLeft
+  of '>': result.align = faRight
+  of '^': result.align = faCenter
+  of '=': result.align = faPadding
+  else: result.align = faDefault
+
+  case fmt.get(caps, 2, '-')
+  of '-': result.sign = fsMinus
+  of '+': result.sign = fsPlus
+  of ' ': result.sign = fsSpace
+  else: result.sign = fsMinus
+
+  result.baseprefix = caps.has(3)
+
+  result.width = fmt.get(caps, 4, -1)
+
+  if caps.has(4) and fmt[caps.bounds(4).first] == '0':
+    if result.fill != "":
+      raise newException(FormatError, "Leading 0 in with not allowed with explicit fill character")
+    if result.align != faDefault:
+      raise newException(FormatError, "Leading 0 in with not allowed with explicit alignment")
+    result.fill = "0"
+    result.align = faPadding
+
+  result.comma = caps.has(5)
+
+  result.precision = fmt.get(caps, 6, -1, 1)
+
+  case fmt.get(caps, 7, 0.char)
+  of 's': result.typ = ftStr
+  of 'c': result.typ = ftChar
+  of 'd', 'n': result.typ = ftDec
+  of 'b': result.typ = ftBin
+  of 'o': result.typ = ftOct
+  of 'x': result.typ = ftHex
+  of 'X': result.typ = ftHex; result.upcase = true
+  of 'f', 'F': result.typ = ftFix
+  of 'e': result.typ = ftSci
+  of 'E': result.typ = ftSci; result.upcase = true
+  of 'g': result.typ = ftGen
+  of 'G': result.typ = ftGen; result.upcase = true
+  of '%': result.typ = ftPercent
+  else: result.typ = ftDefault
+
+  result.arysep = fmt.get(caps, 8, "", 1)
+
+proc getalign(fmt: Format; defalign: FmtAlign; slen: int) : tuple[left, right:int] {.nosideeffect.} =
+  ## Returns the number of left and right padding characters for a
+  ## given format alignment and width of the object to be printed.
+  ##
+  ## `fmt`
+  ##    the format data
+  ## `default`
+  ##    if `fmt.align == faDefault`, then this alignment is used
+  ## `slen`
+  ##    the width of the object to be printed.
+  ##
+  ## The returned values `(left, right)` will be as minimal as possible
+  ## so that `left + slen + right >= fmt.width`.
+  result.left = 0
+  result.right = 0
+  if (fmt.width >= 0) and (slen < fmt.width):
+    let alg = if fmt.align == faDefault: defalign else: fmt.align
+    case alg:
+    of faLeft: result.right = fmt.width - slen
+    of faRight, faPadding: result.left = fmt.width - slen
+    of faCenter:
+      result.left = (fmt.width - slen) div 2
+      result.right = fmt.width - slen - result.left
+    else: discard
+
+proc writefill(o: var Writer; fmt: Format; n: int; signum: int = 0) =
+  ## Write characters for filling. This function also writes the sign
+  ## of a numeric format and handles the padding alignment
+  ## accordingly.
+  ##
+  ## `o`
+  ##   output object
+  ## `add`
+  ##   output function
+  ## `fmt`
+  ##   format to be used (important for padding alignment)
+  ## `n`
+  ##   the number of filling characters to be written
+  ## `signum`
+  ##   the sign of the number to be written, < 0 negative, > 0 positive, = 0 zero
+  if fmt.align == faPadding and signum != 0:
+    if signum < 0: write(o, '-')
+    elif fmt.sign == fsPlus: write(o, '+')
+    elif fmt.sign == fsSpace: write(o, ' ')
+
+  if fmt.fill.len == 0:
+    for i in 1..n: write(o, ' ')
+  else:
+    for i in 1..n:
+      for c in fmt.fill:
+        write(o, c)
+
+  if fmt.align != faPadding and signum != 0:
+    if signum < 0: write(o, '-')
+    elif fmt.sign == fsPlus: write(o, '+')
+    elif fmt.sign == fsSpace: write(o, ' ')
+
+proc writeformat(o: var Writer; s: string; fmt: Format) =
+  ## Write string `s` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if fmt.typ notin {ftDefault, ftStr}:
+    raise newException(FormatError, "String variable must have 's' format type")
+
+  # compute alignment
+  let len = if fmt.precision < 0: runelen(s) else: min(runelen(s), fmt.precision)
+  var alg = getalign(fmt, faLeft, len)
+  writefill(o, fmt, alg.left)
+  var pos = 0
+  for i in 0..len-1:
+    let rlen = runeLenAt(s, pos)
+    for j in pos..pos+rlen-1: write(o, s[j])
+    pos += rlen
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: char; fmt: Format) =
+  ## Write character `c` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if not (fmt.typ in {ftChar, ftDefault}):
+    raise newException(FormatError, "Character variable must have 'c' format type")
+
+  # compute alignment
+  var alg = getalign(fmt, faLeft, 1)
+  writefill(o, fmt, alg.left)
+  write(o, c)
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; c: Rune; fmt: Format) =
+  ## Write rune `c` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if not (fmt.typ in {ftChar, ftDefault}):
+    raise newException(FormatError, "Character variable must have 'c' format type")
+
+  # compute alignment
+  var alg = getalign(fmt, faLeft, 1)
+  writefill(o, fmt, alg.left)
+  let s = c.toUTF8
+  for c in s: write(o, c)
+  writefill(o, fmt, alg.right)
+
+proc abs(x: SomeUnsignedInt): SomeUnsignedInt {.inline.} = x
+  ## Return the absolute value of the unsigned int `x`.
+
+proc writeformat(o: var Writer; i: SomeInteger; fmt: Format) =
+  ## Write integer `i` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  var fmt = fmt
+  if fmt.typ == ftDefault:
+    fmt.typ = ftDec
+  if not (fmt.typ in {ftBin, ftOct, ftHex, ftDec}):
+    raise newException(FormatError, "Integer variable must of one of the following types: b,o,x,X,d,n")
+
+  var base: type(i)
+  var len = 0
+  case fmt.typ:
+  of ftDec:
+    base = 10
+  of ftBin:
+    base = 2
+    if fmt.baseprefix: len += 2
+  of ftOct:
+    base = 8
+    if fmt.baseprefix: len += 2
+  of ftHex:
+    base = 16
+    if fmt.baseprefix: len += 2
+  else: assert(false)
+
+  if fmt.sign != fsMinus or i < 0: len.inc
+
+  var x: type(i) = abs(i)
+  var irev: type(i) = 0
+  var ilen = 0
+  while x > 0.SomeInteger:
+    len.inc
+    ilen.inc
+    irev = irev * base + x mod base
+    x = x div base
+  if ilen == 0:
+    ilen.inc
+    len.inc
+
+  var alg = getalign(fmt, faRight, len)
+  writefill(o, fmt, alg.left, if i >= 0.SomeInteger: 1 else: -1)
+  if fmt.baseprefix:
+    case fmt.typ
+    of ftBin:
+      write(o, '0')
+      write(o, 'b')
+    of ftOct:
+      write(o, '0')
+      write(o, 'o')
+    of ftHex:
+      write(o, '0')
+      write(o, 'x')
+    else:
+      raise newException(FormatError, "# only allowed with b, o, x or X")
+  while ilen > 0:
+    ilen.dec
+    let c = irev mod base
+    irev = irev div base
+    if c < 10:
+      write(o, ('0'.int + c.int).char)
+    elif fmt.upcase:
+      write(o, ('A'.int + c.int - 10).char)
+    else:
+      write(o, ('a'.int + c.int - 10).char)
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; p: pointer; fmt: Format) =
+  ## Write pointer `i` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  ##
+  ## Pointers are cast to unsigned int and formatted as hexadecimal
+  ## with prefix unless specified otherwise.
+  var f = fmt
+  if f.typ == 0.char:
+    f.typ = 'x'
+    f.baseprefix = true
+  writeformat(o, add, cast[uint](p), f)
+
+proc writeformat(o: var Writer; x: SomeFloat; fmt: Format) =
+  ## Write real number `x` according to format `fmt` using output
+  ## object `o` and output function `add`.
+  var fmt = fmt
+  # handle default format
+  if fmt.typ == ftDefault:
+    fmt.typ = ftGen
+    if fmt.precision < 0: fmt.precision = DefaultPrec
+  if not (fmt.typ in {ftFix, ftSci, ftGen, ftPercent}):
+    raise newException(FormatError, "Integer variable must of one of the following types: f,F,e,E,g,G,%")
+
+  let positive = x >= 0 and classify(x) != fcNegZero
+  var len = 0
+
+  if fmt.sign != fsMinus or not positive: len.inc
+
+  var prec = if fmt.precision < 0: DefaultPrec else: fmt.precision
+  var y = abs(x)
+  var exp = 0
+  var numstr, frstr: array[0..31, char]
+  var numlen, frbeg, frlen = 0
+
+  if fmt.typ == ftPercent: y *= 100
+
+  case classify(x):
+  of fcNan:
+    numstr[0..2] = ['n', 'a', 'n']
+    numlen = 3
+  of fcInf, fcNegInf:
+    numstr[0..2] = ['f', 'n', 'i']
+    numlen = 3
+  of fcZero, fcNegZero:
+    numstr[0] = '0'
+    numlen = 1
+  else: # a usual fractional number
+    if not (fmt.typ in {ftFix, ftPercent}): # not fixed point
+      exp = int(floor(log10(y)))
+      if fmt.typ == ftGen:
+        if prec == 0: prec = 1
+        if -4 <= exp and exp < prec:
+          prec = prec-1-exp
+          exp = 0
+        else:
+          prec = prec - 1
+          len += 4 # exponent
+      else:
+        len += 4 # exponent
+      # shift y so that 1 <= abs(y) < 2
+      if exp > 0: y /= pow(10.SomeFloat, abs(exp).SomeFloat)
+      elif exp < 0: y *= pow(10.SomeFloat, abs(exp).SomeFloat)
+    elif fmt.typ == ftPercent:
+      len += 1 # percent sign
+
+    # handle rounding by adding +0.5 * LSB
+    if prec < len(round_nums): y += round_nums[prec]
+
+    # split into integer and fractional part
+    var mult = 1'i64
+    for i in 1..prec: mult *= 10
+    var num = y.int64
+    var fr = ((y - num.SomeFloat) * mult.SomeFloat).int64
+    # build integer part string
+    while num != 0:
+      numstr[numlen] = ('0'.int + (num mod 10)).char
+      numlen.inc
+      num = num div 10
+    if numlen == 0:
+      numstr[0] = '0'
+      numlen.inc
+    # build fractional part string
+    while fr != 0:
+      frstr[frlen] = ('0'.int + (fr mod 10)).char
+      frlen.inc
+      fr = fr div 10
+    while frlen < prec:
+      frstr[frlen] = '0'
+      frlen.inc
+    # possible remove trailing 0
+    if fmt.typ == ftGen:
+      while frbeg < frlen and frstr[frbeg] == '0': frbeg.inc
+  # update length of string
+  len += numlen;
+  if frbeg < frlen:
+    len += 1 + frlen - frbeg # decimal point and fractional string
+
+  let alg = getalign(fmt, faRight, len)
+  writefill(o, fmt, alg.left, if positive: 1 else: -1)
+  for i in (numlen-1).countdown(0): write(o, numstr[i])
+  if frbeg < frlen:
+    write(o, '.')
+    for i in (frlen-1).countdown(frbeg): write(o, frstr[i])
+  if fmt.typ == ftSci or (fmt.typ == ftGen and exp != 0):
+    write(o, if fmt.upcase: 'E' else: 'e')
+    if exp >= 0:
+      write(o, '+')
+    else:
+      write(o, '-')
+      exp = -exp
+    if exp < 10:
+      write(o, '0')
+      write(o, ('0'.int + exp).char)
+    else:
+      var i=0
+      while exp > 0:
+        numstr[i] = ('0'.int + exp mod 10).char
+        i+=1
+        exp = exp div 10
+      while i>0:
+        i-=1
+        write(o, numstr[i])
+  if fmt.typ == ftPercent: write(o, '%')
+  writefill(o, fmt, alg.right)
+
+proc writeformat(o: var Writer; b: bool; fmt: Format) =
+  ## Write boolean value `b` according to format `fmt` using output
+  ## object `o`. A boolean may be formatted numerically or as string.
+  ## In the former case true is written as 1 and false as 0, in the
+  ## latter the strings "true" and "false" are shown, respectively.
+  ## The default is string format.
+  if fmt.typ in {ftStr, ftDefault}:
+    writeformat(o,
+                if b: "true"
+                else: "false",
+                fmt)
+  elif fmt.typ in {ftBin, ftOct, ftHex, ftDec}:
+    writeformat(o,
+                if b: 1
+                else: 0,
+                fmt)
+  else:
+    raise newException(FormatError, "Boolean values must of one of the following types: s,b,o,x,X,d,n")
+
+proc writeformat(o: var Writer; ary: openArray[system.any]; fmt: Format) =
+  ## Write array `ary` according to format `fmt` using output object
+  ## `o` and output function `add`.
+  if ary.len == 0: return
+
+  var sep: string
+  var nxtfmt = fmt
+  if fmt.arysep == nil:
+    sep = "\t"
+  elif fmt.arysep.len == 0:
+    sep = ""
+  else:
+    let sepch = fmt.arysep[0]
+    let nxt = 1 + skipUntil(fmt.arysep, sepch, 1)
+    if nxt >= 1:
+      nxtfmt.arysep = fmt.arysep.substr(nxt)
+      sep = fmt.arysep.substr(1, nxt-1)
+    else:
+      nxtfmt.arysep = ""
+      sep = fmt.arysep.substr(1)
+  writeformat(o, ary[0], nxtfmt)
+  for i in 1..ary.len-1:
+    for c in sep: write(o, c)
+    writeformat(o, ary[i], nxtfmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` formatted with `fmt` to `o`.
+  writeformat(o, x, fmt)
+
+proc addformat[T](o: var Writer; x: T; fmt: string) {.inline.} =
+  ## The same as `addformat(o, x, parse(fmt))`.
+  addformat(o, x, fmt.parse)
+
+proc addformat(s: var string; x: string) {.inline.} =
+  ## Write `x` to `s`. This is a fast specialized version for
+  ## appending unformatted strings.
+  add(s, x)
+
+proc addformat(f: File; x: string) {.inline.} =
+  ## Write `x` to `f`. This is a fast specialized version for
+  ## writing unformatted strings to a file.
+  write(f, x)
+
+proc addformat[T](f: File; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` to file `f` using format `fmt`.
+  var g = f
+  writeformat(g, x, fmt)
+
+proc addformat[T](f: File; x: T; fmt: string) {.inline.} =
+  ## Write `x` to file `f` using format string `fmt`. This is the same
+  ## as `addformat(f, x, parse(fmt))`
+  addformat(f, x, parse(fmt))
+
+proc addformat(s: Stream; x: string) {.inline.} =
+  ## Write `x` to `s`. This is a fast specialized version for
+  ## writing unformatted strings to a stream.
+  write(s, x)
+
+proc addformat[T](s: Stream; x: T; fmt: Format = DefaultFmt) {.inline.} =
+  ## Write `x` to stream `s` using format `fmt`.
+  var g = s
+  writeformat(g, x, fmt)
+
+proc addformat[T](s: Stream; x: T; fmt: string) {.inline.} =
+  ## Write `x` to stream `s` using format string `fmt`. This is the same
+  ## as `addformat(s, x, parse(fmt))`
+  addformat(s, x, parse(fmt))
+
+proc format[T](x: T; fmt: Format): string =
+  ## Return `x` formatted as a string according to format `fmt`.
+  result = ""
+  addformat(result, x, fmt)
+
+proc format[T](x: T; fmt: string): string =
+  ## Return `x` formatted as a string according to format string `fmt`.
+  result = format(x, fmt.parse)
+
+proc format[T](x: T): string {.inline.} =
+  ## Return `x` formatted as a string according to the default format.
+  ## The default format corresponds to an empty format string.
+  var fmt {.global.} : Format = DefaultFmt
+  result = format(x, fmt)
+
+proc unquoted(s: string): string {.compileTime.} =
+  ## Return `s` {{ and }} by single { and }, respectively.
+  result = ""
+  var pos = 0
+  while pos < s.len:
+    let nxt = pos + skipUntil(s, {'{', '}'})
+    result.add(s.substr(pos, nxt))
+    pos = nxt + 2
+
+proc splitfmt(s: string): seq[Part] {.compiletime, nosideeffect.} =
+  ## Split format string `s` into a sequence of "parts".
+  ##
+
+  ## Each part is either a literal string or a format specification. A
+  ## format specification is a substring of the form
+  ## "{[arg][:format]}" where `arg` is either empty or a number
+  ## referring to the arg-th argument and an additional field or array
+  ## index. The format string is a string accepted by `parse`.
+  let subpeg = sequence(capture(digits()),
+                          capture(?sequence(charSet({'.'}), *pegs.identStartChars(), *identChars())),
+                          capture(?sequence(charSet({'['}), +digits(), charSet({']'}))),
+                          capture(?sequence(charSet({':'}), *pegs.any())))
+  result = @[]
+  var pos = 0
+  while true:
+    let oppos = pos + skipUntil(s, {'{', '}'}, pos)
+    # reached the end
+    if oppos >= s.len:
+      if pos < s.len:
+        result.add(Part(kind: pkStr, str: s.substr(pos).unquoted))
+      return
+    # skip double
+    if oppos + 1 < s.len and s[oppos] == s[oppos+1]:
+      result.add(Part(kind: pkStr, str: s.substr(pos, oppos)))
+      pos = oppos + 2
+      continue
+    if s[oppos] == '}':
+      error("Single '}' encountered in format string")
+    if oppos > pos:
+      result.add(Part(kind: pkStr, str: s.substr(pos, oppos-1).unquoted))
+    # find matching closing }
+    var lvl = 1
+    var nested = false
+    pos = oppos
+    while lvl > 0:
+      pos.inc
+      pos = pos + skipUntil(s, {'{', '}'}, pos)
+      if pos >= s.len:
+        error("Single '{' encountered in format string")
+      if s[pos] == '{':
+        lvl.inc
+        if lvl == 2:
+          nested = true
+        if lvl > 2:
+          error("Too many nested format levels")
+      else:
+        lvl.dec
+    let clpos = pos
+    var fmtpart = Part(kind: pkFmt, arg: -1, fmt: s.substr(oppos+1, clpos-1), field: "", index: int.high, nested: nested)
+    if fmtpart.fmt.len > 0:
+      var m: array[0..3, string]
+      if not fmtpart.fmt.match(subpeg, m):
+        error("invalid format string")
+
+      if m[1].len > 0:
+        fmtpart.field = m[1].substr(1)
+      if m[2].len > 0:
+        discard parseInt(m[2].substr(1, m[2].len-2), fmtpart.index)
+
+      if m[0].len > 0: discard parseInt(m[0], fmtpart.arg)
+      if m[3].len == 0:
+        fmtpart.fmt = ""
+      elif m[3][0] == ':':
+        fmtpart.fmt = m[3].substr(1)
+      else:
+        fmtpart.fmt = m[3]
+    result.add(fmtpart)
+    pos = clpos + 1
+
+proc literal(s: string): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of string `s`. This handles the case if
+  ## `s` is nil.
+  result = newLit(s)
+
+proc literal(b: bool): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of boolean `b`. This is either `true`
+  ## or `false` symbol.
+  result = if b: "true".ident else: "false".ident
+
+proc literal[T](x: T): NimNode {.compiletime, nosideeffect.} =
+  ## Return the nim literal of value `x`.
+  when type(x) is enum:
+    result = ($x).ident
+  else:
+    result = newLit(x)
+
+proc generatefmt(fmtstr: string;
+                 args: var openArray[tuple[arg:NimNode, cnt:int]];
+                 arg: var int;): seq[tuple[val, fmt:NimNode]] {.compiletime.} =
+  ## fmtstr
+  ##   the format string
+  ## args
+  ##   array of expressions for the arguments
+  ## arg
+  ##   the number of the next argument for automatic parsing
+  ##
+  ## If arg is < 0 then the functions assumes that explicit numbering
+  ## must be used, otherwise automatic numbering is used starting at
+  ## `arg`. The value of arg is updated according to the number of
+  ## arguments being used. If arg == 0 then automatic and manual
+  ## numbering is not decided (because no explicit manual numbering is
+  ## fixed und no automatically numbered argument has been used so
+  ## far).
+  ##
+  ## The function returns a list of pairs `(val, fmt)` where `val` is
+  ## an expression to be formatted and `fmt` is the format string (or
+  ## Format). Therefore, the resulting string can be generated by
+  ## concatenating expressions `val.format(fmt)`. If `fmt` is `nil`
+  ## then `val` is a (literal) string expression.
+  try:
+    result = @[]
+    for part in splitfmt(fmtstr):
+      case part.kind
+      of pkStr: result.add((newLit(part.str), nil))
+      of pkFmt:
+        # first compute the argument expression
+        # start with the correct index
+        var argexpr : NimNode
+        if part.arg >= 0:
+          if arg > 0:
+            error("Cannot switch from automatic field numbering to manual field specification")
+          if part.arg >= args.len:
+            error("Invalid explicit argument index: " & $part.arg)
+          argexpr = args[part.arg].arg
+          args[part.arg].cnt = args[part.arg].cnt + 1
+          arg = -1
+        else:
+          if arg < 0:
+            error("Cannot switch from manual field specification to automatic field numbering")
+          if arg >= args.len:
+            error("Too few arguments for format string")
+          argexpr = args[arg].arg
+          args[arg].cnt = args[arg].cnt + 1
+          arg.inc
+        # possible field access
+        if part.field.len > 0:
+          argexpr = newDotExpr(argexpr, part.field.ident)
+        # possible array access
+        if part.index < int.high:
+          argexpr = newNimNode(nnkBracketExpr).add(argexpr, newLit(part.index))
+        # now the expression for the format data
+        var fmtexpr: NimNode
+        if part.nested:
+          # nested format string. Compute the format string by
+          # concatenating the parts of the substring.
+          for e in generatefmt(part.fmt, args, arg):
+            var newexpr = if part.fmt.len == 0: e.val else: newCall(bindsym"format", e.val, e.fmt)
+            if fmtexpr != nil and fmtexpr.kind != nnkNilLit:
+              fmtexpr = infix(fmtexpr, "&", newexpr)
+            else:
+              fmtexpr = newexpr
+        else:
+          # literal format string, precompute the format data
+          fmtexpr = newNimNode(nnkPar)
+          for field, val in part.fmt.parse.fieldPairs:
+            fmtexpr.add(newNimNode(nnkExprColonExpr).add(field.ident, literal(val)))
+        # add argument
+        result.add((argexpr, fmtexpr))
+  finally:
+    discard
+
+proc addfmtfmt(fmtstr: string; args: NimNode; retvar: NimNode): NimNode {.compileTime.} =
+  var argexprs = newseq[tuple[arg:NimNode; cnt:int]](args.len)
+  result = newNimNode(nnkStmtListExpr)
+  # generate let bindings for arguments
+  for i in 0..args.len-1:
+    let argsym = gensym(nskLet, "arg" & $i)
+    result.add(newLetStmt(argsym, args[i]))
+    argexprs[i].arg = argsym
+  # add result values
+  var arg = 0
+  for e in generatefmt(fmtstr, argexprs, arg):
+    if e.fmt == nil or e.fmt.kind == nnkNilLit:
+      result.add(newCall(bindsym"addformat", retvar, e.val))
+    else:
+      result.add(newCall(bindsym"addformat", retvar, e.val, e.fmt))
+  for i, arg in argexprs:
+    if arg.cnt == 0:
+      warning("Argument " & $(i+1) & " `" & args[i].repr & "` is not used in format string")
+
+macro addfmt(s: var string, fmtstr: string{lit}, args: varargs[typed]): untyped =
+  ## The same as `s.add(fmtstr.fmt(args...))` but faster.
+  result = addfmtfmt($fmtstr, args, s)
+
+var s: string = ""
+s.addfmt("a:{}", 42)
diff --git a/tests/tuples/twrong_generic_caching.nim b/tests/tuples/twrong_generic_caching.nim
new file mode 100644
index 000000000..32ef344d2
--- /dev/null
+++ b/tests/tuples/twrong_generic_caching.nim
@@ -0,0 +1,4 @@
+
+import parsecfg
+
+import asynchttpserver
diff --git a/tests/tuples/twrongtupleaccess.nim b/tests/tuples/twrongtupleaccess.nim
new file mode 100644
index 000000000..591716a2e
--- /dev/null
+++ b/tests/tuples/twrongtupleaccess.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "attempting to call undeclared routine: \'setBLAH\'"
+  file: "twrongtupleaccess.nim"
+  line: 9
+"""
+# Bugfix
+
+var v = (5.0, 10.0)
+v.setBLAH(10)
diff --git a/tests/tvardecl.nim b/tests/tvardecl.nim
deleted file mode 100755
index 496601e3a..000000000
--- a/tests/tvardecl.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-# Test the new variable declaration syntax

-

-var

-  x = 0

-  s = "Hallo"

-  a, b: int = 4

-

-write(stdout, a)

-write(stdout, b) #OUT 44

diff --git a/tests/tvarious.nim b/tests/tvarious.nim
deleted file mode 100755
index 52dd46184..000000000
--- a/tests/tvarious.nim
+++ /dev/null
@@ -1,43 +0,0 @@
-# Test various aspects

-

-import

-  mvarious

-

-type

-  PA = ref TA

-  PB = ref TB

-

-  TB = object

-    a: PA

-

-  TA = object

-    b: TB

-    x: int

-

-proc getPA(): PA =

-  var

-    b: bool

-  b = not false

-  return nil

-

-var

-  global: int

-

-var

-  s: string

-  i: int

-  r: TA

-

-r.b.a.x = 0

-global = global + 1

-exportme()

-write(stdout, "Hallo wie heißt du? ")

-write(stdout, getPA().x)

-s = readLine(stdin)

-i = 0

-while i < s.len:

-  if s[i] == 'c': write(stdout, "'c' in deinem Namen gefunden\n")

-  i = i + 1

-

-write(stdout, "Du heißt " & s)

-

diff --git a/tests/twalker.nim b/tests/twalker.nim
deleted file mode 100755
index ba89ee7c6..000000000
--- a/tests/twalker.nim
+++ /dev/null
@@ -1,13 +0,0 @@
-# iterate over all files with a given filter:

-

-import

-  os, times

-

-proc main(filter: string) =

-  for filename in walkFiles(filter):

-    writeln(stdout, filename)

-

-  for key, val in iterOverEnvironment():

-    writeln(stdout, key & '=' & val)

-

-main("*.nim")

diff --git a/tests/typerel/t2plus.nim b/tests/typerel/t2plus.nim
new file mode 100644
index 000000000..4b18b6221
--- /dev/null
+++ b/tests/typerel/t2plus.nim
@@ -0,0 +1,22 @@
+discard """
+  output: "2.0"
+"""
+
+{.warning[TypelessParam]: off.}
+
+import sugar
+
+# bug #3329
+
+proc foldRight[T,U](lst: seq[T], v: U, f: (T, U) -> U): U =
+  result = v
+  for x in lst:
+    result = f(x, result)
+
+proc mean[T: SomeNumber](xs: seq[T]): T =
+  xs.foldRight(0.T, (xBAZ: auto, yBAZ: auto) => xBAZ + yBAZ) / T(xs.len)
+
+when true:
+  let x = mean(@[1.float, 2, 3])
+  echo x
+
diff --git a/tests/typerel/t4799.nim b/tests/typerel/t4799.nim
new file mode 100644
index 000000000..814ad361d
--- /dev/null
+++ b/tests/typerel/t4799.nim
@@ -0,0 +1,246 @@
+discard """
+  targets: "c cpp"
+  output: "OK"
+"""
+
+type
+  GRBase[T] = ref object of RootObj
+    val: T
+  GRC[T] = ref object of GRBase[T]
+  GRD[T] = ref object of GRBase[T]
+
+proc testGR[T](x: varargs[GRBase[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_1:
+  var rgv = GRBase[int](val: 3)
+  var rgc = GRC[int](val: 4)
+  var rgb = GRD[int](val: 2)
+  doAssert(testGR(rgb, rgc, rgv) == "243")
+  doAssert(testGR(rgc, rgv, rgb) == "432")
+  doAssert(testGR(rgv, rgb, rgc) == "324")
+  doAssert(testGR([rgb, rgc, rgv]) == "243")
+  doAssert(testGR([rgc, rgv, rgb]) == "432")
+  doAssert(testGR([rgv, rgb, rgc]) == "324")
+
+type
+  PRBase[T] = object of RootObj
+    val: T
+  PRC[T] = object of PRBase[T]
+  PRD[T] = object of PRBase[T]
+
+proc testPR[T](x: varargs[ptr PRBase[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_2:
+  var pgv = PRBase[int](val: 3)
+  var pgc = PRC[int](val: 4)
+  var pgb = PRD[int](val: 2)
+  doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243")
+  doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432")
+  doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324")
+  doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243")
+  doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432")
+  doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324")
+
+type
+  RBase = ref object of RootObj
+    val: int
+  RC = ref object of RBase
+  RD = ref object of RBase
+
+proc testR(x: varargs[RBase]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_3:
+  var rv = RBase(val: 3)
+  var rc = RC(val: 4)
+  var rb = RD(val: 2)
+  doAssert(testR(rb, rc, rv) == "243")
+  doAssert(testR(rc, rv, rb) == "432")
+  doAssert(testR(rv, rb, rc) == "324")
+  doAssert(testR([rb, rc, rv]) == "243")
+  doAssert(testR([rc, rv, rb]) == "432")
+  doAssert(testR([rv, rb, rc]) == "324")
+
+type
+  PBase = object of RootObj
+    val: int
+  PC = object of PBase
+  PD = object of PBase
+
+proc testP(x: varargs[ptr PBase]): string =
+  result = ""
+  for c in x:
+    result.add $c.val
+
+block test_t4799_4:
+  var pv = PBase(val: 3)
+  var pc = PC(val: 4)
+  var pb = PD(val: 2)
+  doAssert(testP(pb.addr, pc.addr, pv.addr) == "243")
+  doAssert(testP(pc.addr, pv.addr, pb.addr) == "432")
+  doAssert(testP(pv.addr, pb.addr, pc.addr) == "324")
+  doAssert(testP([pb.addr, pc.addr, pv.addr]) == "243")
+  doAssert(testP([pc.addr, pv.addr, pb.addr]) == "432")
+  doAssert(testP([pv.addr, pb.addr, pc.addr]) == "324")
+
+type
+  PSBase[T, V] = ref object of RootObj
+    val: T
+    color: V
+  PSRC[T] = ref object of PSBase[T, int]
+  PSRD[T] = ref object of PSBase[T, int]
+
+proc testPS[T, V](x: varargs[PSBase[T, V]]): string =
+  result = ""
+  for c in x:
+    result.add c.val
+    result.add $c.color
+
+block test_t4799_5:
+  var a = PSBase[string, int](val: "base", color: 1)
+  var b = PSRC[string](val: "rc", color: 2)
+  var c = PSRD[string](val: "rd", color: 3)
+
+  doAssert(testPS(a, b, c) == "base1rc2rd3")
+  doAssert(testPS(b, a, c) == "rc2base1rd3")
+  doAssert(testPS(c, b, a) == "rd3rc2base1")
+  doAssert(testPS([a, b, c]) == "base1rc2rd3")
+  doAssert(testPS([b, a, c]) == "rc2base1rd3")
+  doAssert(testPS([c, b, a]) == "rd3rc2base1")
+
+type
+  SBase[T, V] = ref object of RootObj
+    val: T
+    color: V
+  SRC = ref object of SBase[string, int]
+  SRD = ref object of SBase[string, int]
+
+proc testS[T, V](x: varargs[SBase[T, V]]): string =
+  result = ""
+  for c in x:
+    result.add c.val
+    result.add $c.color
+
+block test_t4799_6:
+  var a = SBase[string, int](val: "base", color: 1)
+  var b = SRC(val: "rc", color: 2)
+  var c = SRD(val: "rd", color: 3)
+
+  doAssert(testS(a, b, c) == "base1rc2rd3")
+  doAssert(testS(b, a, c) == "rc2base1rd3")
+  doAssert(testS(c, b, a) == "rd3rc2base1")
+  doAssert(testS([a, b, c]) == "base1rc2rd3")
+  # this is not varargs bug, but array construction bug
+  # see #7955
+  #doAssert(testS([b, c, a]) == "rc2rd3base1")
+  #doAssert(testS([c, b, a]) == "rd3rc2base1")
+
+proc test_inproc() =
+  block test_inproc_1:
+    var rgv = GRBase[int](val: 3)
+    var rgc = GRC[int](val: 4)
+    var rgb = GRD[int](val: 2)
+    doAssert(testGR(rgb, rgc, rgv) == "243")
+    doAssert(testGR(rgc, rgv, rgb) == "432")
+    doAssert(testGR(rgv, rgb, rgc) == "324")
+    doAssert(testGR([rgb, rgc, rgv]) == "243")
+    doAssert(testGR([rgc, rgv, rgb]) == "432")
+    doAssert(testGR([rgv, rgb, rgc]) == "324")
+
+  block test_inproc_2:
+    var pgv = PRBase[int](val: 3)
+    var pgc = PRC[int](val: 4)
+    var pgb = PRD[int](val: 2)
+    doAssert(testPR(pgb.addr, pgc.addr, pgv.addr) == "243")
+    doAssert(testPR(pgc.addr, pgv.addr, pgb.addr) == "432")
+    doAssert(testPR(pgv.addr, pgb.addr, pgc.addr) == "324")
+    doAssert(testPR([pgb.addr, pgc.addr, pgv.addr]) == "243")
+    doAssert(testPR([pgc.addr, pgv.addr, pgb.addr]) == "432")
+    doAssert(testPR([pgv.addr, pgb.addr, pgc.addr]) == "324")
+
+test_inproc()
+
+template reject(x) =
+  static: assert(not compiles(x))
+
+block test_t4799_7:
+  type
+    Vehicle[T] = ref object of RootObj
+      tire: T
+    Car[T] = object of Vehicle[T]
+    Bike[T] = object of Vehicle[T]
+
+  proc testVehicle[T](x: varargs[Vehicle[T]]): string {.used.} =
+    result = ""
+    for c in x:
+      result.add $c.tire
+
+  var v = Vehicle[int](tire: 3)
+  var c = Car[int](tire: 4)
+  var b = Bike[int](tire: 2)
+
+  reject:
+    echo testVehicle(b, c, v)
+
+block test_t4799_8:
+  type
+    Vehicle = ref object of RootObj
+      tire: int
+    Car = object of Vehicle
+    Bike = object of Vehicle
+
+  proc testVehicle(x: varargs[Vehicle]): string {.used.} =
+    result = ""
+    for c in x:
+      result.add $c.tire
+
+  var v = Vehicle(tire: 3)
+  var c = Car(tire: 4)
+  var b = Bike(tire: 2)
+
+  reject:
+    echo testVehicle(b, c, v)
+
+type
+  PGVehicle[T] = ptr object of RootObj
+    tire: T
+  PGCar[T] = object of PGVehicle[T]
+  PGBike[T] = object of PGVehicle[T]
+
+proc testVehicle[T](x: varargs[PGVehicle[T]]): string {.used.} =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var pgc = PGCar[int](tire: 4)
+var pgb = PGBike[int](tire: 2)
+
+reject:
+  echo testVehicle(pgb, pgc)
+
+type
+  RVehicle = ptr object of RootObj
+    tire: int
+  RCar = object of RVehicle
+  RBike = object of RVehicle
+
+proc testVehicle(x: varargs[RVehicle]): string {.used.} =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var rc = RCar(tire: 4)
+var rb = RBike(tire: 2)
+
+reject:
+  echo testVehicle(rb, rc)
+
+echo "OK"
diff --git a/tests/typerel/t4799_1.nim b/tests/typerel/t4799_1.nim
new file mode 100644
index 000000000..03d2a0cfa
--- /dev/null
+++ b/tests/typerel/t4799_1.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc"
+  targets: "c cpp"
+  outputsub: '''ObjectAssignmentDefect'''
+  exitcode: "1"
+"""
+
+type
+  Vehicle[T] = object of RootObj
+    tire: T
+  Car[T] = object of Vehicle[T]
+  Bike[T] = object of Vehicle[T]
+
+proc testVehicle[T](x: varargs[Vehicle[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var v = Vehicle[int](tire: 3)
+var c = Car[int](tire: 4)
+var b = Bike[int](tire: 2)
+echo testVehicle b, c, v
diff --git a/tests/typerel/t4799_2.nim b/tests/typerel/t4799_2.nim
new file mode 100644
index 000000000..ef8571f25
--- /dev/null
+++ b/tests/typerel/t4799_2.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc"
+  targets: "c cpp"
+  outputsub: '''ObjectAssignmentDefect'''
+  exitcode: "1"
+"""
+
+type
+  Vehicle[T] = object of RootObj
+    tire: T
+  Car[T] = object of Vehicle[T]
+  Bike[T] = object of Vehicle[T]
+
+proc testVehicle[T](x: varargs[Vehicle[T]]): string =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var v = Vehicle[int](tire: 3)
+var c = Car[int](tire: 4)
+var b = Bike[int](tire: 2)
+echo testVehicle([b, c, v])
\ No newline at end of file
diff --git a/tests/typerel/t4799_3.nim b/tests/typerel/t4799_3.nim
new file mode 100644
index 000000000..26258b983
--- /dev/null
+++ b/tests/typerel/t4799_3.nim
@@ -0,0 +1,22 @@
+discard """
+  matrix: "--mm:refc"
+  targets: "c cpp"
+  outputsub: '''ObjectAssignmentDefect'''
+  exitcode: "1"
+"""
+
+type
+  Vehicle = object of RootObj
+    tire: int
+  Car = object of Vehicle
+  Bike = object of Vehicle
+
+proc testVehicle(x: varargs[Vehicle]): string =
+  result = ""
+  for c in x:
+    result.add $c.tire
+
+var v = Vehicle(tire: 3)
+var c = Car(tire: 4)
+var b = Bike(tire: 2)
+echo testVehicle([b, c, v])
\ No newline at end of file
diff --git a/tests/typerel/t7600_1.nim b/tests/typerel/t7600_1.nim
new file mode 100644
index 000000000..83f93ae7f
--- /dev/null
+++ b/tests/typerel/t7600_1.nim
@@ -0,0 +1,21 @@
+discard """
+errormsg: "type mismatch: got <Thin[system.int]>"
+nimout: '''t7600_1.nim(21, 1) Error: type mismatch: got <Thin[system.int]>
+but expected one of:
+proc test[T](x: Paper[T])
+  first type mismatch at position: 1
+  required type for x: Paper[test.T]
+  but expression 'tn' is of type: Thin[system.int]
+
+expression: test tn'''
+"""
+
+type
+  Paper[T] = ref object of RootObj
+    thickness: T
+  Thin[T]  = object of Paper[T]
+
+proc test[T](x: Paper[T]) = discard
+
+var tn = Thin[int]()
+test tn
diff --git a/tests/typerel/t7600_2.nim b/tests/typerel/t7600_2.nim
new file mode 100644
index 000000000..9488a44bc
--- /dev/null
+++ b/tests/typerel/t7600_2.nim
@@ -0,0 +1,20 @@
+discard """
+errormsg: "type mismatch: got <Thin>"
+nimout: '''t7600_2.nim(20, 1) Error: type mismatch: got <Thin>
+but expected one of:
+proc test(x: Paper)
+  first type mismatch at position: 1
+  required type for x: Paper
+  but expression 'tn' is of type: Thin
+
+expression: test tn'''
+"""
+
+type
+  Paper = ref object of RootObj
+  Thin  = object of Paper
+
+proc test(x: Paper) = discard
+
+var tn = Thin()
+test tn
diff --git a/tests/typerel/t7734.nim b/tests/typerel/t7734.nim
new file mode 100644
index 000000000..1e8df2cf1
--- /dev/null
+++ b/tests/typerel/t7734.nim
@@ -0,0 +1,19 @@
+type
+  Foo[T: SomeFloat] = object
+    learning_rate: T
+
+  Bar[T: SomeFloat] = object
+    learning_rate: T
+    momentum: T
+
+  Model = object
+    weight: int
+
+  FooClass = Foo or Bar
+
+
+proc optimizer[M; T: SomeFloat](model: M, _: typedesc[Foo], learning_rate: T): Foo[T] =
+  result.learning_rate = learning_rate
+
+let a = Model(weight: 1)
+let opt = a.optimizer(Foo, 10.0)
diff --git a/tests/typerel/t8172.nim b/tests/typerel/t8172.nim
new file mode 100644
index 000000000..57b788250
--- /dev/null
+++ b/tests/typerel/t8172.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "cannot convert array[0..0, string] to varargs[string]"
+  line: 11
+"""
+
+proc f(v: varargs[string]) =
+  echo(v)
+
+f("b", "c")   # Works
+f(["b", "c"]) # Works
+f("b", ["c"]) # Fails
diff --git a/tests/typerel/t8905.nim b/tests/typerel/t8905.nim
new file mode 100644
index 000000000..9383962cf
--- /dev/null
+++ b/tests/typerel/t8905.nim
@@ -0,0 +1,7 @@
+type
+  Foo[T] = distinct seq[T]
+  Bar[T] = object
+
+proc newFoo[T](): Foo[T] = Foo[T](newSeq[T]())
+
+var x = newFoo[Bar[int]]()
diff --git a/tests/typerel/tclosure_nil_as_default.nim b/tests/typerel/tclosure_nil_as_default.nim
new file mode 100644
index 000000000..fe9f42b14
--- /dev/null
+++ b/tests/typerel/tclosure_nil_as_default.nim
@@ -0,0 +1,11 @@
+
+# bug #4328
+type
+    foo[T] = object
+        z: T
+
+proc test[T](x: foo[T], p: proc(a: T) = nil) =
+    discard
+
+var d: foo[int]
+d.test()  # <- param omitted
diff --git a/tests/typerel/tcommontype.nim b/tests/typerel/tcommontype.nim
new file mode 100644
index 000000000..f32228177
--- /dev/null
+++ b/tests/typerel/tcommontype.nim
@@ -0,0 +1,20 @@
+type
+  TAnimal{.inheritable.}=object
+  PAnimal=ref TAnimal
+
+  TDog=object of TAnimal
+  PDog=ref TDog
+
+  TCat=object of TAnimal
+  PCat=ref TCat
+
+  TAnimalArray=array[0..2,PAnimal]
+
+proc newDog():PDog = new(result)
+proc newCat():PCat = new(result)
+proc test(a:openArray[PAnimal])=
+  echo("dummy")
+
+#test(newDog(),newCat()) #does not work
+var myarray:TAnimalArray=[newDog(),newCat(),newDog()] #does not work
+#var myarray2:TAnimalArray=[newDog(),newDog(),newDog()] #does not work either
diff --git a/tests/typerel/temptynode.nim b/tests/typerel/temptynode.nim
new file mode 100644
index 000000000..8c71a6092
--- /dev/null
+++ b/tests/typerel/temptynode.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "type mismatch: got <void>"
+  line: 16
+"""
+
+# bug #950
+
+import macros
+
+proc blah(x: proc (a, b: int): int) =
+  echo x(5, 5)
+
+macro test(): untyped =
+  result = newNimNode(nnkEmpty)
+
+blah(test())
diff --git a/tests/typerel/texplicitcmp.nim b/tests/typerel/texplicitcmp.nim
new file mode 100644
index 000000000..57f1e81b6
--- /dev/null
+++ b/tests/typerel/texplicitcmp.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''[1 2 3 ]
+[1 2 3 ]
+[1 2 3 ]'''
+"""
+
+# bug #297
+
+import json, tables, algorithm
+
+proc outp(a: openArray[int]) =
+  stdout.write "["
+  for i in a: stdout.write($i & " ")
+  stdout.write "]\n"
+
+proc works() =
+  var f = @[3, 2, 1]
+  sort(f, system.cmp[int])
+  outp(f)
+
+proc weird(json_params: Table) =
+  var f = @[3, 2, 1]
+  # The following line doesn't compile: type mismatch. Why?
+  sort(f, system.cmp[int])
+  outp(f)
+
+var t = @[3, 2, 1]
+sort(t, system.cmp[int])
+outp(t)
+works()
+weird(initTable[string, JsonNode]())
diff --git a/tests/typerel/tgeneric_subtype_regression.nim b/tests/typerel/tgeneric_subtype_regression.nim
new file mode 100644
index 000000000..def5d721e
--- /dev/null
+++ b/tests/typerel/tgeneric_subtype_regression.nim
@@ -0,0 +1,19 @@
+discard """
+  errormsg: "type mismatch: got <FooRef[system.string]>"
+  line: 15
+"""
+
+# bug #4478
+
+type
+  Foo[T] = object
+  FooRef[T] = ref Foo[T]
+
+proc takeFoo[T](foo: Foo[T]): int = discard
+
+proc g(x: FooRef[string]) =
+  echo x.takeFoo() != 8
+
+var x: FooRef[string]
+
+g(x)
diff --git a/tests/typerel/tno_gcmem_in_shared.nim b/tests/typerel/tno_gcmem_in_shared.nim
new file mode 100644
index 000000000..dd8a1cb94
--- /dev/null
+++ b/tests/typerel/tno_gcmem_in_shared.nim
@@ -0,0 +1,23 @@
+discard """
+  errormsg: "shared memory may not refer to GC'ed thread local memory"
+  line: 14
+  disabled: true
+"""
+
+type
+  Region = object
+  Foo = Region ptr int
+
+  MyObject = object
+    a, b: string
+
+  Bar[T] = shared ptr T
+  Bzar = Bar[MyObject]
+
+proc bar(x: Region ptr int) =
+  discard
+
+var
+  s: Foo
+
+bar s
diff --git a/tests/typerel/tno_int_in_bool_context.nim b/tests/typerel/tno_int_in_bool_context.nim
new file mode 100644
index 000000000..66e9da58a
--- /dev/null
+++ b/tests/typerel/tno_int_in_bool_context.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "type mismatch: got <int literal(1)> but expected 'bool'"
+  line: 6
+"""
+
+if 1:
+  echo "wtf?"
diff --git a/tests/typerel/tnocontains.nim b/tests/typerel/tnocontains.nim
new file mode 100644
index 000000000..8bea8aa56
--- /dev/null
+++ b/tests/typerel/tnocontains.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "type mismatch: got <string, string>"
+  file: "tnocontains.nim"
+  line: 10
+"""
+
+# shouldn't compile since it doesn't do what you think it does without
+# importing strutils:
+
+let x = "abcdef".contains("abc")
+echo x
diff --git a/tests/typerel/tproctypeclass.nim b/tests/typerel/tproctypeclass.nim
new file mode 100644
index 000000000..e8fab9780
--- /dev/null
+++ b/tests/typerel/tproctypeclass.nim
@@ -0,0 +1,89 @@
+import std/assertions
+
+proc main =
+  iterator closureIter(): int {.closure.} =
+    yield 1
+    yield 2
+  iterator inlineIter(): int {.inline.} =
+    yield 1
+    yield 2
+  proc procNotIter(): int = 1
+
+  doAssert closureIter is iterator
+  doAssert inlineIter is iterator
+  doAssert procNotIter isnot iterator
+
+  doAssert closureIter isnot proc
+  doAssert inlineIter isnot proc
+  doAssert procNotIter is proc
+
+  doAssert typeof(closureIter) is iterator
+  doAssert typeof(inlineIter) is iterator
+  doAssert typeof(procNotIter) isnot iterator
+
+  doAssert typeof(closureIter) isnot proc
+  doAssert typeof(inlineIter) isnot proc
+  doAssert typeof(procNotIter) is proc
+
+  block:
+    proc fn1(iter: iterator {.closure.}) = discard
+    proc fn2[T: iterator {.closure.}](iter: T) = discard
+
+    fn1(closureIter)
+    fn2(closureIter)
+
+    doAssert not compiles(fn1(procNotIter))
+    doAssert not compiles(fn2(procNotIter))
+
+    doAssert not compiles(fn1(inlineIter))
+    doAssert not compiles(fn2(inlineIter))
+
+  block: # concrete iterator type
+    proc fn1(iter: iterator(): int) = discard
+    proc fn2[T: iterator(): int](iter: T) = discard
+
+    fn1(closureIter)
+    fn2(closureIter)
+
+    doAssert not compiles(fn1(procNotIter))
+    doAssert not compiles(fn2(procNotIter))
+
+    doAssert not compiles(fn1(inlineIter))
+    doAssert not compiles(fn2(inlineIter))
+
+  proc takesNimcall[T: proc {.nimcall.}](p: T) = discard
+  proc takesClosure[T: proc {.closure.}](p: T) = discard
+  proc takesAnyProc[T: proc](p: T) = discard
+
+  proc nimcallProc(): int {.nimcall.} = 1
+  proc closureProc(): int {.closure.} = 2
+
+  doAssert nimcallProc is proc {.nimcall.}
+  takesNimcall(nimcallProc)
+  doAssert closureProc isnot proc {.nimcall.}
+  doAssert not compiles(takesNimcall(closureProc))
+
+  doAssert nimcallProc isnot proc {.closure.}
+  doAssert not compiles(takesClosure(nimcallProc))
+  doAssert closureProc is proc {.closure.}
+  takesClosure(closureProc)
+  
+  doAssert nimcallProc is proc
+  takesAnyProc(nimcallProc)
+  doAssert closureProc is proc
+  takesAnyProc(closureProc)
+
+  block: # supposed to test that sameType works 
+    template ensureNotRedefine(Ty): untyped =
+      proc foo[T: Ty](x: T) = discard
+      doAssert not (compiles do:
+        proc bar[T: Ty](x: T) = discard
+        proc bar[T: Ty](x: T) = discard)
+    ensureNotRedefine proc
+    ensureNotRedefine iterator
+    ensureNotRedefine proc {.nimcall.}
+    ensureNotRedefine iterator {.nimcall.}
+    ensureNotRedefine proc {.closure.}
+    ensureNotRedefine iterator {.closure.}
+
+main()
diff --git a/tests/typerel/tptrs.nim b/tests/typerel/tptrs.nim
new file mode 100644
index 000000000..3505a7736
--- /dev/null
+++ b/tests/typerel/tptrs.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "type mismatch: got <ptr int16> but expected 'ptr int'"
+  line: 8
+"""
+
+var
+  n: int16
+  p: ptr int = addr n
diff --git a/tests/typerel/trectuple.nim b/tests/typerel/trectuple.nim
new file mode 100644
index 000000000..334c4a911
--- /dev/null
+++ b/tests/typerel/trectuple.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "illegal recursion in type 'TNode'"
+  line: 8
+  disabled: true
+"""
+
+type
+    PNode = ref TNode
+    TNode = tuple # comment
+      self: PNode # comment
+      a, b: int # comment
+
+var node: PNode
+new(node)
+node.self = node
+
diff --git a/tests/typerel/trectuples.nim b/tests/typerel/trectuples.nim
new file mode 100644
index 000000000..af9ba2dbb
--- /dev/null
+++ b/tests/typerel/trectuples.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "illegal recursion in type 'Node'"
+  line: 6
+"""
+
+type Node = tuple[left: ref Node]
+
+proc traverse(root: ref Node) =
+  if root.left != nil: traverse(root.left)
+
+type A = tuple[B: ptr A]
+proc C(D: ptr A) = C(D.B)
+
+
diff --git a/tests/trectype.nim b/tests/typerel/trectype.nim
index a7a6f56e0..9313faa20 100755..100644
--- a/tests/trectype.nim
+++ b/tests/typerel/trectype.nim
@@ -1,21 +1,24 @@
-# Test recursive type descriptions

-# (mainly for the C code generator)

-

-type

-  PA = ref TA

-  TA = array [0..2, PA]

-

-  PRec = ref TRec

-  TRec {.final.} = object

-    a, b: TA

-

-  P1 = ref T1

-  PB = ref TB

-  TB = array [0..3, P1]

-  T1 = array [0..6, PB]

+discard """
+  errormsg: "internal error: cannot generate C type for: PA"
+  disabled: true
+"""
+# Test recursive type descriptions
+# (mainly for the C code generator)
+
+type
+  PA = ref TA
+  TA = array[0..2, PA]
+
+  PRec = ref TRec
+  TRec {.final.} = object
+    a, b: TA
+
+  P1 = ref T1
+  PB = ref TB
+  TB = array[0..3, P1]
+  T1 = array[0..6, PB]
 
 var
   x: PA
 new(x)
 #ERROR_MSG internal error: cannot generate C type for: PA
-
diff --git a/tests/trefs.nim b/tests/typerel/trefs.nim
index ab3934088..e9862bd0f 100755..100644
--- a/tests/trefs.nim
+++ b/tests/typerel/trefs.nim
@@ -1,16 +1,20 @@
-# test for ref types (including refs to procs)

-

-type

-  TProc = proc (a, b: int): int {.stdcall.}

-

-proc foo(c, d: int): int {.stdcall.} =

-  return 0

-

-proc wrongfoo(c, e: int): int {.inline.} =

-  return 0

-

-var p: TProc

-p = foo

-write(stdout, "success!")

-p = wrongfoo  #ERROR_MSG type mismatch

-

+discard """
+  errormsg: "type mismatch"
+  file: "trefs.nim"
+  line: 20
+"""
+# test for ref types (including refs to procs)
+
+type
+  TProc = proc (a, b: int): int {.stdcall.}
+
+proc foo(c, d: int): int {.stdcall.} =
+  return 0
+
+proc wrongfoo(c, e: int): int {.inline.} =
+  return 0
+
+var p: TProc
+p = foo
+write(stdout, "success!")
+p = wrongfoo  #ERROR_MSG type mismatch
diff --git a/tests/typerel/tregionptrs2.nim b/tests/typerel/tregionptrs2.nim
new file mode 100644
index 000000000..7fe758c8e
--- /dev/null
+++ b/tests/typerel/tregionptrs2.nim
@@ -0,0 +1,23 @@
+
+# bug #2039
+
+type
+    RegionTy = object
+    ThingyPtr = RegionTy ptr Thingy
+    Thingy = object
+        next: ThingyPtr
+        name: string
+
+proc iname(t: ThingyPtr) =
+    var x = t
+
+    while not x.isNil:
+        echo x.name
+        x = x.next
+
+proc go() =
+    var athing : ThingyPtr
+
+    iname(athing)
+
+go()
diff --git a/tests/typerel/trettypeinference.nim b/tests/typerel/trettypeinference.nim
new file mode 100644
index 000000000..aa0d66e5b
--- /dev/null
+++ b/tests/typerel/trettypeinference.nim
@@ -0,0 +1,33 @@
+discard """
+  nimout:    "instantiated for string\ninstantiated for int\ninstantiated for bool"
+  output: "int\nseq[string]\nA\nB\n100\ntrue"
+"""
+
+import typetraits
+
+proc plus(a, b: auto): auto = a + b
+proc makePair(a, b: auto): auto = (first: a, second: b)
+
+proc `+`(a, b: string): seq[string] = @[a, b]
+
+var i = plus(10, 20)
+var s = plus("A", "B")
+
+var p = makePair("key", 100)
+static: assert p[0].type is string
+
+echo i.type.name
+echo s.type.name
+
+proc inst(a: auto): auto =
+  static: echo "instantiated for ", a.type.name
+  result = a
+
+echo inst("A")
+echo inst("B")
+echo inst(100)
+echo inst(true)
+
+# XXX: [string, tyGenericParam] is cached instead of [string, string]
+# echo inst[string, string]("C")
+
diff --git a/tests/typerel/tsecondarrayproperty.nim b/tests/typerel/tsecondarrayproperty.nim
new file mode 100644
index 000000000..315ad06bf
--- /dev/null
+++ b/tests/typerel/tsecondarrayproperty.nim
@@ -0,0 +1,31 @@
+discard """
+output: "4"
+"""
+
+
+type
+  TFoo = object
+    data: array[0..100, int]
+  TSecond = distinct TFoo
+
+proc `[]` (self: var TFoo, x: int): var int =
+  return self.data[x]
+
+proc `[]=` (self: var TFoo, x, y: int) =
+  # only `[]` returning a 'var T' seems to not work for now :-/
+  self.data[x] = y
+
+proc second(self: var TFoo): var TSecond =
+  return TSecond(self)
+
+proc `[]`(self: var TSecond, x: int): var int =
+  return TFoo(self).data[2*x]
+
+var f: TFoo
+
+for i in 0..f.data.high: f[i] = 2 * i
+
+echo f.second[1]
+
+#echo `second[]`(f,1)
+# this is the only way I could use it, but not what I expected
diff --git a/tests/typerel/tsigmatch.nim b/tests/typerel/tsigmatch.nim
new file mode 100644
index 000000000..7541f2028
--- /dev/null
+++ b/tests/typerel/tsigmatch.nim
@@ -0,0 +1,6 @@
+block: # bug #13618
+  proc test(x: Natural or BackwardsIndex): int =
+    int(x)
+
+  doAssert test(^1) == 1
+  doAssert test(1) == 1
diff --git a/tests/typerel/tstr_as_openarray.nim b/tests/typerel/tstr_as_openarray.nim
new file mode 100644
index 000000000..14cd21479
--- /dev/null
+++ b/tests/typerel/tstr_as_openarray.nim
@@ -0,0 +1,22 @@
+discard """
+  output: '''success'''
+"""
+var s = "HI"
+
+proc x (zz: openArray[char]) =
+  discard
+
+x s
+
+proc z [T] (zz: openArray[T]) =
+  discard
+
+z s
+z([s,s,s])
+
+proc y [T] (arg: var openArray[T]) =
+  arg[0] = 'X'
+y s
+doAssert s == "XI"
+
+echo "success"
diff --git a/tests/typerel/tsymchoice_for_expr.nim b/tests/typerel/tsymchoice_for_expr.nim
new file mode 100644
index 000000000..394b22704
--- /dev/null
+++ b/tests/typerel/tsymchoice_for_expr.nim
@@ -0,0 +1,15 @@
+# bug #1988
+
+template t(e) = discard
+
+proc positive(x: int): int = +x
+proc negative(x: int): int = -x
+proc negative(x: float): float = -x
+
+proc p1 = t(negative)
+proc p2[X] = t(positive)
+proc p3[X] = t(negative)
+
+p1()      # This compiles.
+p2[int]() # This compiles.
+p3[int]() # This raises an error.
diff --git a/tests/typerel/ttuple1.nim b/tests/typerel/ttuple1.nim
new file mode 100644
index 000000000..a03cc510e
--- /dev/null
+++ b/tests/typerel/ttuple1.nim
@@ -0,0 +1,20 @@
+discard """
+output: '''
+M=1000, D=500, C=100, L=50, X=10, V=5, I=1
+'''
+"""
+
+const romanNumbers = [
+    ("M", 1000), ("D", 500), ("C", 100),
+    ("L", 50), ("X", 10), ("V", 5), ("I", 1) ]
+
+var c = 0
+for key, val in items(romanNumbers):
+  inc(c)
+  stdout.write(key & "=" & $val)
+  if c < romanNumbers.len: stdout.write(", ") else: echo""
+#echo""
+
+proc PrintBiTuple(t: tuple[k: string, v: int]): int =
+  stdout.write(t.k & "=" & $t.v & ", ")
+  return 0
diff --git a/tests/typerel/ttynilinstantiation.nim b/tests/typerel/ttynilinstantiation.nim
new file mode 100644
index 000000000..303506689
--- /dev/null
+++ b/tests/typerel/ttynilinstantiation.nim
@@ -0,0 +1,7 @@
+proc foo[T: proc](x: T) =
+  # old error here:
+  let y = x
+  # invalid type: 'typeof(nil)' for let
+
+foo(nil) #[tt.Error
+   ^ type mismatch: got <typeof(nil)>]#
diff --git a/tests/typerel/ttypedesc_as_genericparam1.nim b/tests/typerel/ttypedesc_as_genericparam1.nim
new file mode 100644
index 000000000..8fdcf217e
--- /dev/null
+++ b/tests/typerel/ttypedesc_as_genericparam1.nim
@@ -0,0 +1,7 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "type mismatch: got <typedesc[int]>"
+  line: 7
+"""
+# bug #3079, #1146
+echo repr(int)
\ No newline at end of file
diff --git a/tests/typerel/ttypedesc_as_genericparam1_orc.nim b/tests/typerel/ttypedesc_as_genericparam1_orc.nim
new file mode 100644
index 000000000..d528a7421
--- /dev/null
+++ b/tests/typerel/ttypedesc_as_genericparam1_orc.nim
@@ -0,0 +1,5 @@
+discard """
+  matrix: "--mm:orc"
+"""
+
+doAssert repr(int) == "int"
diff --git a/tests/typerel/ttypedesc_as_genericparam2.nim b/tests/typerel/ttypedesc_as_genericparam2.nim
new file mode 100644
index 000000000..882f66584
--- /dev/null
+++ b/tests/typerel/ttypedesc_as_genericparam2.nim
@@ -0,0 +1,10 @@
+discard """
+  matrix: "--mm:refc"
+  errormsg: "'repr' doesn't support 'void' type"
+  line: 10
+"""
+
+# bug #2879
+
+var s: seq[int]
+echo repr(s.new_seq(3))
diff --git a/tests/typerel/ttypelessemptyset.nim b/tests/typerel/ttypelessemptyset.nim
new file mode 100644
index 000000000..a4b6f003a
--- /dev/null
+++ b/tests/typerel/ttypelessemptyset.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "statement returns no value that can be discarded"
+"""
+var q = false
+discard (if q: {} else: {})
+
diff --git a/tests/typerel/ttypenoval.nim b/tests/typerel/ttypenoval.nim
new file mode 100644
index 000000000..ca6c920ec
--- /dev/null
+++ b/tests/typerel/ttypenoval.nim
@@ -0,0 +1,53 @@
+discard """
+  errormsg: "type mismatch: got <typedesc[int]> but expected 'int'"
+  file: "ttypenoval.nim"
+  line: 38
+"""
+
+# A min-heap.
+type
+  TNode[T] = tuple[priority: int, data: T]
+
+  TBinHeap[T] = object
+    heap: seq[TNode[T]]
+    last: int
+
+  PBinHeap[T] = ref TBinHeap[T]
+
+proc newBinHeap*[T](heap: var PBinHeap[T], size: int) =
+  new(heap)
+  heap.last = 0
+  newSeq(heap.heap, size)
+  #newSeq(heap.seq, size)
+
+proc parent(elem: int): int {.inline.} =
+  return (elem-1) div 2
+
+proc siftUp[T](heap: PBinHeap[T], elem: int) =
+  var idx = elem
+  while idx != 0:
+    var p = parent(idx)
+    if heap.heap[idx] < heap.heap[p]:
+      swap(heap.heap[idx], heap.heap[p])
+      idx = p
+    else:
+      break
+
+proc add*[T](heap: PBinHeap[T], priority: int, data: T) =
+  var node: TNode[T]
+  node.priority = int
+  node.data = data
+  heap.heap[heap.last] = node
+  siftUp(heap, heap.last)
+  inc(heap.last)
+
+proc print*[T](heap: PBinHeap[T]) =
+  for i in countup(0, heap.last):
+    echo($heap.heap[i])
+
+var
+  heap: PBinHeap[int]
+
+newBinHeap(heap, 256)
+add(heap, 1, 100)
+print(heap)
diff --git a/tests/typerel/ttypenovalue.nim b/tests/typerel/ttypenovalue.nim
new file mode 100644
index 000000000..4664253ea
--- /dev/null
+++ b/tests/typerel/ttypenovalue.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "invalid type: 'typedesc[seq[tuple[title: string, body: string]]]' for var"
+  line: 7
+"""
+
+proc crashAndBurn() =
+  var stuff = seq[tuple[title, body: string]]
+
+
+crashAndBurn()
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/typerel/tvarargsexpr.nim b/tests/typerel/tvarargsexpr.nim
new file mode 100644
index 000000000..092d50076
--- /dev/null
+++ b/tests/typerel/tvarargsexpr.nim
@@ -0,0 +1,29 @@
+discard """
+  output: '''success
+true
+true'''
+"""
+
+#bug #913
+
+import macros
+
+macro thirteen(args: varargs[untyped]): int =
+  result = newIntLitNode(13)
+
+doAssert(13==thirteen([1,2])) # works
+doAssert(13==thirteen(1,2)) # works
+
+doAssert(13==thirteen(1,[2])) # does not work
+doAssert(13==thirteen([1], 2)) # does not work
+
+echo "success"
+
+# bug #2545
+
+import macros
+macro test(e: varargs[untyped]): untyped =
+  bindSym"true"
+
+echo test(a)
+echo test(fake=90, arguments=80, also="false", possible=true)
diff --git a/tests/typerel/tvoid.nim b/tests/typerel/tvoid.nim
new file mode 100644
index 000000000..8bb5691b8
--- /dev/null
+++ b/tests/typerel/tvoid.nim
@@ -0,0 +1,98 @@
+discard """
+  output: '''12
+empty
+he, no return type;
+abc a string
+ha'''
+"""
+
+proc ReturnT[T](x: T): T =
+  when T is void:
+    echo "he, no return type;"
+  else:
+    result = x & " a string"
+
+proc nothing(x, y: void): void =
+  echo "ha"
+
+proc callProc[T](p: proc (x: T) {.nimcall.}, x: T) =
+  when T is void:
+    p()
+  else:
+    p(x)
+
+proc intProc(x: int) =
+  echo x
+
+proc emptyProc() =
+  echo "empty"
+
+callProc[int](intProc, 12)
+callProc[void](emptyProc)
+
+
+ReturnT[void]()
+echo ReturnT[string]("abc")
+nothing()
+
+block: # typeof(stmt)
+  proc fn1(): auto =
+    discard
+  proc fn2(): auto =
+    1
+  doAssert type(fn1()) is void
+  doAssert typeof(fn1()) is void
+  doAssert typeof(fn1()) isnot int
+
+  doAssert type(fn2()) isnot void
+  doAssert typeof(fn2()) isnot void
+  when typeof(fn1()) is void: discard
+  else: doAssert false
+
+  doAssert typeof(1+1) is int
+  doAssert typeof((discard)) is void
+
+  type A1 = typeof(fn1())
+  doAssert A1 is void
+  type A2 = type(fn1())
+  doAssert A2 is void
+  doAssert A2 is A1
+
+  when false:
+    # xxx: MCS/UFCS doesn't work here: Error: expression 'fn1()' has no type (or is ambiguous)
+    type A3 = fn1().type
+  proc bar[T](a: T): string = $T
+  doAssert bar(1) == "int"
+  doAssert bar(fn1()) == "void"
+
+  proc bar2[T](a: T): bool = T is void
+  doAssert not bar2(1)
+  doAssert bar2(fn1())
+
+  block:
+    proc bar3[T](a: T): T = a
+    let a1 = bar3(1)
+    doAssert compiles(block:
+      let a1 = bar3(fn2()))
+    doAssert not compiles(block:
+      let a2 = bar3(fn1()))
+    doAssert compiles(block: bar3(fn1()))
+    doAssert compiles(bar3(fn1()))
+    doAssert typeof(bar3(fn1())) is void
+    doAssert not compiles(sizeof(bar3(fn1())))
+
+  block:
+    var a = 1
+    doAssert typeof((a = 2)) is void
+    doAssert typeof((a = 2; a = 3)) is void
+    doAssert typeof(block:
+      a = 2; a = 3) is void
+
+  block:
+    var a = 1
+    template bad1 = echo (a; a = 2)
+    doAssert not compiles(bad1())
+
+  block:
+    template bad2 = echo (nonexistent; discard)
+    doAssert not compiles(bad2())
diff --git a/tests/typalias.nim b/tests/typerel/typalias.nim
index ba9f38ed9..e85f1f664 100755..100644
--- a/tests/typalias.nim
+++ b/tests/typerel/typalias.nim
@@ -1,15 +1,15 @@
 
 type
   TMyObj = TYourObj
-  TYourObj = object of TObject
+  TYourObj = object of RootObj
     x, y: int
-  
+
 proc init: TYourObj =
   result.x = 0
   result.y = -1
-  
+
 proc f(x: var TYourObj) =
-  nil
-  
+  discard
+
 var m: TMyObj = init()
 f(m)
diff --git a/tests/typerel/typedescs.nim b/tests/typerel/typedescs.nim
new file mode 100644
index 000000000..faf919e13
--- /dev/null
+++ b/tests/typerel/typedescs.nim
@@ -0,0 +1,22 @@
+# bug #1774
+proc p(T: typedesc) = discard
+
+p(type((5, 6)))       # Compiles
+(type((5, 6))).p      # Doesn't compile (SIGSEGV: Illegal storage access.)
+type T = type((5, 6)) # Doesn't compile (SIGSEGV: Illegal storage access.)
+
+block: # issue #21677
+  type
+    Uints = uint16|uint32
+
+  template constructor(name: untyped, typ: typedesc[Uints], typ2: typedesc[Uints]) =
+    type
+      name = object
+        data: typ
+        data2: typ2
+
+    proc `init name`(data: typ, data2: typ2): name =
+      result.data = data
+      result.data2 = data2
+
+  constructor(Test, uint32, uint16)
diff --git a/tests/typerel/typedescs2.nim b/tests/typerel/typedescs2.nim
new file mode 100644
index 000000000..a0308719d
--- /dev/null
+++ b/tests/typerel/typedescs2.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "invalid type: 'typedesc[Table]' for const"
+  file: "typedescs2.nim"
+  line: 16
+"""
+
+# bug #9961
+
+import typetraits
+import tables
+
+proc test(v: typedesc) =
+  echo v.type.name
+
+# This crashes the compiler
+const b: typedesc = Table
+test b
diff --git a/tests/typerel/typeof_in_template.nim b/tests/typerel/typeof_in_template.nim
new file mode 100644
index 000000000..3724cc994
--- /dev/null
+++ b/tests/typerel/typeof_in_template.nim
@@ -0,0 +1,16 @@
+discard """
+  output: '''@["a", "c"]'''
+"""
+
+# bug #3230
+
+import sequtils
+
+const
+  test_strings = ["a", "b", "c"]
+
+proc is_doc(x: string): bool = x == "b"
+
+let
+  tests = @test_strings.filter_it(not it.is_doc)
+echo tests
diff --git a/tests/typerel/typredef.nim b/tests/typerel/typredef.nim
new file mode 100644
index 000000000..c502a834c
--- /dev/null
+++ b/tests/typerel/typredef.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "illegal recursion in type \'Uint8\'"
+  file: "typredef.nim"
+  line: 7
+"""
+type
+  Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'
diff --git a/tests/types/t14127_cast_number.nim b/tests/types/t14127_cast_number.nim
new file mode 100644
index 000000000..4bb23f22f
--- /dev/null
+++ b/tests/types/t14127_cast_number.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "c cpp js"
+"""
+block: # bug #14127
+  template int2uint(T) =
+    var a = -1
+    let b = cast[T](a)
+    doAssert b < 0
+    let c = b + 1
+    doAssert c is T
+    doAssert c == 0
+
+  int2uint(int8)
+  int2uint(int16)
+  int2uint(int32)
+  int2uint(int64)
+
+block: # maybe related
+  template uint2int(T) =
+    var a = 3
+    let b = cast[T](a)
+    doAssert b > 0
+    let c = b - 1
+    doAssert c is T
+    doAssert c == 2
+
+  uint2int(uint8)
+  uint2int(uint16)
+  uint2int(uint32)
+  uint2int(uint64)
diff --git a/tests/types/t15836.nim b/tests/types/t15836.nim
new file mode 100644
index 000000000..27d3ad0d0
--- /dev/null
+++ b/tests/types/t15836.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "type mismatch: got <int literal(1), proc (a: GenericParam): auto>"
+  line: 11
+""" 
+
+proc takesProc[T](x: T, f: proc(x: T): int) =
+    echo f(x) + 2
+
+takesProc(1, proc (a: int): int = 2) # ok, prints 4
+takesProc(1, proc (a: auto): auto = 2) # ok, prints 4
+takesProc(1, proc (a: auto): auto = "uh uh") # prints garbage
diff --git a/tests/types/t15836_2.nim b/tests/types/t15836_2.nim
new file mode 100644
index 000000000..6a16e2d22
--- /dev/null
+++ b/tests/types/t15836_2.nim
@@ -0,0 +1,21 @@
+import std/sugar
+
+type Tensor[T] = object
+  x: T
+
+proc numerical_gradient*[T](input: T, f: (proc(x: T): T), h = T(1e-5)): T {.inline.} =
+  result = default(T)
+
+proc numerical_gradient*[T](input: Tensor[T], f: (proc(x: Tensor[T]): T), h = T(1e-5)): Tensor[T] {.noinit.} =
+  result = default(Tensor[T])
+
+proc conv2d*[T](input: Tensor[T]): Tensor[T] {.inline.} =
+  result = default(Tensor[T])
+
+proc sum*[T](arg: Tensor[T]): T = default(T)
+
+proc sum*[T](arg: Tensor[T], axis: int): Tensor[T] {.noinit.} = default(Tensor[T])
+
+let dinput = Tensor[int](x: 1)
+let target_grad_input = dinput.numerical_gradient(
+    x => conv2d(x).sum())
diff --git a/tests/types/t21027.nim b/tests/types/t21027.nim
new file mode 100644
index 000000000..3a992177a
--- /dev/null
+++ b/tests/types/t21027.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "Invalid usage of cast, cast requires a type to convert to, e.g., cast[int](0d)."
+"""
+# bug #21027
+let x: uint64 = cast(5)
diff --git a/tests/types/t21260.nim b/tests/types/t21260.nim
new file mode 100644
index 000000000..90d6613c1
--- /dev/null
+++ b/tests/types/t21260.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "illegal recursion in type 'Foo'"
+  line: 8
+"""
+
+type
+  Kind = enum kA, kB
+  Foo = object
+    case k: Kind:
+    of kA:
+      foo: Foo
+    of kB:
+      discard
diff --git a/tests/types/t5648.nim b/tests/types/t5648.nim
new file mode 100644
index 000000000..b3bd406b3
--- /dev/null
+++ b/tests/types/t5648.nim
@@ -0,0 +1,32 @@
+discard """
+  output: '''
+ptr Foo
+'''
+joinable: false
+"""
+# not joinable because it causes out of memory with --gc:boehm
+
+# issue #5648
+
+import typetraits
+
+type Foo = object
+  bar: int
+
+proc main() =
+  var f = create(Foo)
+  f.bar = 3
+  echo f.type.name
+
+  discard realloc(f, 0)
+
+  var g = Foo()
+  g.bar = 3
+
+var
+  mainPtr = cast[pointer](main)
+  mainFromPtr = cast[typeof(main)](mainPtr)
+
+doAssert main == mainFromPtr
+
+main()
diff --git a/tests/types/t6456.nim b/tests/types/t6456.nim
new file mode 100644
index 000000000..19bbc2c02
--- /dev/null
+++ b/tests/types/t6456.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "type \'ptr void\' is not allowed"
+  line: 6
+"""
+
+proc foo(x: ptr void) =
+  discard
diff --git a/tests/types/t6969.nim b/tests/types/t6969.nim
new file mode 100644
index 000000000..14a8481cf
--- /dev/null
+++ b/tests/types/t6969.nim
@@ -0,0 +1,6 @@
+discard """
+errormsg: "invalid type: 'object' for var"
+line: 6
+"""
+
+var a: object
diff --git a/tests/types/taliasbugs.nim b/tests/types/taliasbugs.nim
new file mode 100644
index 000000000..f1b35edf6
--- /dev/null
+++ b/tests/types/taliasbugs.nim
@@ -0,0 +1,169 @@
+discard """
+  nimout: '''true
+true
+true
+true
+true
+true'''
+  output: '''true
+true
+true
+true
+true
+true
+R
+R
+R
+R
+19
+(c: 0)
+(c: 13)
+@[(c: 11)]
+@[(c: 17)]
+100'''
+"""
+
+# bug #5360
+import macros
+
+type
+  Order = enum
+    R
+  OrderAlias = Order
+
+template getOrderTypeA(): typedesc = Order
+template getOrderTypeB(): typedesc = OrderAlias
+
+type
+  OrderR    = getOrderTypeA()
+  OrderG    = getOrderTypeB()
+
+macro typeRep(a, b: typed): untyped =
+  if sameType(a, b):
+    echo "true"
+  else:
+    echo "false"
+
+template test(a, b: typedesc) =
+  when a is b:
+    echo "true"
+  else:
+    echo "false"
+
+test(OrderAlias, Order)
+test(OrderR, Order)
+test(OrderG, Order)
+
+test(OrderR, OrderG)
+test(OrderR, OrderAlias)
+test(OrderG, OrderAlias)
+
+typeRep(OrderAlias.R, Order.R)  # true
+typeRep(OrderR.R, Order.R)      # true
+typeRep(OrderG.R, Order.R)      # true
+
+typeRep(OrderR.R, OrderAlias.R) # true
+typeRep(OrderG.R, OrderAlias.R) # true
+typeRep(OrderR.R, OrderG.R)     # true
+
+echo OrderR.R      # R
+echo OrderG.R      # R
+echo OrderAlias.R  # R
+echo Order.R       # R
+
+# bug #5238
+
+type
+  Rgba8 = object
+    c: int
+  BlenderRgb*[ColorT] = object
+
+template getColorType*[C](x: typedesc[BlenderRgb[C]]): typedesc = C
+
+type
+  ColorT = getColorType(BlenderRgb[int])
+
+proc setColor(c: var ColorT) =
+  c = 19
+
+var n: ColorT
+n.setColor()
+echo n
+
+type
+  ColorType = getColorType(BlenderRgb[Rgba8])
+
+var x: ColorType
+echo x
+
+proc setColor(c: var ColorType) =
+  c = Rgba8(c: 13)
+
+proc setColor(c: var seq[ColorType]) =
+  c[0] = Rgba8(c: 11)
+
+proc setColorArray(c: var openArray[ColorType]) =
+  c[0] = Rgba8(c: 17)
+
+x.setColor()
+echo x
+
+var y = @[Rgba8(c:15)]
+y.setColor()
+echo y
+
+y.setColorArray()
+echo y
+
+#bug #6016
+type
+  Onion {.union.} = object
+    field1: int
+    field2: uint64
+
+  Stroom  = Onion
+
+  PStroom = ptr Stroom
+
+proc pstruct(u: PStroom) =
+  echo u.field2
+
+var oni = Onion(field1: 100)
+pstruct(oni.addr)
+
+
+# bug #4124
+
+import sequtils
+
+type
+    Foo = distinct string
+
+var
+  foo: Foo
+
+type
+    Alias = (type(foo))
+var
+  a: Alias
+
+a = foo
+
+when true:
+  var xs = @[1,2,3]
+
+  proc asFoo(i: string): Foo =
+      Foo(i)
+
+  var xx = xs.mapIt(asFoo($(it + 5)))
+
+
+block t4674:
+  type
+    FooObj[T] = object
+      v: T
+    Foo1[T] = FooObj[T]
+    Foo2 = FooObj
+    Foo1x = Foo1
+    Foo12x = Foo1 | Foo2
+    Foo2x = Foo2  # Error: illegal recursion in type 'Foo2x'
diff --git a/tests/types/tassignemptytuple.nim b/tests/types/tassignemptytuple.nim
new file mode 100644
index 000000000..9d5a311ba
--- /dev/null
+++ b/tests/types/tassignemptytuple.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "cannot infer the type of the tuple"
+  file: "tassignemptytuple.nim"
+  line: 11
+"""
+
+var
+  foo: seq[int]
+  bar: tuple[a: seq[int], b: set[char]]
+
+(foo, bar) = (@[], (@[], {}))
diff --git a/tests/types/tauto_canbe_void.nim b/tests/types/tauto_canbe_void.nim
new file mode 100644
index 000000000..c43215d1e
--- /dev/null
+++ b/tests/types/tauto_canbe_void.nim
@@ -0,0 +1,15 @@
+discard """
+output: '''
+arg
+arg
+'''
+"""
+
+
+import sugar
+
+template tempo(s) =
+  s("arg")
+
+tempo((s: string)->auto => echo(s))
+tempo((s: string) => echo(s))
diff --git a/tests/types/tauto_excessive.nim b/tests/types/tauto_excessive.nim
new file mode 100644
index 000000000..2626b0cf4
--- /dev/null
+++ b/tests/types/tauto_excessive.nim
@@ -0,0 +1,20 @@
+discard """
+  output: '''10
+10.0
+1.0hiho'''
+"""
+
+# bug #3224
+proc f(x: auto): auto =
+  result = $(x+10)
+
+proc f(x, y: auto): auto =
+  result = $(x+y)
+
+
+echo f(0)     # prints 10
+echo f(0.0)  # prints 10.0
+
+proc `+`(a, b: string): string = a & b
+
+echo f(0.7, 0.3), f("hi", "ho")
diff --git a/tests/types/tcast1.nim b/tests/types/tcast1.nim
new file mode 100644
index 000000000..ab375b8b2
--- /dev/null
+++ b/tests/types/tcast1.nim
@@ -0,0 +1,63 @@
+discard """
+output: '''
+@[1.0, 2.0, 3.0]
+@[1.0, 2.0, 3.0]
+'''
+"""
+
+# bug #6406
+
+import sequtils
+
+proc remap1(s: seq[int], T: typedesc): seq[T] =
+  s.map do (x: int) -> T:
+    x.T
+
+proc remap2[T](s: seq[int], typ: typedesc[T]): seq[T] =
+  s.map do (x: int) -> T:
+    x.T
+
+echo remap1(@[1,2,3], float)
+echo remap2(@[1,2,3], float)
+
+
+#--------------------------------------------------------------------
+# conversion to bool, issue #13744
+proc test_conv_to_bool = 
+  var 
+    i0 = 0
+    i1 = 1
+    ih = high(uint)
+    il = low(int)
+
+    f0 = 0.0
+    f1 = 1.0
+    fh = Inf
+    fl = -Inf
+    f_nan = NaN
+
+  doAssert(bool(i0) == false)
+  doAssert(bool(i1) == true)
+  doAssert(bool(-i1) == true)
+  doAssert(bool(il) == true)
+  doAssert(bool(ih) == true)
+
+  doAssert(bool(f0) == false)
+  doAssert(bool(-f0) == false)
+  doAssert(bool(f1) == true)
+  doAssert(bool(-f1) == true)
+  doAssert(bool(fh) == true)
+  doAssert(bool(fl) == true)
+  doAssert(bool(fnan) == true) # NaN to bool gives true according to standard
+
+
+static:
+  doAssert(bool(0) == false)
+  doAssert(bool(-1) == true)
+  doAssert(bool(2) == true)
+  doAssert(bool(NaN) == true)
+  doAssert(bool(0.0) == false)
+  doAssert(bool(-0.0) == false)
+  test_conv_to_bool()
+test_conv_to_bool()
+
diff --git a/tests/types/tcyclic.nim b/tests/types/tcyclic.nim
new file mode 100644
index 000000000..651394c8b
--- /dev/null
+++ b/tests/types/tcyclic.nim
@@ -0,0 +1,135 @@
+## todo publish the `isCyclic` when it's mature.
+proc isCyclic(t: typedesc): bool {.magic: "TypeTrait".} =
+  ## Returns true if the type can potentially form a cyclic type
+
+template cyclicYes(x: typed) =
+  doAssert isCyclic(x)
+
+template cyclicNo(x: typed) =
+  doAssert not isCyclic(x)
+
+# atomic types are not cyclic
+cyclicNo(int)
+cyclicNo(float)
+cyclicNo(string)
+cyclicNo(char)
+cyclicNo(void)
+
+type
+  Object = object
+  Ref = ref object
+
+cyclicNo(Object)
+cyclicNo(Ref)
+
+type
+  Data1 = ref object
+  Data2 = ref object
+    id: Data1
+
+cyclicNo(Data2)
+
+type
+  Cyclone = ref object
+    data: Cyclone
+
+  Alias = Cyclone
+
+  Acyclic {.acyclic.} = ref object
+    data: Acyclic
+
+  LinkedNode = object
+    next: ref LinkedNode
+
+  LinkedNodeWithCursor = object
+    next {.cursor.} : ref LinkedNodeWithCursor
+
+cyclicYes(Cyclone)
+cyclicYes(Alias)
+cyclicNo(seq[Cyclone])
+cyclicNo((Cyclone, ))
+cyclicNo(Acyclic)
+
+cyclicYes(LinkedNode)
+cyclicNo(LinkedNodeWithCursor) # cursor doesn't increase rc, cannot form a cycle
+
+type
+  ObjectWithoutCycles = object
+    data: seq[ObjectWithoutCycles]
+
+cyclicNo(ObjectWithoutCycles)
+
+
+block:
+  type
+    Try = object
+      id: Best
+    Best = object
+      name: ref Try
+    Best2 = ref Best
+
+  cyclicYes(Best)
+  cyclicYes(Try)
+  cyclicNo(Best2)
+
+  type
+    Base = object
+      data: ref seq[Base]
+    Base2 = ref Base
+
+  cyclicYes(Base)
+  cyclicNo(Base2)
+
+
+  type
+    Base3 = ref object
+      id: Base3
+
+    Base4 = object
+      id: ref Base4
+
+  cyclicYes(Base3)
+  cyclicYes(Base4)
+  cyclicYes(ref Base4)
+
+block:
+  type Cyclic2 = object
+    x: ref (Cyclic2, int)
+
+  cyclicYes (Cyclic2, int)
+  cyclicYes (ref (Cyclic2, int))
+
+block:
+  type
+    myseq[T] = object
+      data: ptr UncheckedArray[T]
+    Node = ref object
+      kids: myseq[Node]
+
+  cyclicNo(Node)
+
+block:
+  type
+    myseq[T] = object
+      data: ptr UncheckedArray[T]
+    Node = ref object
+      kids: myseq[Node]
+
+  proc `=trace`(x: var myseq[Node]; env: pointer) = discard
+
+  cyclicYes(Node)
+
+block:
+  type
+    Foo = object
+      id: ptr ref Foo
+
+  cyclicNo(Foo)
+
+block:
+  type
+    InheritableObj = object of RootObj
+    InheritableRef = ref object of RootObj
+
+  cyclicYes(InheritableObj)
+  cyclicYes(InheritableRef)
diff --git a/tests/types/temptyseqs.nim b/tests/types/temptyseqs.nim
new file mode 100644
index 000000000..6e7b58ced
--- /dev/null
+++ b/tests/types/temptyseqs.nim
@@ -0,0 +1,90 @@
+discard """
+  output: '''1
+foo
+bar
+baz
+foo
+bar
+baz
+yes
+no'''
+"""
+
+# bug #1708
+let foo = {
+  "1" : (bar: @["1"]),
+  "2" : (bar: @[])
+}
+
+# bug #871
+
+when true:
+  import os
+
+  type
+    In_out = tuple[src, dest: string, options: ref int]
+
+  let
+    nil_var: In_out = ("hey"/"there", "something", nil)
+    #nil_var2 = ("hey"/"there", "something", nil)
+
+# bug #1721
+const foo2: seq[string] = @[]
+
+echo foo[0][0][0]
+
+proc takeEmpty(x: openArray[string] = []) = discard
+takeEmpty()
+takeEmpty([])
+
+proc takeEmpty2(x: openArray[string] = @[]) = discard
+takeEmpty2()
+takeEmpty2([])
+takeEmpty2(@[])
+
+#takeEmpty2([nil])
+
+#rawMessage(errExecutionOfProgramFailed, [])
+
+# bug #2470
+const
+  stuff: seq[string] = @[]
+
+for str in stuff:
+  echo "str=", str
+
+# bug #1354
+proc foo4[T](more: seq[T] = @[]) =
+  var more2 = more
+
+foo4[int]()
+
+proc maino: int =
+  var wd: cstring = nil
+  inc result
+
+discard maino()
+
+proc varargso(a: varargs[string]) =
+  for x in a:
+    echo x
+
+varargso(["foo", "bar", "baz"])
+varargso("foo", "bar", "baz")
+
+
+type
+  Flago = enum
+    tfRequiresInit, tfNotNil
+
+var s: set[Flago] = {tfRequiresInit}
+
+if {tfRequiresInit, tfNotNil} * s != {}:
+  echo "yes"
+else:
+  echo "no"
+
+if {tfRequiresInit, tfNotNil} * s <= {tfNotNil}:
+  echo "yes"
+else:
+  echo "no"
diff --git a/tests/types/texportgeneric.nim b/tests/types/texportgeneric.nim
new file mode 100644
index 000000000..9e6be2bb6
--- /dev/null
+++ b/tests/types/texportgeneric.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "{.exportc.} not allowed for generic types"
+  line: 6
+"""
+
+type Struct[T] {.exportc.} = object
+  a:int
+  b: T
\ No newline at end of file
diff --git a/tests/types/tfinalobj.nim b/tests/types/tfinalobj.nim
new file mode 100644
index 000000000..ad3085132
--- /dev/null
+++ b/tests/types/tfinalobj.nim
@@ -0,0 +1,15 @@
+discard """
+  output: '''abc'''
+"""
+
+type
+  TA {.pure, final.} = object
+    x: string
+
+var
+  a: TA
+a.x = "abc"
+
+doAssert TA.sizeof == string.sizeof
+
+echo a.x
diff --git a/tests/tforwty.nim b/tests/types/tforwty.nim
index 0f1d3697f..626abd5ef 100755..100644
--- a/tests/tforwty.nim
+++ b/tests/types/tforwty.nim
@@ -1,9 +1,9 @@
-# Test 13: forward types

-

-type

-  PSym = ref TSym

-

-  TSym = object

-    next: PSym

-

-var s: PSym

+# Test 13: forward types
+
+type
+  PSym = ref TSym
+
+  TSym = object
+    next: PSym
+
+var s: PSym
diff --git a/tests/tforwty2.nim b/tests/types/tforwty2.nim
index 5d15e112a..6449e25bc 100755..100644
--- a/tests/tforwty2.nim
+++ b/tests/types/tforwty2.nim
@@ -1,22 +1,22 @@
-# Test for a hard to fix internal error

-# occured in the SDL library

-

-{.push dynlib: "SDL.dll", callconv: cdecl.}

-

-type

-  PSDL_semaphore = ptr TSDL_semaphore

-  TSDL_semaphore {.final.} = object

-    sem: Pointer             #PSem_t;

-    when not defined(USE_NAMED_SEMAPHORES):

-      sem_data: int

-    when defined(BROKEN_SEMGETVALUE):

-      # This is a little hack for MacOS X -

-      # It's not thread-safe, but it's better than nothing

-      sem_value: cint

-

-type

-  PSDL_Sem = ptr TSDL_Sem

-  TSDL_Sem = TSDL_Semaphore

-

-proc SDL_CreateSemaphore(initial_value: Int32): PSDL_Sem {.

-  importc: "SDL_CreateSemaphore".}

+# Test for a hard to fix internal error
+# occurred in the SDL library
+
+{.push dynlib: "SDL.dll", callconv: cdecl.}
+
+type
+  PSDL_semaphore = ptr TSDL_semaphore
+  TSDL_semaphore {.final.} = object
+    sem: pointer             #PSem_t;
+    when not defined(USE_NAMED_SEMAPHORES):
+      sem_data: int
+    when defined(BROKEN_SEMGETVALUE):
+      # This is a little hack for MacOS X -
+      # It's not thread-safe, but it's better than nothing
+      sem_value: cint
+
+type
+  PSDL_Sem = ptr TSDL_Sem
+  TSDL_Sem = TSDL_Semaphore
+
+proc SDL_CreateSemaphore(initial_value: int32): PSDL_Sem {.
+  importc: "SDL_CreateSemaphore".}
diff --git a/tests/types/thard_tyforward.nim b/tests/types/thard_tyforward.nim
new file mode 100644
index 000000000..8f606a0f9
--- /dev/null
+++ b/tests/types/thard_tyforward.nim
@@ -0,0 +1,22 @@
+type
+  Bar[T] = Foo[T, T]
+  Baz[T] = proc (x: Foo[T, T])
+  
+  GenericAlias[T] = Foo[T, T]
+  GenericAlias2[T] = Foo[Baz[T], T]
+  
+  Concrete1 = Foo[int, float]
+  Concrete2 = proc(x: proc(a: Foo[int, float]))
+  
+  Foo[T, U] = object
+    x: T
+    y: U
+
+var
+  x1: Bar[float]
+  x2: Baz[int]
+  x3: Concrete1
+  x4: Concrete2
+  x5: GenericAlias[int]
+  x6: GenericAlias2[string]
+
diff --git a/tests/types/tillegalrecursion3.nim b/tests/types/tillegalrecursion3.nim
new file mode 100644
index 000000000..fb5c1641c
--- /dev/null
+++ b/tests/types/tillegalrecursion3.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "illegal recursion in type 'Foo'"
+"""
+
+type
+  Imported {.importc.} = object
+
+  Foo = object
+    b: Imported
+    a: Foo
+
+var myFoo: Foo
diff --git a/tests/types/tillegalseqrecursion.nim b/tests/types/tillegalseqrecursion.nim
new file mode 100644
index 000000000..9221bb38a
--- /dev/null
+++ b/tests/types/tillegalseqrecursion.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "illegal recursion in type 'CyclicSeq'"
+"""
+# issue #13715
+type
+  CyclicSeq = seq[ref CyclicSeq]
diff --git a/tests/types/tillegaltuplerecursion.nim b/tests/types/tillegaltuplerecursion.nim
new file mode 100644
index 000000000..cb75ad9c3
--- /dev/null
+++ b/tests/types/tillegaltuplerecursion.nim
@@ -0,0 +1,40 @@
+discard """
+  errormsg: "illegal recursion in type"
+"""
+
+# This is one big illegal type cycle. It doesn't really matter at
+# what line the error is reported, nor what name is picked to point
+# out the illegal recursion.
+
+type
+  MyType0 = ref tuple
+    children: MyType1
+
+  MyType1 = ref tuple
+    children: array[10, MyType2]
+
+  MyType2 = ref tuple
+    children: seq[MyType3]
+
+  MyType3 = ref tuple
+    children: UncheckedArray[MyType4]
+
+  MyType4 = ref tuple
+    children: MyType5
+
+  MyType5 = tuple
+    children: array[10, MyType6]
+
+  MyType6 = tuple
+    children: seq[MyType7]
+
+  MyType7 = tuple
+    children: UncheckedArray[MyType8]
+
+  MyType8 = tuple
+    children: ptr MyType9
+
+  MyType9 = tuple
+    children: MyType10
+
+  MyType10 = distinct seq[MyType0]
diff --git a/tests/types/tillegaltuplerecursiongeneric.nim b/tests/types/tillegaltuplerecursiongeneric.nim
new file mode 100644
index 000000000..da65d48eb
--- /dev/null
+++ b/tests/types/tillegaltuplerecursiongeneric.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "illegal recursion in type 'RefTree'"
+"""
+
+type
+  RefTree[T] = ref tuple[le, ri: RefTree[T]; data: T]
+  RefTreeInt = RefTree[int]
diff --git a/tests/types/tillegaltuplerecursiongeneric2.nim b/tests/types/tillegaltuplerecursiongeneric2.nim
new file mode 100644
index 000000000..36ebd63be
--- /dev/null
+++ b/tests/types/tillegaltuplerecursiongeneric2.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "illegal recursion in type 'TPearl'"
+"""
+
+type
+  TPearl[T] = tuple
+    next: TPearl[T]
+
+var x: TPearl[int]
diff --git a/tests/types/tillegaltyperecursion.nim b/tests/types/tillegaltyperecursion.nim
new file mode 100644
index 000000000..372615c4d
--- /dev/null
+++ b/tests/types/tillegaltyperecursion.nim
@@ -0,0 +1,17 @@
+discard """
+  cmd: "nim $target --threads:on $options $file"
+  errormsg: "illegal recursion in type 'TIRC'"
+  line: 12
+"""
+
+import net
+import strutils
+import os
+
+type
+    TIRC = object
+        Socket: Socket
+        Thread: Thread[TIRC]
+
+proc initIRC*(): TIRC =
+    result.Socket = socket()
diff --git a/tests/types/tillegaltyperecursion2.nim b/tests/types/tillegaltyperecursion2.nim
new file mode 100644
index 000000000..c539a361d
--- /dev/null
+++ b/tests/types/tillegaltyperecursion2.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "illegal recursion in type 'Executor'"
+  line: 8
+"""
+# bug reported by PR #5637
+type
+  Executor[N] = Executor[N]
+var e: Executor[int]
diff --git a/tests/types/tillegaltyperecursion3.nim b/tests/types/tillegaltyperecursion3.nim
new file mode 100644
index 000000000..8e1138329
--- /dev/null
+++ b/tests/types/tillegaltyperecursion3.nim
@@ -0,0 +1,10 @@
+discard """
+errormsg: "illegal recursion in type 'Weird'"
+"""
+
+# issue #3456
+
+import tables
+type
+  Weird = ref seq[Weird]
+var t = newTable[int, Weird]()
diff --git a/tests/tillrec.nim b/tests/types/tillrec.nim
index 21ce19889..7584282b6 100755..100644
--- a/tests/tillrec.nim
+++ b/tests/types/tillrec.nim
@@ -1,10 +1,15 @@
-# test illegal recursive types

-

-type

-  TLegal {.final.} = object

-    x: int

-    kids: seq[TLegal]

-

-  TIllegal {.final.} = object  #ERROR_MSG illegal recursion in type 'TIllegal'

-    y: Int

-    x: array[0..3, TIllegal]

+discard """
+  errormsg: "illegal recursion in type \'TIllegal\'"
+  file: "tillrec.nim"
+  line: 13
+"""
+# test illegal recursive types
+
+type
+  TLegal {.final.} = object
+    x: int
+    kids: seq[TLegal]
+
+  TIllegal {.final.} = object  #ERROR_MSG illegal recursion in type 'TIllegal'
+    y: int
+    x: array[0..3, TIllegal]
diff --git a/tests/types/tinfiniterecursion.nim b/tests/types/tinfiniterecursion.nim
new file mode 100644
index 000000000..52eaaa93b
--- /dev/null
+++ b/tests/types/tinfiniterecursion.nim
@@ -0,0 +1,8 @@
+discard """
+  errormsg: "illegal recursion in type 'XIM'"
+  line: 8
+"""
+
+type
+  XIM* = ptr XIM
+  XIMProc* = proc (a2: XIM)
diff --git a/tests/types/tinheritgenericparameter.nim b/tests/types/tinheritgenericparameter.nim
new file mode 100644
index 000000000..d0d313635
--- /dev/null
+++ b/tests/types/tinheritgenericparameter.nim
@@ -0,0 +1,39 @@
+discard """
+  cmd: "nim check --hints:off --warnings:off $file"
+  action: "reject"
+  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 [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 [error]
+tinheritgenericparameter.nim(37, 23) Error: expression '' has no type (or is ambiguous)
+'''
+"""
+
+type
+  MyObject = object
+  HorzLayout[Base, T] = ref object of Base
+    data: seq[T]
+  VertLayout[T, Base] = ref object of Base
+    data: seq[T]
+  UiElement = ref object of RootObj
+    a: int
+  MyType[T] = ref object of RootObj
+    data: seq[T]
+  OtherElement[T] = ref object of T
+  Child[T] = ref object of HorzLayout[UiElement, T]
+  Child2[T] = ref object of VertLayout[T, UiElement]
+  Child3[T] = ref object of HorzLayout[MyObject, T]
+  Child4[T] = ref object of HorzLayout[int, T]
+static:
+  var a = Child[int](a: 300, data: @[100, 200, 300])
+  assert a.a == 300
+  assert a.data == @[100, 200, 300]
+discard Child2[string]()
+discard Child3[string]()
+discard Child4[string]()
+discard OtherElement[MyType[int]]()
+
diff --git a/tests/types/tinheritpartialgeneric.nim b/tests/types/tinheritpartialgeneric.nim
new file mode 100644
index 000000000..1845778bf
--- /dev/null
+++ b/tests/types/tinheritpartialgeneric.nim
@@ -0,0 +1,43 @@
+discard """
+  output: '''(c: "hello", a: 10, b: 12.0)
+(a: 15.5, b: "hello")
+(a: 11.75, b: 123)'''
+"""
+
+# bug #5231
+# generic object inheriting from
+# partial specialized generic object
+type
+  Curve1[T, X] = object of RootObj
+    a: T
+    b: X
+
+  Curve2[T] = Curve1[T, float64]
+
+  Curve3[T] = object of Curve2[T]
+    c: string
+
+  Curve4[T] = Curve1[float64, T]
+
+  Curve5[T] = object of Curve4[T]
+
+  Curve6[T] = object of T
+
+var x: Curve3[int]
+x.a = 10
+x.b = 12.0
+x.c = "hello"
+
+echo x
+
+var y: Curve5[string]
+y.b = "hello"
+y.a = 15.5
+
+echo y
+
+var z: Curve6[Curve4[int]]
+z.a = 11.75
+z.b = 123
+
+echo z
\ No newline at end of file
diff --git a/tests/types/tinheritref.nim b/tests/types/tinheritref.nim
new file mode 100644
index 000000000..c03e3bcab
--- /dev/null
+++ b/tests/types/tinheritref.nim
@@ -0,0 +1,83 @@
+# bug #554, #179
+
+type T[E] =
+  ref object
+    elem: E
+
+var ob: T[int]
+
+ob = T[int](elem: 23)
+
+doAssert ob.elem == 23
+
+type
+  TKeysIteratorA* = ref object of TTreeIteratorA  #compiles
+
+  TTreeIteratorA* {.inheritable.} = ref object
+
+  TTreeIterator* [T,D] {.inheritable.} = ref object
+
+  TKeysIterator* [T,D] = ref object of TTreeIterator[T,D]  #this not
+
+var
+  it: TKeysIterator[int, string] = nil
+
+#bug #5521
+type
+  Texture = enum
+    Smooth
+    Coarse
+
+  FruitBase = object of RootObj
+    color: int
+    case kind: Texture
+    of Smooth:
+      skin: float64
+    of Coarse:
+      grain: int
+
+  Apple = object of FruitBase
+    width: int
+    taste: float64
+
+var x = Apple(kind: Smooth, skin: 1.5)
+var u = x.skin
+
+doAssert u == 1.5
+
+type
+  BaseRef {.inheritable, pure.} = ref object
+    baseRef: int
+
+  SubRef = ref object of BaseRef
+
+  BasePtr {.inheritable, pure.} = ptr object
+    basePtr: int
+  SubPtr = ptr object of BasePtr
+
+  BaseObj {.inheritable, pure.} = object
+    baseObj: int
+
+  SubObj = object of BaseObj
+
+template baseObj[T](t: ptr T): untyped = T
+
+proc something123(): int =
+  var r : SubRef
+  r.new
+  var p : SubPtr
+  p = create(baseObj(p))
+  var r2 : ref BaseObj
+  r2.new
+
+  var accu = 0
+  # trigger code generation
+  accu += r.baseRef
+  accu += p.basePtr
+  accu += r2.baseObj
+
+  doAssert sizeof(r[]) == sizeof(int)
+  doAssert sizeof(baseObj(p)) == sizeof(int)
+  doAssert sizeof(r2[]) == sizeof(int)
+
+discard something123()
diff --git a/tests/types/tisopr.nim b/tests/types/tisopr.nim
new file mode 100644
index 000000000..c95b63c90
--- /dev/null
+++ b/tests/types/tisopr.nim
@@ -0,0 +1,171 @@
+discard """
+  output: '''true true false yes
+false
+true
+false
+true
+true
+yes'''
+"""
+
+proc IsVoid[T](): string =
+  when T is void:
+    result = "yes"
+  else:
+    result = "no"
+
+const x = int is int
+echo x, " ", float is float, " ", float is string, " ", IsVoid[void]()
+
+template yes(e): void =
+  static: assert e
+
+template no(e): void =
+  static: assert(not e)
+
+when false:
+  var s = @[1, 2, 3]
+
+  yes s.items is iterator
+  no  s.items is proc
+
+  yes s.items is iterator: int
+  no  s.items is iterator: float
+
+  yes s.items is iterator: TNumber
+  no  s.items is iterator: object
+
+  type
+    Iter[T] = iterator: T
+
+  yes s.items is Iter[TNumber]
+  no  s.items is Iter[float]
+
+type
+  Foo[N: static[int], T] = object
+    field: array[1..N, T]
+
+  Bar[T] = Foo[4, T]
+  Baz[N: static[int]] = Foo[N, float]
+
+no Foo[2, float] is Foo[3, float]
+no Foo[2, float] is Foo[2, int]
+
+yes Foo[4, string] is Foo[4, string]
+yes Bar[int] is Foo[4, int]
+yes Foo[4, int] is Bar[int]
+
+no Foo[4, int] is Baz[4]
+yes Foo[4, float] is Baz[4]
+
+
+# bug #2505
+
+echo(8'i8 is int32)
+
+# bug #1853
+type SeqOrSet[E] = seq[E] or set[E]
+type SeqOfInt = seq[int]
+type SeqOrSetOfInt = SeqOrSet[int]
+
+# This prints "true", as expected. Previously "false" was returned and that
+# seemed less correct that (1) printing "true" or (2) raising a compiler error.
+echo seq is SeqOrSet
+
+# This prints "false", as expected.
+echo seq is SeqOrSetOfInt
+
+# This prints "true", as expected.
+echo SeqOfInt is SeqOrSet
+
+# This causes an internal error (filename: compiler/semtypes.nim, line: 685).
+echo SeqOfInt is SeqOrSetOfInt
+
+# bug #2522
+proc test[T](x: T) =
+  when T is typedesc:
+    echo "yes"
+  else:
+    echo "no"
+
+test(7)
+
+block:
+  # bug #13066
+  type Bar[T1,T2] = object
+  type Foo[T1,T2] = object
+  type Foo2 = Foo
+  doAssert Foo2 is Foo
+  doAssert Foo is Foo2
+  doAssert Foo is Foo
+  doAssert Foo2 is Foo2
+  doAssert Foo2 isnot Bar
+  doAssert Foo[int,float] is Foo2[int,float]
+
+  # other
+  doAssert Foo[int,float] isnot Foo2[float,float]
+  doAssert Foo[int,float] is Foo2
+  doAssert Foo[int,float|int] is Foo2
+  doAssert Foo2[int,float|int] is Foo
+  doAssert Foo2[int,float|int] isnot Bar
+  doAssert int is (int|float)
+
+
+block:
+  # Slice[T] as static type issue
+  type
+    MyEnum = enum
+      x1, x2, x3, x4, x5, x6
+
+  proc enumGen[T: enum](s: static[Slice[T]]) = 
+    doAssert($s.a & "  " & $s.b == "x1  x3")
+
+  enumGen(x1..x3)
+
+block:
+  # issue #11142
+  type
+    MyObjParam[N: static int] = object
+      x: int
+
+    MyObj[P: static MyObjParam] = object
+      y: int
+
+  const P = MyObjParam[256](x: 2)
+  let Q = MyObj[P](y: 2)
+  doAssert($Q  == "(y: 2)")
+
+block: # previously tisop.nim
+  type
+    TRecord = (tuple) or (object)
+    TFoo[T, U] = object
+      x: int
+      when T is string:
+        y: float
+      else:
+        y: string
+      when U is TRecord:
+        z: float
+    E = enum A, B, C
+  template m(t: typedesc): typedesc =
+    when t is enum:
+      string
+    else:
+      int
+  var f: TFoo[int, int]
+  static: doAssert(typeof(f.y) is string)
+  when compiles(f.z):
+    {.error: "Foo should not have a `z` field".}
+  proc p(a, b: auto) =
+    when typeof(a) is int:
+      static: doAssert false
+    var f: TFoo[m(a.typeof), b.typeof]
+    static:
+      doAssert f.x.typeof is int
+      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/tissues_types.nim b/tests/types/tissues_types.nim
new file mode 100644
index 000000000..6bb1258f4
--- /dev/null
+++ b/tests/types/tissues_types.nim
@@ -0,0 +1,118 @@
+discard """
+  output: '''true
+true
+true
+true
+(member: "hello world")
+(member: 123.456)
+(member: "hello world", x: ...)
+(member: 123.456, x: ...)
+0
+false
+'''
+"""
+
+block t1252:
+  echo float32 isnot float64
+  echo float32 isnot float
+  echo int32 isnot int64
+  echo int32 isnot int
+
+block t5640:
+  type
+    vecBase[I: static[int]] = distinct array[I, float32]
+    vec2 = vecBase[2]
+
+  var v = vec2([0.0'f32, 0.0'f32])
+
+block t7581:
+  discard int -1
+
+block t7905:
+  template foobar(arg: typed): untyped =
+    type
+      MyType = object
+        member: type(arg)
+
+    var myVar: MyType
+    myVar.member = arg
+    echo myVar
+
+  foobar("hello world")
+  foobar(123.456'f64)
+
+  template foobarRec(arg: typed): untyped =
+    type
+      MyType = object
+        member: type(arg)
+        x: ref MyType
+
+    var myVar: MyType
+    myVar.member = arg
+    echo myVar
+
+  foobarRec("hello world")
+  foobarRec(123.456'f64)
+
+# bug #5170
+
+when true:
+  type Foo = object
+    bar: bool
+
+  type Bar = object
+    sameBody: string
+
+  var b0: Bar
+  b0.sameBody = "abc"
+
+block:
+  type Foo = object
+    baz: int
+
+  type Bar = object
+    sameBody: string
+
+  var b1: Bar
+  b1.sameBody = "def"
+
+  var f2: Foo
+  echo f2.baz
+
+var f1: Foo
+echo f1.bar
+
+import macros
+
+block: # issue #12582
+  macro foo(T: type): type =
+    nnkBracketExpr.newTree(bindSym "array", newLit 1, T)
+  var
+    _: foo(int) # fine
+  type
+    Foo = object
+      x: foo(int) # fine
+    Bar = ref object
+      x: foo(int) # error
+  let b = Bar()
+  let b2 = Bar(x: [123])
+
+block:
+  when true: # bug #14710
+    type Foo[T] = object
+      x1: int
+      when T.sizeof == 4: discard # SIGSEGV
+      when sizeof(T) == 4: discard # ok
+    let t = Foo[float](x1: 1)
+    doAssert t.x1 == 1
+
+block:
+  template s(d: varargs[typed])=discard
+
+  proc something(x:float)=discard
+  proc something(x:int)=discard
+  proc otherthing()=discard
+
+  s(something)
+  s(otherthing, something)
+  s(something, otherthing)
diff --git a/tests/types/titerable.nim b/tests/types/titerable.nim
new file mode 100644
index 000000000..fe27de4fd
--- /dev/null
+++ b/tests/types/titerable.nim
@@ -0,0 +1,143 @@
+discard """
+  targets: "c js"
+"""
+
+from stdtest/testutils import accept, reject, whenVMorJs
+
+# toSeq-like templates
+
+template toSeq2(a: iterable): auto =
+  var ret: seq[typeof(a)]
+  for ai in a: ret.add ai
+  ret
+
+template toSeq3(a: iterable[string]): auto =
+  var ret: seq[typeof(a)]
+  for ai in a: ret.add ai
+  ret
+
+template toSeq4[T](a: iterable[T]): auto =
+  var ret: seq[typeof(a)]
+  for ai in a: ret.add ai
+  ret
+
+template toSeq5[T: SomeInteger](a: iterable[T]): auto =
+  var ret: seq[typeof(a)]
+  for ai in a: ret.add ai
+  ret
+
+template toSeq6(a: iterable[int | float]): auto =
+  var ret: seq[typeof(a)]
+  for ai in a: ret.add ai
+  ret
+
+template toSeq7(a: iterable[seq]): auto =
+  var ret: seq[typeof(a)]
+  for ai in a: ret.add ai
+  ret
+
+template fn7b(a: untyped) = discard
+template fn7c(a: typed) = discard
+template fn7d(a: auto) = discard
+template fn7e[T](a: T) = discard
+
+template fn8a(a: iterable) = discard
+template fn8b[T](a: iterable[T]) = discard
+template fn8c(a: iterable[int]) = discard
+
+template bad1 =
+  template fn4(a: int, b: iterable[float, int]) =
+    discard
+
+template bad2 =
+  proc fn4(a: iterable) = discard
+
+template bad3 =
+  proc fn4(a: iterable[int]) = discard
+
+template good4 =
+  template fn1(a: iterable) = discard
+  template fn2(a: iterable[int]) = discard
+
+# iterators
+iterator iota(n: int): auto =
+  for i in 0..<n: yield i
+
+iterator repeat[T](a: T, n: int): T =
+  for i in 0..<n:
+    yield a
+
+iterator myiter(n: int): auto =
+  for i in 0..<n: yield $(i*2)
+
+when not defined(js):
+  iterator iotaClosure(n: int): auto {.closure.} =
+    for i in 0..<n: yield i
+
+template main() =
+  let expected1 = @[0, 1, 2]
+  let expected2 = @["0", "2"]
+
+  doAssert toSeq2(myiter(2)) == expected2
+  doAssert toSeq2(iota(3)) == expected1
+  doAssert toSeq2(1.1.repeat(2)) == @[1.1, 1.1]
+
+  whenVMorJs: discard
+  do:
+    doAssert toSeq2(iotaClosure(3)) == expected1
+
+  when true:
+    # MCS/UFCS
+    doAssert iota(3).toSeq2() == expected1
+
+  doAssert toSeq3(myiter(2)) == expected2
+  accept toSeq3(myiter(2))
+  reject toSeq3(iota(3))
+
+  doAssert toSeq4(iota(3)) == expected1
+  doAssert toSeq4(myiter(2)) == expected2
+  
+  doAssert toSeq4(0..2) == expected1
+  doAssert toSeq4(items(0..2)) == expected1
+  doAssert toSeq4(items(@[0,1,2])) == expected1
+  reject toSeq4(@[0,1,2])
+  reject toSeq4(13)
+
+  block:
+    accept fn8a(iota(3))
+    accept fn7b(iota(3))
+    reject fn7c(iota(3))
+    reject fn7d(iota(3))
+    reject fn7e(iota(3))
+
+  block:
+    fn8a(iota(3))
+    reject fn8a(123)
+    reject fn8c(123)
+    reject fn8c(123.3)
+    accept fn8c(items(@[1,2]))
+
+  block:
+    # shows that iterable is more restrictive than untyped
+    reject fn8a(nonexistent)
+    accept fn7b(nonexistent)
+    reject fn7c(nonexistent)
+    reject fn7d(nonexistent)
+    reject fn7e(nonexistent)
+
+  doAssert toSeq5(iota(3)) == expected1
+  reject toSeq5(myiter(2))
+
+  doAssert toSeq6(iota(3)) == expected1
+  reject toSeq6(myiter(2))
+
+  doAssert toSeq2("abc".repeat(3)) == @["abc", "abc", "abc"]
+  doAssert toSeq2(@['x', 'y'].repeat(2)) == @[@['x', 'y'], @['x', 'y']]
+
+  reject bad1
+  reject bad2
+  reject bad3
+  accept good4
+
+static: main()
+main()
diff --git a/tests/types/tlent_var.nim b/tests/types/tlent_var.nim
new file mode 100644
index 000000000..73b5bef9b
--- /dev/null
+++ b/tests/types/tlent_var.nim
@@ -0,0 +1,25 @@
+discard """
+  output: ''''''
+"""
+
+type
+  MyObj = object
+    a: int
+
+proc test_lent(x: MyObj): lent int =
+  x.a
+
+proc test_var(x: var MyObj): var int =
+  x.a
+
+var x = MyObj(a: 5)
+
+doAssert: test_var(x).addr == x.a.addr
+doAssert: test_lent(x).addr == x.a.addr
+
+proc varProc(x: var int) =
+  x = 100
+
+doAssert: not compiles(test_lent(x) = 1)
+doAssert: not compiles(varProc(test_lent(x)))
+
diff --git a/tests/types/tnontype.nim b/tests/types/tnontype.nim
new file mode 100644
index 000000000..4e2bafb32
--- /dev/null
+++ b/tests/types/tnontype.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "expected type, but got: 3"
+"""
+
+type
+  Foo = (block:
+    int)
+  
+  Bar = 3
diff --git a/tests/types/told_pragma_syntax1.nim b/tests/types/told_pragma_syntax1.nim
new file mode 100644
index 000000000..49823662d
--- /dev/null
+++ b/tests/types/told_pragma_syntax1.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "invalid indentation"
+"""
+
+type Foo = object {.final.}
diff --git a/tests/types/told_pragma_syntax2.nim b/tests/types/told_pragma_syntax2.nim
new file mode 100644
index 000000000..eea185725
--- /dev/null
+++ b/tests/types/told_pragma_syntax2.nim
@@ -0,0 +1,5 @@
+discard """
+  errormsg: "invalid indentation"
+"""
+
+type Bar {.final.} [T] = object
diff --git a/tests/types/tparameterizedparent0.nim b/tests/types/tparameterizedparent0.nim
new file mode 100644
index 000000000..90e7a9c0c
--- /dev/null
+++ b/tests/types/tparameterizedparent0.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "inheritance only works with non-final objects"
+  file: "tparameterizedparent0.nim"
+  line: 14
+"""
+# bug #5264
+type
+  Kapal* = enum
+    Besar
+
+  Apple[T] = object of T
+    color: int
+
+var x = Apple[Kapal](color: 13)
+echo x
diff --git a/tests/types/tparameterizedparent1.nim b/tests/types/tparameterizedparent1.nim
new file mode 100644
index 000000000..5da8189f4
--- /dev/null
+++ b/tests/types/tparameterizedparent1.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "inheritance only works with non-final objects"
+  file: "tparameterizedparent1.nim"
+  line: 14
+"""
+# bug #5264
+type
+  FruitBase = object
+    color: int
+
+  Apple[T] = object of T
+    width: int
+
+var x: Apple[FruitBase]
diff --git a/tests/types/tparameterizedparent2.nim b/tests/types/tparameterizedparent2.nim
new file mode 100644
index 000000000..e96b9edbe
--- /dev/null
+++ b/tests/types/tparameterizedparent2.nim
@@ -0,0 +1,77 @@
+discard """
+  output: '''(width: 11, color: 13)
+(width: 15, weight: 13, taste: 11, color: 14)
+(width: 17, color: 16)
+(width: 12.0, taste: "yummy", color: 13)
+(width: 0, tast_e: 0.0, kind: Smooth, skin: 1.5, color: 12)'''
+"""
+# bug #5264
+type
+  Texture = enum
+    Smooth
+    Coarse
+
+  FruitBase = object of RootObj
+    color: int
+
+  Level2Fruit = object of FruitBase
+    taste: int
+
+  AppleBanana = object of Level2Fruit
+    weight: int
+
+  BaseFruit[T] = object of RootObj
+    color: T
+
+  Apple[T] = object of T
+    width: int
+
+  Peach[X, T, Y] = object of T
+    width: X
+    taste: Y
+
+  Lemon[T] = object of T
+    width: int
+    tast_e: float64
+    case kind: Texture
+    of Smooth:
+      skin: float64
+    of Coarse:
+      grain: int
+
+var x: Apple[FruitBase]
+x.color = 13
+x.width = 11
+echo x
+
+proc setColor(self: var FruitBase, c: int) =
+  self.color = c
+
+proc setTaste[T](self: var Apple[T], c: int) =
+  self.taste = c
+
+#proc setColor[T](self: var BaseFruit[T], c: int) =
+#  self.color = c
+
+var y: Apple[AppleBanana]
+y.setColor(14)
+y.setTaste(11)
+y.weight = 13
+y.width = 15
+echo y
+
+var w: Apple[BaseFruit[int]]
+w.width = 17
+w.color = 16
+echo w
+
+var z: Peach[float64, BaseFruit[int], string]
+z.width = 12
+z.taste = "yummy"
+#z.setColor(13) #this trigger other bug
+z.color = 13
+echo z
+
+var k = Lemon[FruitBase](kind: Smooth, skin: 1.5)
+k.setColor(12)
+echo k
diff --git a/tests/types/tparameterizedparent3.nim b/tests/types/tparameterizedparent3.nim
new file mode 100644
index 000000000..fcca6453e
--- /dev/null
+++ b/tests/types/tparameterizedparent3.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "attempt to redefine: 'color'"
+  file: "tparameterizedparent3.nim"
+  line: 13
+"""
+# bug #5264
+type
+  FruitBase = object of RootObj
+    color: int
+
+  Apple[T] = object of T
+    width: int
+    color: int
+
+var x: Apple[FruitBase]
diff --git a/tests/types/tparameterizedparent4.nim b/tests/types/tparameterizedparent4.nim
new file mode 100644
index 000000000..4759d9d9b
--- /dev/null
+++ b/tests/types/tparameterizedparent4.nim
@@ -0,0 +1,30 @@
+discard """
+  errormsg: "attempt to redefine: 'grain'"
+  file: "tparameterizedparent4.nim"
+  line: 23
+"""
+# bug #5264
+type
+  Texture = enum
+    Smooth
+    Coarse
+
+  FruitBase = object of RootObj
+    color: int
+    grain: string
+
+  Apple[T] = object of T
+    width: int
+    tast_e: float64
+    case kind: Texture
+    of Smooth:
+      skin: float64
+    of Coarse:
+      grain: int
+
+proc setColor(self: var FruitBase, c: int) =
+  self.color = c
+
+var x = Apple[FruitBase](kind: Smooth, skin: 1.5)
+x.setColor(14)
+echo x
diff --git a/tests/types/ttopdowninference.nim b/tests/types/ttopdowninference.nim
new file mode 100644
index 000000000..765761e99
--- /dev/null
+++ b/tests/types/ttopdowninference.nim
@@ -0,0 +1,333 @@
+block:
+  var s: seq[string] = (discard; @[])
+
+  var x: set[char] =
+    if true:
+      try:
+        case 1
+        of 1:
+          if false:
+            {'4'}
+          else:
+            block:
+              s.add "a"
+              {}
+        else: {'3'}
+      except: {'2'}
+    else: {'1'}
+  doAssert x is set[char]
+  doAssert x == {}
+  doAssert s == @["a"]
+
+  x = {'a', 'b'}
+  doAssert x == {'a', 'b'}
+
+  x = (s.add "b"; {})
+  doAssert x == {}
+  doAssert s == @["a", "b"]
+
+  let x2: set[byte] = {1}
+  doAssert x2 == {1u8}
+
+block:
+  let x3: array[0..2, byte] = [1, 2, 3]
+  #let x4: openarray[byte] = [1, 2, 3]
+  #let x5: openarray[byte] = @[1, 2, 3]
+  let x6: seq[byte] = @[1, 2, 3]
+  let x7: seq[seq[float32]] = @[@[1, 2, 3], @[4.3, 5, 6]]
+  type ABC = enum a, b, c
+  let x8: array[ABC, byte] = [1, 2, 3]
+  doAssert x8[a] == 1
+  doAssert x8[a] + x8[b] == x8[c]
+
+  const x9: array[-2..2, float] = [0, 1, 2, 3, 4]
+  let x10: array[ABC, byte] = block:
+    {.gcsafe.}:
+      [a: 1, b: 2, c: 3]
+  proc `@`(x: float): float = x + 1
+  doAssert @1 == 2
+  let x11: seq[byte] = system.`@`([1, 2, 3])
+
+block:
+  type Foo = object
+    x: BiggestInt
+  var foo: Foo
+  foo.x = case true
+  of true: ord(1)
+  else: 0
+  foo.x = if true: ord(1) else: 0
+
+block:
+  type Foo = object
+    x: (float, seq[(byte, seq[byte])])
+    
+  let foo = Foo(x: (1, @{2: @[], 3: @[4, 5]}))
+  doAssert foo.x == (1.0, @{2u8: @[], 3u8: @[4u8, 5]})
+
+block:
+  type Foo = object
+    x: tuple[a: float, b: seq[(byte, seq[byte])]]
+    
+  let foo = Foo(x: (a: 1, b: @{2: @[3, 4], 5: @[]}))
+  doAssert foo.x == (1.0, @{2u8: @[3u8, 4], 5u8: @[]})
+
+block:
+  proc foo(): seq[float] = @[1]
+
+  let fooLamb = proc(): seq[float] = @[1]
+
+  doAssert foo() == fooLamb()
+
+block:
+  type Foo[T] = float32
+
+  let x: seq[Foo[int32]] = @[1]
+
+block:
+  type Foo = ref object
+  type Bar[T] = ptr object
+
+  let x1: seq[Foo] = @[nil]
+  let x2: seq[Bar[int]] = @[nil]
+  let x3: seq[cstring] = @[nil]
+
+block:
+  let x: seq[cstring] = @["abc", nil, "def"]
+  doAssert x.len == 3
+  doAssert x[0] == cstring"abc"
+  doAssert x[1].isNil
+  doAssert x[2] == "def".cstring
+
+block:
+  type Foo = object
+    x: tuple[a: float, b: seq[(byte, seq[cstring])]]
+    
+  let foo = Foo(x: (a: 1, b: @{2: @[nil, "abc"]}))
+  doAssert foo.x == (1.0, @{2u8: @[cstring nil, cstring "abc"]})
+
+block:
+  type Foo = object
+    x: tuple[a: float, b: seq[(byte, seq[ptr int])]]
+    
+  let foo = Foo(x: (a: 1, b: @{2: @[nil, nil]}))
+  doAssert foo.x == (1.0, @{2u8: @[(ptr int)(nil), nil]})
+
+when false: # unsupported
+  block: # type conversion
+    let x = seq[(cstring, float32)](@{"abc": 1.0, "def": 2.0})
+    doAssert x[0] == (cstring"abc", 1.0'f32)
+    doAssert x[1] == (cstring"def", 2.0'f32)
+
+block: # enum
+  type Foo {.pure.} = enum a
+  type Bar {.pure.} = enum a, b, c
+
+  var s: seq[Bar] = @[a, b, c]
+
+block: # overload selection
+  proc foo(x, y: int): int = x + y + 1
+  proc foo(x: int): int = x - 1
+  var s: seq[proc (x, y: int): int] = @[nil, foo, foo]
+  var s2: seq[int]
+  for a in s:
+    if not a.isNil: s2.add(a(1, 2))
+  doAssert s2 == @[4, 4]
+
+block: # with generics?
+  proc foo(x, y: int): int = x + y + 1
+  proc foo(x: int): int = x - 1
+  proc bar[T](x, y: T): T = x - y
+  var s: seq[proc (x, y: int): int] = @[nil, foo, foo, bar]
+  var s2: seq[int]
+  for a in s:
+    if not a.isNil: s2.add(a(1, 2))
+  doAssert s2 == @[4, 4, -1]
+  proc foo(x, y: float): float = x + y + 1.0
+  var s3: seq[proc (x, y: float): float] = @[nil, foo, foo, bar]
+  var s4: seq[float]
+  for a in s3:
+    if not a.isNil: s4.add(a(1, 2))
+  doAssert s4 == @[4.0, 4, -1]
+
+block: # range types
+  block:
+    let x: set[range[1u8..5u8]] = {1, 3}
+    doAssert x == {range[1u8..5u8](1), 3}
+    doAssert $x == "{1, 3}"
+  block:
+    let x: seq[set[range[1u8..5u8]]] = @[{1, 3}]
+    doAssert x == @[{range[1u8..5u8](1), 3}]
+    doAssert $x[0] == "{1, 3}"
+  block:
+    let x: seq[range[1u8..5u8]] = @[1, 3]
+    doAssert x == @[range[1u8..5u8](1), 3]
+    doAssert $x == "@[1, 3]"
+  block: # already worked before, make sure it still works
+    let x: set[range['a'..'e']] = {'a', 'c'}
+    doAssert x == {range['a'..'e']('a'), 'c'}
+    doAssert $x == "{'a', 'c'}"
+  block: # extended
+    let x: seq[set[range['a'..'e']]] = @[{'a', 'c'}]
+    doAssert x[0] == {range['a'..'e']('a'), 'c'}
+    doAssert $x == "@[{'a', 'c'}]"
+  block:
+    type Foo = object
+      x: (range[1u8..5u8], seq[(range[1f32..5f32], seq[range['a'..'e']])])
+      
+    let foo = Foo(x: (1, @{2: @[], 3: @['c', 'd']}))
+    doAssert foo.x == (range[1u8..5u8](1u8), @{range[1f32..5f32](2f32): @[], 3f32: @[range['a'..'e']('c'), 'd']})
+  block:
+    type Foo = object
+      x: (range[1u8..5u8], seq[(range[1f32..5f32], seq[set[range['a'..'e']]])])
+      
+    let foo = Foo(x: (1, @{2: @[], 3: @[{'c', 'd'}]}))
+    doAssert foo.x == (range[1u8..5u8](1u8), @{range[1f32..5f32](2f32): @[], 3f32: @[{range['a'..'e']('c'), 'd'}]})
+
+block: # templates
+  template foo: untyped = (1, 2, "abc")
+  let x: (float, byte, cstring) = foo()
+  doAssert x[0] == float(1)
+  doAssert x[1] == byte(2)
+  doAssert x[2] == cstring("abc")
+  let (a, b, c) = x
+  doAssert a == float(1)
+  doAssert b == byte(2)
+  doAssert c == cstring("abc")
+
+
+proc foo(): set[char] = # bug #11259
+  discard "a"
+  {}
+
+discard foo()
+
+block: # bug #11085
+  const ok1: set[char] = {}
+  var ok1b: set[char] = {}
+
+  const ok2: set[char] = block:
+    {}
+
+  const ok3: set[char] = block:
+    var x: set[char] = {}
+    x
+  var ok3b: set[char] = block:
+    var x: set[char] = {}
+    x
+
+  var bad: set[char] = block:
+    {}
+
+# bug #6213
+block:
+  block:
+    type MyEnum = enum a, b
+    type MyTuple = tuple[x: set[MyEnum]]
+
+    var myVar: seq[MyTuple] = @[ (x: {}) ]
+    doAssert myVar.len == 1
+
+  block:
+    type
+      Foo = tuple
+        f: seq[string]
+        s: string
+
+    proc e(): seq[Foo] =
+      return @[
+        (@[], "asd")
+      ]
+
+    doAssert e()[0].f == @[]
+
+block: # bug #11777
+  type S = set[0..5]
+  var s: S = {1, 2}
+  doAssert 1 in s
+
+block: # bug #20807
+  var s: seq[string]
+  template fail =
+    s = @[]
+  template test(body: untyped) =
+    body
+  proc test(a: string) = discard
+  test: fail()
+  doAssert not (compiles do:
+    let x: seq[int] = `@`[string]([]))
+
+block: # bug #21377
+  proc b[T](v: T): seq[int] =
+    let x = 0
+    @[]
+
+  doAssert b(0) == @[]
+
+block: # bug #21377
+  proc b[T](v: T): seq[T] =
+    let x = 0
+    @[]
+
+  doAssert b(0) == @[]
+
+block: # bug #21377
+  proc b[T](v: T): set[bool] =
+    let x = 0
+    {}
+
+  doAssert b(0) == {}
+
+block: # bug #21377
+  proc b[T](v: T): array[0, int] =
+    let x = 0
+    []
+
+  doAssert b(0) == []
+
+block: # bug #21377
+  proc b[T](v: T): array[0, (string, string)] =
+    let x = 0
+    {:}
+
+  doAssert b(0) == {:}
+
+block: # bug #22180
+  type A = object
+  proc j() = discard
+
+  let x =
+    if false:
+      (ref A)(nil)
+    else:
+      if false:
+        quit 1
+      else:
+        if true:
+          j()
+          nil  # compiles with (ref A)(nil) here
+        else:
+          (ref A)(nil)
+  doAssert x.isNil
+  
+  let y =
+    case true
+    of false:
+      (ref A)(nil)
+    else:
+      case true
+      of false:
+        quit 1
+      else:
+        case true
+        of true:
+          j()
+          nil  # compiles with (ref A)(nil) here
+        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/types/tyet_another_generic_regression.nim b/tests/types/tyet_another_generic_regression.nim
new file mode 100644
index 000000000..2e5f9bb23
--- /dev/null
+++ b/tests/types/tyet_another_generic_regression.nim
@@ -0,0 +1,41 @@
+discard """
+  output: ''''''
+"""
+
+import system
+
+type Bar[T] = ref object
+ value: T
+
+type types = int32|int64 # if I change this to just int32 or int64 it works (compiles)
+
+# if I replace Bar everywhere with seq it also compiles fine
+proc Foo[T: Bar[types]](): T =
+ when T is Bar: nil
+
+discard Foo[Bar[int32]]()
+#bug #6073
+
+# bug #11479
+
+import tables
+
+proc test() =
+  discard readfile("temp.nim")
+  echo "ho"
+
+const
+  map = {
+    "test": test,
+  }.toTable
+
+#map["test"]()
+
+#-------------------------------------------------------------------
+# bug
+const val = 10
+ 
+type 
+  t = object
+    when val >= 10:
+      a: int
diff --git a/tests/typredef.nim b/tests/typredef.nim
deleted file mode 100755
index a77d91f40..000000000
--- a/tests/typredef.nim
+++ /dev/null
@@ -1,3 +0,0 @@
-type

-  Uint8 = Uint8 #ERROR_MSG illegal recursion in type 'Uint8'

-

diff --git a/tests/untestable/gdb/gdb_pretty_printer_test.py b/tests/untestable/gdb/gdb_pretty_printer_test.py
new file mode 100644
index 000000000..aed0cfeb0
--- /dev/null
+++ b/tests/untestable/gdb/gdb_pretty_printer_test.py
@@ -0,0 +1,64 @@
+import gdb
+import re
+import sys
+# this test should test the gdb pretty printers of the nim
+# library. But be aware this test is not complete. It only tests the
+# command line version of gdb. It does not test anything for the
+# machine interface of gdb. This means if if this test passes gdb
+# frontends might still be broken.
+
+gdb.execute("set python print-stack full")
+gdb.execute("source ../../../tools/debug/nim-gdb.py")
+# debug all instances of the generic function `myDebug`, should be 14
+gdb.execute("rbreak myDebug")
+gdb.execute("run")
+
+outputs = [
+  'meTwo',
+  '""',
+  '"meTwo"',
+  '{meOne, meThree}',
+  'MyOtherEnum(1)',
+  '{MyOtherEnum(0), MyOtherEnum(2)}',
+  'array = {1, 2, 3, 4, 5}',
+  'seq(0, 0)',
+  'seq(0, 10)',
+  'array = {"one", "two"}',
+  'seq(3, 3) = {1, 2, 3}',
+  'seq(3, 3) = {"one", "two", "three"}',
+  'Table(3, 64) = {[4] = "four", [5] = "five", [6] = "six"}',
+  'Table(3, 8) = {["two"] = 2, ["three"] = 3, ["one"] = 1}',
+  '{a = 1, b = "some string"}',
+  '("hello", 42)'
+]
+
+argRegex = re.compile("^.* = (?:No suitable Nim \$ operator found for type: \w+\s*)*(.*)$")
+# Remove this error message which can pop up
+noSuitableRegex = re.compile("(No suitable Nim \$ operator found for type: \w+\s*)")
+
+for i, expected in enumerate(outputs):
+  gdb.write(f"\x1b[38;5;105m{i+1}) expecting: {expected}: \x1b[0m", gdb.STDLOG)
+  gdb.flush()
+  currFrame = gdb.selected_frame()
+  functionSymbol = currFrame.block().function
+  assert functionSymbol.line == 24, str(functionSymbol.line)
+  raw = ""
+  if i == 6:
+    # myArray is passed as pointer to int to myDebug. I look up myArray up in the stack
+    gdb.execute("up")
+    raw = gdb.parse_and_eval("myArray")    
+  elif i == 9:
+    # myOtherArray is passed as pointer to int to myDebug. I look up myOtherArray up in the stack
+    gdb.execute("up")
+    raw = gdb.parse_and_eval("myOtherArray")
+  else:
+    rawArg = re.sub(noSuitableRegex, "", gdb.execute("info args", to_string = True))
+    raw = rawArg.split("=", 1)[-1].strip()
+  output = str(raw)
+
+  if output != expected:
+    gdb.write(f"\x1b[38;5;196m ({output}) != expected: ({expected})\x1b[0m\n", gdb.STDERR)
+    gdb.execute("quit 1")
+  else:
+    gdb.write("\x1b[38;5;34mpassed\x1b[0m\n", gdb.STDLOG)
+  gdb.execute("continue")
diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_program.nim b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim
new file mode 100644
index 000000000..163c99860
--- /dev/null
+++ b/tests/untestable/gdb/gdb_pretty_printer_test_program.nim
@@ -0,0 +1,89 @@
+
+
+import tables
+
+type
+  MyEnum = enum
+    meOne,
+    meTwo,
+    meThree,
+    meFour,
+
+  MyOtherEnum = enum
+    moOne,
+    moTwo,
+    moThree,
+    moFoure,
+  
+  MyObj = object
+    a*: int
+    b*: string
+
+var counter = 0
+
+proc myDebug[T](arg: T): void =
+  counter += 1
+
+proc testProc(): void =
+  var myEnum = meTwo
+  myDebug(myEnum) #1
+  
+  # create a string, but don't allocate it
+  var myString: string
+  myDebug(myString) #2
+
+  # create a string object but also make the NTI for MyEnum is generated
+  myString = $myEnum
+  myDebug(myString) #3
+  
+  var mySet = {meOne,meThree}
+  myDebug(mySet) #4
+
+  # for MyOtherEnum there is no NTI. This tests the fallback for the pretty printer.
+  var moEnum = moTwo
+  myDebug(moEnum) #5
+
+  var moSet = {moOne,moThree}
+  myDebug(moSet) #6
+
+  let myArray = [1,2,3,4,5]
+  myDebug(myArray) #7
+
+  # implicitly initialized seq test
+  var mySeq: seq[string]
+  myDebug(mySeq) #8
+
+  # len not equal to capacity
+  let myOtherSeq = newSeqOfCap[string](10)
+  myDebug(myOtherSeq) #9
+
+  let myOtherArray = ["one","two"]
+  myDebug(myOtherArray) #10
+
+  # numeric sec
+  var mySeq3 = @[1,2,3]
+  myDebug(mySeq3) #11
+
+  # seq had to grow
+  var mySeq4 = @["one","two","three"]
+  myDebug(mySeq4) #12
+
+  var myTable = initTable[int, string]()
+  myTable[4] = "four"
+  myTable[5] = "five"
+  myTable[6] = "six"
+  myDebug(myTable) #13
+
+  var myOtherTable = {"one": 1, "two": 2, "three": 3}.toTable
+  myDebug(myOtherTable) #14
+
+  var obj = MyObj(a: 1, b: "some string")
+  myDebug(obj) #15
+
+  var tup = ("hello", 42)
+  myDebug(tup) # 16
+
+  assert counter == 16
+
+
+testProc()
diff --git a/tests/untestable/gdb/gdb_pretty_printer_test_run.sh b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh
new file mode 100755
index 000000000..411c68435
--- /dev/null
+++ b/tests/untestable/gdb/gdb_pretty_printer_test_run.sh
@@ -0,0 +1,13 @@
+#!/usr/bin/env bash
+set -e
+# Compile the test project with fresh debug information.
+nim c --debugger:native --mm:orc --out:gdbNew gdb_pretty_printer_test_program.nim
+echo "Running new runtime tests..."
+# 2>&1 redirects stderr to stdout (all output in stdout)
+gdb -x gdb_pretty_printer_test.py --batch-silent --args gdbNew 2>&1
+
+
+# Do it all again, but with old runtime
+nim c --debugger:native --mm:refc --out:gdbOld gdb_pretty_printer_test_program.nim &> /dev/null
+echo "Running old runtime tests"
+gdb -x gdb_pretty_printer_test.py --batch-silent --args gdbOld 2>&1
diff --git a/tests/untestable/network/README.md b/tests/untestable/network/README.md
new file mode 100644
index 000000000..173cf105f
--- /dev/null
+++ b/tests/untestable/network/README.md
@@ -0,0 +1,8 @@
+This directory contains tests that require networking and cannot be run in CI.
+
+The tests can be run manually during development using:
+```nim
+./koch tests cat untestable/network/stdlib
+```
+
+The directory structure mimics tests/
diff --git a/tests/untestable/network/stdlib/tnet.nim b/tests/untestable/network/stdlib/tnet.nim
new file mode 100644
index 000000000..cb0f38944
--- /dev/null
+++ b/tests/untestable/network/stdlib/tnet.nim
@@ -0,0 +1,16 @@
+discard """
+outputsub: ""
+"""
+
+import net, nativesockets
+import unittest
+
+suite "getPrimaryIPAddr":
+  test "localhost v4":
+    check getPrimaryIPAddr(parseIpAddress("127.0.0.1")) == parseIpAddress("127.0.0.1")
+
+  test "localhost v6":
+    check getPrimaryIPAddr(parseIpAddress("::1")) == parseIpAddress("::1")
+
+  test "v4":
+    check getPrimaryIPAddr() != parseIpAddress("127.0.0.1")
diff --git a/tests/untestable/readme.markdown b/tests/untestable/readme.markdown
new file mode 100644
index 000000000..de1ba9459
--- /dev/null
+++ b/tests/untestable/readme.markdown
@@ -0,0 +1,9 @@
+This directory contains integration tests which are not automatically executed
+for various reasons:
+- dependency on external services
+- dependency on files / configuration / state of the local host
+- tests that are extremely slow or require large amounts of memory or storage
+- tests that spawn local daemons
+
+Integration tests can become stale very quickly. Automated ./koch tests are
+strongly recommended.
diff --git a/tests/untestable/thttpclient_ssl_disabled.nim b/tests/untestable/thttpclient_ssl_disabled.nim
new file mode 100644
index 000000000..b95dad2c6
--- /dev/null
+++ b/tests/untestable/thttpclient_ssl_disabled.nim
@@ -0,0 +1,36 @@
+#
+#            Nim - SSL integration tests
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Compile and run with:
+## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:nimDisableCertificateValidation -d:ssl -p:. tests/untestable/thttpclient_ssl_disabled.nim
+
+from stdtest/testutils import enableRemoteNetworking
+when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(openbsd)):
+  import httpclient, net, unittest
+
+  const expired = "https://expired.badssl.com/"
+
+  doAssert defined(nimDisableCertificateValidation)
+
+  suite "SSL certificate check - disabled":
+
+    test "httpclient in insecure mode":
+      var ctx = newContext(verifyMode = CVerifyPeer)
+      var client = newHttpClient(sslContext = ctx)
+      let a = $client.getContent(expired)
+
+    test "httpclient in insecure mode":
+      var ctx = newContext(verifyMode = CVerifyPeerUseEnvVars)
+      var client = newHttpClient(sslContext = ctx)
+      let a = $client.getContent(expired)
+
+    test "net socket in insecure mode":
+      var sock = newSocket()
+      var ctx = newContext(verifyMode = CVerifyPeerUseEnvVars)
+      ctx.wrapSocket(sock)
+      sock.connect("expired.badssl.com", 443.Port)
+      sock.close
diff --git a/tests/untestable/thttpclient_ssl_env_var.nim b/tests/untestable/thttpclient_ssl_env_var.nim
new file mode 100644
index 000000000..3f25a6ff4
--- /dev/null
+++ b/tests/untestable/thttpclient_ssl_env_var.nim
@@ -0,0 +1,74 @@
+#
+#            Nim - SSL integration tests
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Warning: this test performs external networking.
+## Compile with:
+## ./bin/nim c -d:ssl -p:. tests/untestable/thttpclient_ssl_env_var.nim
+##
+## Test with:
+##  SSL_CERT_FILE=BogusInexistentFileName tests/untestable/thttpclient_ssl_env_var
+##  SSL_CERT_DIR=BogusInexistentDirName tests/untestable/thttpclient_ssl_env_var
+
+import httpclient, unittest, os
+from net import newSocket, newContext, wrapSocket, connect, close, Port,
+  CVerifyPeerUseEnvVars
+from strutils import contains
+
+const
+  expired = "https://expired.badssl.com/"
+  good = "https://google.com/"
+
+
+suite "SSL certificate check":
+
+  test "httpclient with inexistent file":
+    if existsEnv("SSL_CERT_FILE"):
+      var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars)
+      var client = newHttpClient(sslContext=ctx)
+      checkpoint("Client created")
+      check client.getContent("https://google.com").contains("doctype")
+      checkpoint("Google ok")
+      try:
+        let a = $client.getContent(good)
+        echo "Connection should have failed"
+        fail()
+      except:
+        echo getCurrentExceptionMsg()
+        check getCurrentExceptionMsg().contains("certificate verify failed")
+
+    elif existsEnv("SSL_CERT_DIR"):
+      try:
+        var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars)
+        var client = newHttpClient(sslContext=ctx)
+        echo "Should have raised 'No SSL/TLS CA certificates found.'"
+        fail()
+      except:
+        check getCurrentExceptionMsg() ==
+          "No SSL/TLS CA certificates found."
+
+  test "net socket with inexistent file":
+    if existsEnv("SSL_CERT_FILE"):
+      var sock = newSocket()
+      var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars)
+      ctx.wrapSocket(sock)
+      checkpoint("Socket created")
+      try:
+        sock.connect("expired.badssl.com", 443.Port)
+        fail()
+      except:
+        sock.close
+        check getCurrentExceptionMsg().contains("certificate verify failed")
+
+    elif existsEnv("SSL_CERT_DIR"):
+      var sock = newSocket()
+      checkpoint("Socket created")
+      try:
+        var ctx = newContext(verifyMode=CVerifyPeerUseEnvVars) # raises here
+        fail()
+      except:
+        check getCurrentExceptionMsg() ==
+          "No SSL/TLS CA certificates found."
diff --git a/tests/untestable/thttpclient_ssl_remotenetwork.nim b/tests/untestable/thttpclient_ssl_remotenetwork.nim
new file mode 100644
index 000000000..3cb759516
--- /dev/null
+++ b/tests/untestable/thttpclient_ssl_remotenetwork.nim
@@ -0,0 +1,230 @@
+#
+#
+#            Nim - SSL integration tests
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Test with:
+## nim r --putenv:NIM_TESTAMENT_REMOTE_NETWORKING:1 -d:ssl -p:. --threads:on tests/untestable/thttpclient_ssl_remotenetwork.nim
+##
+## See https://github.com/FedericoCeratto/ssl-comparison/blob/master/README.md
+## for a comparison with other clients.
+
+from stdtest/testutils import enableRemoteNetworking
+when enableRemoteNetworking and (defined(nimTestsEnableFlaky) or not defined(windows) and not defined(openbsd)):
+  # Not supported on Windows due to old openssl version
+  import
+    httpclient,
+    net,
+    strutils,
+    threadpool,
+    unittest
+
+
+  type
+    # bad and dubious tests should not pass SSL validation
+    # "_broken" mark the test as skipped. Some tests have different
+    # behavior depending on OS and SSL version!
+    # TODO: chase and fix the broken tests
+    Category = enum
+      good, bad, dubious, good_broken, bad_broken, dubious_broken
+    CertTest = tuple[url:string, category:Category, desc: string]
+
+  # badssl certs sometimes expire, set to false when that happens
+  when true:
+    const certificate_tests: array[0..54, CertTest] = [
+      ("https://wrong.host.badssl.com/", bad, "wrong.host"),
+      ("https://captive-portal.badssl.com/", bad, "captive-portal"),
+      ("https://expired.badssl.com/", bad, "expired"),
+      ("https://google.com/", good, "good"),
+      ("https://self-signed.badssl.com/", bad, "self-signed"),
+      ("https://untrusted-root.badssl.com/", bad, "untrusted-root"),
+      ("https://revoked.badssl.com/", bad_broken, "revoked"),
+      ("https://pinning-test.badssl.com/", bad_broken, "pinning-test"),
+      ("https://no-common-name.badssl.com/", bad, "no-common-name"),
+      ("https://no-subject.badssl.com/", bad, "no-subject"),
+      ("https://sha1-intermediate.badssl.com/", bad, "sha1-intermediate"),
+      ("https://sha256.badssl.com/", good, "sha256"),
+      ("https://sha384.badssl.com/", bad, "sha384"),
+      ("https://sha512.badssl.com/", bad, "sha512"),
+      ("https://1000-sans.badssl.com/", bad, "1000-sans"),
+      ("https://10000-sans.badssl.com/", good_broken, "10000-sans"),
+      ("https://ecc256.badssl.com/", good_broken, "ecc256"),
+      ("https://ecc384.badssl.com/", good_broken, "ecc384"),
+      ("https://rsa2048.badssl.com/", good, "rsa2048"),
+      ("https://rsa8192.badssl.com/", dubious_broken, "rsa8192"),
+      ("http://http.badssl.com/", good, "regular http"),
+      ("https://http.badssl.com/", bad_broken, "http on https URL"),  # FIXME
+      ("https://cbc.badssl.com/", dubious, "cbc"),
+      ("https://rc4-md5.badssl.com/", bad, "rc4-md5"),
+      ("https://rc4.badssl.com/", bad, "rc4"),
+      ("https://3des.badssl.com/", bad, "3des"),
+      ("https://null.badssl.com/", bad, "null"),
+      ("https://mozilla-old.badssl.com/", bad_broken, "mozilla-old"),
+      ("https://mozilla-intermediate.badssl.com/", dubious_broken, "mozilla-intermediate"),
+      ("https://mozilla-modern.badssl.com/", good, "mozilla-modern"),
+      ("https://dh480.badssl.com/", bad, "dh480"),
+      ("https://dh512.badssl.com/", bad, "dh512"),
+      ("https://dh1024.badssl.com/", dubious_broken, "dh1024"),
+      ("https://dh2048.badssl.com/", good, "dh2048"),
+      ("https://dh-small-subgroup.badssl.com/", bad_broken, "dh-small-subgroup"),
+      ("https://dh-composite.badssl.com/", bad_broken, "dh-composite"),
+      ("https://static-rsa.badssl.com/", dubious, "static-rsa"),
+      ("https://tls-v1-0.badssl.com:1010/", dubious, "tls-v1-0"),
+      ("https://tls-v1-1.badssl.com:1011/", dubious, "tls-v1-1"),
+      ("https://invalid-expected-sct.badssl.com/", bad, "invalid-expected-sct"),
+      ("https://hsts.badssl.com/", good, "hsts"),
+      ("https://upgrade.badssl.com/", good, "upgrade"),
+      ("https://preloaded-hsts.badssl.com/", good, "preloaded-hsts"),
+      ("https://subdomain.preloaded-hsts.badssl.com/", bad, "subdomain.preloaded-hsts"),
+      ("https://https-everywhere.badssl.com/", good, "https-everywhere"),
+      ("https://long-extended-subdomain-name-containing-many-letters-and-dashes.badssl.com/", good,
+        "long-extended-subdomain-name-containing-many-letters-and-dashes"),
+      ("https://longextendedsubdomainnamewithoutdashesinordertotestwordwrapping.badssl.com/", good,
+        "longextendedsubdomainnamewithoutdashesinordertotestwordwrapping"),
+      ("https://superfish.badssl.com/", bad, "(Lenovo) Superfish"),
+      ("https://edellroot.badssl.com/", bad, "(Dell) eDellRoot"),
+      ("https://dsdtestprovider.badssl.com/", bad, "(Dell) DSD Test Provider"),
+      ("https://preact-cli.badssl.com/", bad, "preact-cli"),
+      ("https://webpack-dev-server.badssl.com/", bad, "webpack-dev-server"),
+      ("https://mitm-software.badssl.com/", bad, "mitm-software"),
+      ("https://sha1-2016.badssl.com/", dubious, "sha1-2016"),
+      ("https://sha1-2017.badssl.com/", bad, "sha1-2017"),
+    ]
+  else:
+    const certificate_tests: array[0..0, CertTest] = [
+      ("https://google.com/", good, "good")
+    ]
+
+
+  template evaluate(exception_msg: string, category: Category, desc: string) =
+    # Evaluate test outcome. Tests flagged as `_broken` are evaluated and skipped
+    let raised = (exception_msg.len > 0)
+    let should_not_raise = category in {good, dubious_broken, bad_broken}
+    if should_not_raise xor raised:
+      # we are seeing a known behavior
+      if category in {good_broken, dubious_broken, bad_broken}:
+        skip()
+      if raised:
+        # check exception_msg == "No SSL certificate found." or
+        doAssert exception_msg == "No SSL certificate found." or
+          exception_msg == "SSL Certificate check failed." or
+          exception_msg.contains("certificate verify failed") or
+          exception_msg.contains("key too small") or
+          exception_msg.contains("alert handshake failure") or
+          exception_msg.contains("bad dh p length") or
+          # TODO: This one should only triggers for 10000-sans
+          exception_msg.contains("excessive message size"), exception_msg
+
+    else:
+      # this is unexpected
+      var fatal = true
+      var msg = ""
+      if raised:
+        msg = "         $# ($#) raised: $#" % [desc, $category, exception_msg]
+        if "500 Internal Server Error" in exception_msg:
+          # refs https://github.com/nim-lang/Nim/issues/16338#issuecomment-804300278
+          # we got: `good (good) raised: 500 Internal Server Error`
+          fatal = false
+          msg.add " (http 500 => assuming this is not our problem)"
+      else:
+        msg = "         $# ($#) did not raise" % [desc, $category]
+
+      if category in {good, dubious, bad} and fatal:
+        echo "D20210322T121353: error: " & msg
+        fail()
+      else:
+        echo "D20210322T121353: warning: " & msg
+
+
+  suite "SSL certificate check - httpclient":
+
+    for i, ct in certificate_tests:
+
+      test ct.desc:
+        var ctx = newContext(verifyMode=CVerifyPeer)
+        var client = newHttpClient(sslContext=ctx)
+        let exception_msg =
+          try:
+            let a = $client.getContent(ct.url)
+            ""
+          except:
+            getCurrentExceptionMsg()
+
+        evaluate(exception_msg, ct.category, ct.desc)
+
+
+
+  # threaded tests
+
+
+  type
+    TTOutcome = ref object
+      desc, exception_msg: string
+      category: Category
+
+  proc run_t_test(ct: CertTest): TTOutcome {.thread.} =
+    ## Run test in a {.thread.} - return by ref
+    result = TTOutcome(desc:ct.desc, exception_msg:"", category: ct.category)
+    try:
+      var ctx = newContext(verifyMode=CVerifyPeer)
+      var client = newHttpClient(sslContext=ctx)
+      let a = $client.getContent(ct.url)
+    except:
+      result.exception_msg = getCurrentExceptionMsg()
+
+
+  suite "SSL certificate check - httpclient - threaded":
+    when defined(nimTestsEnableFlaky) or not defined(linux): # xxx pending bug #16338
+      # Spawn threads before the "test" blocks
+      var outcomes = newSeq[FlowVar[TTOutcome]](certificate_tests.len)
+      for i, ct in certificate_tests:
+        let t = spawn run_t_test(ct)
+        outcomes[i] = t
+
+      # create "test" blocks and handle thread outputs
+      for t in outcomes:
+        let outcome = ^t  # wait for a thread to terminate
+        test outcome.desc:
+          evaluate(outcome.exception_msg, outcome.category, outcome.desc)
+    else:
+      echo "skipped test"
+
+  # net tests
+
+
+  type NetSocketTest = tuple[hostname: string, port: Port, category:Category, desc: string]
+  # badssl certs sometimes expire, set to false when that happens
+  when true:
+    const net_tests:array[0..3, NetSocketTest] = [
+      ("imap.gmail.com", 993.Port, good, "IMAP"),
+      ("wrong.host.badssl.com", 443.Port, bad, "wrong.host"),
+      ("captive-portal.badssl.com", 443.Port, bad, "captive-portal"),
+      ("expired.badssl.com", 443.Port, bad, "expired"),
+    ]
+  else:
+    const net_tests: array[0..0, NetSocketTest] = [
+      ("imap.gmail.com", 993.Port, good, "IMAP")
+    ]
+  # TODO: ("null.badssl.com", 443.Port, bad_broken, "null"),
+
+
+  suite "SSL certificate check - sockets":
+
+    for ct in net_tests:
+
+      test ct.desc:
+
+        var sock = newSocket()
+        var ctx = newContext()
+        ctx.wrapSocket(sock)
+        let exception_msg =
+          try:
+            sock.connect(ct.hostname, ct.port)
+            ""
+          except:
+            getCurrentExceptionMsg()
+
+        evaluate(exception_msg, ct.category, ct.desc)
diff --git a/tests/untestable/tpostgres.nim b/tests/untestable/tpostgres.nim
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/tests/untestable/tpostgres.nim
@@ -0,0 +1 @@
+
diff --git a/tests/untestable/tssl.nim b/tests/untestable/tssl.nim
new file mode 100644
index 000000000..fca6385f8
--- /dev/null
+++ b/tests/untestable/tssl.nim
@@ -0,0 +1,36 @@
+#
+#            Nim - SSL integration tests
+#        (c) Copyright 2017 Nim contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+## Warning: this test performs external networking.
+##
+## Test with:
+## ./bin/nim c -d:ssl -p:. -r tests/untestable/tssl.nim
+## ./bin/nim c -d:ssl -p:. --dynlibOverride:ssl --passL:-lcrypto --passL:-lssl -r tests/untestable/tssl.nim
+## The compilation is expected to succeed with any new/old version of OpenSSL,
+## both with dynamic and static linking.
+## The "howsmyssl" test is known to fail with OpenSSL < 1.1 due to insecure
+## cypher suites being used.
+
+import httpclient, os
+from strutils import contains, toHex
+
+from openssl import getOpenSSLVersion
+
+when true:
+  echo "version: 0x" & $getOpenSSLVersion().toHex()
+
+  let client = newHttpClient()
+  # hacky SSL check
+  const url = "https://www.howsmyssl.com"
+  let report = client.getContent(url)
+  if not report.contains(">Probably Okay</span>"):
+    let fn = getTempDir() / "sslreport.html"
+    echo "SSL CHECK ERROR, see " & fn
+    writeFile(fn, report)
+    quit(1)
+
+  echo "done"
diff --git a/tests/usingstmt/tusingstmt.nim b/tests/usingstmt/tusingstmt.nim
new file mode 100644
index 000000000..11803878e
--- /dev/null
+++ b/tests/usingstmt/tusingstmt.nim
@@ -0,0 +1,16 @@
+type
+  Foo = object
+
+using
+  c: Foo
+  x, y: int
+
+proc usesSig(c) = discard
+
+proc foobar(c, y) = discard
+
+usesSig(Foo())
+foobar(Foo(), 123)
+doAssert not compiles(usesSig(123))
+doAssert not compiles(foobar(Foo(), Foo()))
+doAssert not compiles(foobar(123, 123))
diff --git a/tests/valgrind/tbasic_valgrind.nim b/tests/valgrind/tbasic_valgrind.nim
new file mode 100644
index 000000000..455b1ff17
--- /dev/null
+++ b/tests/valgrind/tbasic_valgrind.nim
@@ -0,0 +1,6 @@
+discard """
+  valgrind: true
+  cmd: "nim c --gc:destructors $file"
+"""
+
+echo "hello world"
diff --git a/tests/valgrind/tleak_arc.nim b/tests/valgrind/tleak_arc.nim
new file mode 100644
index 000000000..c47ee137a
--- /dev/null
+++ b/tests/valgrind/tleak_arc.nim
@@ -0,0 +1,14 @@
+discard """
+valgrind: true
+cmd: "nim $target --gc:arc -d:useMalloc $options $file"
+exitcode: 1
+outputsub: "   definitely lost: 7 bytes in 2 blocks"
+disabled: "freebsd"
+disabled: "osx"
+disabled: "openbsd"
+disabled: "windows"
+disabled: "32bit"
+"""
+
+discard alloc(3)
+discard alloc(4)
diff --git a/tests/varres/tnewseq_on_result_vart.nim b/tests/varres/tnewseq_on_result_vart.nim
new file mode 100644
index 000000000..4a700468f
--- /dev/null
+++ b/tests/varres/tnewseq_on_result_vart.nim
@@ -0,0 +1,9 @@
+
+discard """
+  errormsg: "address of 'result' may not escape its stack frame"
+  line: 9
+"""
+# bug #5113
+
+proc makeSeqVar(size: Natural): var seq[int] =
+  newSeq(result, size)
diff --git a/tests/varres/tprevent_forloopvar_mutations.nim b/tests/varres/tprevent_forloopvar_mutations.nim
new file mode 100644
index 000000000..c9aeb94d8
--- /dev/null
+++ b/tests/varres/tprevent_forloopvar_mutations.nim
@@ -0,0 +1,16 @@
+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, 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'
+
+expression: inc i
+'''
+"""
+
+for i in 0..10:
+  echo i
+  inc i
diff --git a/tests/varres/tvarres0.nim b/tests/varres/tvarres0.nim
new file mode 100644
index 000000000..94bdb4a06
--- /dev/null
+++ b/tests/varres/tvarres0.nim
@@ -0,0 +1,141 @@
+discard """
+  output: '''123
+1234
+123
+1234
+12345
+123456
+'''
+"""
+
+# Test simple type
+var a = 123
+proc getA(): var int = a
+
+echo getA()
+
+getA() = 1234
+echo getA()
+
+
+# Test object type
+type Foo = object
+    a: int
+var f: Foo
+f.a = 123
+proc getF(): var Foo = f
+echo getF().a
+getF().a = 1234
+echo getF().a
+getF() = Foo(a: 12345)
+echo getF().a
+(addr getF())[] = Foo(a: 123456)
+echo getF().a
+
+
+block: # #13848
+  template fun() =
+    block:
+      var m = 1
+
+      proc identity(o: var int): var int =
+        result = o
+        result += 5
+
+      identity(m) += 3
+      doAssert m == 5+4
+
+    block:
+      var m = 10
+      proc identity2(o: var int): var int =
+        result = m
+        result += 100
+
+      var ignored = 27
+      identity2(ignored) += 7
+      doAssert m == 10 + 100 + 7
+
+    block:
+      iterator test3(o: var int): var int = yield o
+      var m = 1
+      for m2 in test3(m): m2+=3
+      doAssert m == 4
+
+  static: fun()
+  fun()
+
+  template fun2() =
+    block:
+      var m = 1
+      var m2 = 1
+      iterator test3(o: var int): (var int, var int) =
+        yield (o, m2)
+
+      for ti in test3(m):
+        ti[0]+=3
+        ti[1]+=4
+
+      doAssert (m, m2) == (4, 5)
+  fun2()
+  # static: fun2() # BUG: Error: attempt to access a nil address kind: rkInt
+
+  template fun3() =
+    block:
+      proc test4[T1](o: var T1): var int = o[1]
+      block:
+        var m = @[1,2]
+        test4(m) += 10
+        doAssert m[1] == 2+10
+      block:
+        var m = [1,2]
+        test4(m) += 10
+        doAssert m[1] == 2+10
+      block:
+        var m = (1, 2)
+        test4(m) += 10
+        doAssert m[1] == 2+10
+
+      proc test5[T1](o: var T1): var int = o.x
+      block:
+        type Foo = object
+          x: int
+        var m = Foo(x: 2)
+        test5(m) += 10
+        doAssert m.x == 2+10
+      block:
+        type Foo = ref object
+          x: int
+        var m = Foo(x: 2)
+        test5(m) += 10
+        doAssert m.x == 2+10
+
+      proc test6[T1](o: T1): var int = o.x
+      block:
+        type Foo = ref object
+          x: int
+        var m = Foo(x: 2)
+        test6(m) += 10
+        doAssert m.x == 2+10
+
+  fun3()
+  static: fun3()
+
+  when false:
+    # BUG:
+    # c: SIGSEGV
+    # cpp: error: call to implicitly-deleted default constructor of 'tyTuple__ILZebuYefUeQLAzY85QkHA'
+    proc test7[T](o: var T): (var int,) =
+      (o[1], )
+    var m = @[1,2]
+    test7(m)[0] += 10
+
+block:
+  # example from #13848
+  type
+    MyType[T] = object
+      a,b: T
+    MyTypeAlias = MyType[float32]
+
+  var m: MyTypeAlias
+  proc identity(o: var MyTypeAlias): var MyTypeAlias = o
+  discard identity(m)
diff --git a/tests/varres/tvarres1.nim b/tests/varres/tvarres1.nim
new file mode 100644
index 000000000..e58d7f083
--- /dev/null
+++ b/tests/varres/tvarres1.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "'bla' escapes its stack frame; context: 'bla'"
+  file: "tvarres1.nim"
+  line: 12
+"""
+
+var
+  g = 5
+
+proc p(): var int =
+  var bla: int
+  result = bla
+
+p() = 45
+
+echo g
diff --git a/tests/varres/tvarres2.nim b/tests/varres/tvarres2.nim
new file mode 100644
index 000000000..4ec0bb05b
--- /dev/null
+++ b/tests/varres/tvarres2.nim
@@ -0,0 +1,15 @@
+discard """
+  errormsg: "expression has no address"
+  file: "tvarres2.nim"
+  line: 11
+"""
+
+var
+  g = 5
+
+proc p(): var int =
+  result = 89
+
+p() = 45
+
+echo g
diff --git a/tests/varres/tvarres3.nim b/tests/varres/tvarres3.nim
new file mode 100644
index 000000000..9a46bfb4e
--- /dev/null
+++ b/tests/varres/tvarres3.nim
@@ -0,0 +1,15 @@
+discard """
+  output: "45"
+"""
+
+var
+  g = 5
+
+proc p(): var int =
+  var bla = addr(g) #: array[0..7, int]
+  result = bla[]
+
+p() = 45
+
+echo g
+
diff --git a/tests/varres/tvarres4.nim b/tests/varres/tvarres4.nim
new file mode 100644
index 000000000..119560e7b
--- /dev/null
+++ b/tests/varres/tvarres4.nim
@@ -0,0 +1,20 @@
+discard """
+  output: "45 hallo"
+"""
+
+type
+  TKachel = tuple[i: int, s: string]
+  TSpielwiese = object
+    k: seq[TKachel]
+
+var
+  spielwiese: TSpielwiese
+newSeq(spielwiese.k, 64)
+
+proc at*(s: var TSpielwiese, x, y: int): var TKachel =
+  result = s.k[y * 8 + x]
+
+spielwiese.at(3, 4) = (45, "hallo")
+
+echo spielwiese.at(3,4)[0], " ", spielwiese.at(3,4)[1]
+
diff --git a/tests/varres/tvarres_via_forwarding.nim b/tests/varres/tvarres_via_forwarding.nim
new file mode 100644
index 000000000..fb7201ad2
--- /dev/null
+++ b/tests/varres/tvarres_via_forwarding.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "'y' escapes its stack frame; context: 'forward(y)'"
+  line: 10
+"""
+
+proc forward(x: var int): var int = result = x
+
+proc foo(): var int =
+  var y = 9
+  result = forward(y)
+
+echo foo()
diff --git a/tests/varres/tvartup.nim b/tests/varres/tvartup.nim
new file mode 100644
index 000000000..a8f15b232
--- /dev/null
+++ b/tests/varres/tvartup.nim
@@ -0,0 +1,10 @@
+discard """
+  output: "2 3"
+"""
+# Test the new tuple unpacking
+
+proc divmod(a, b: int): tuple[di, mo: int] =
+  return (a div b, a mod b)
+
+var (x, y) = divmod(15, 6)
+echo x, " ", y
diff --git a/tests/varres/twrong_parameter.nim b/tests/varres/twrong_parameter.nim
new file mode 100644
index 000000000..58d01fd7e
--- /dev/null
+++ b/tests/varres/twrong_parameter.nim
@@ -0,0 +1,16 @@
+discard """
+  errormsg: "'x' is not the first parameter; context: 'x.field[0]'"
+  line: 10
+"""
+
+type
+  MyObject = object
+    field: array[2, int]
+
+proc forward(abc: int; x: var MyObject): var int = result = x.field[0]
+
+proc foo(): var int =
+  var y: MyObject
+  result = forward(45, y)
+
+echo foo()
diff --git a/tests/varstmt/tlet.nim b/tests/varstmt/tlet.nim
new file mode 100644
index 000000000..9c2d9706d
--- /dev/null
+++ b/tests/varstmt/tlet.nim
@@ -0,0 +1,19 @@
+discard """
+  output: '''Very funny, your name is name.
+nameabc'''
+"""
+
+proc main =
+  let name = "name"
+  if name == "":
+    echo("Poor soul, you lost your name?")
+  elif name == "name":
+    echo("Very funny, your name is name.")
+  else:
+    echo("Hi, ", name, "!")
+
+  let (x, y) = ("abc", name)
+  echo y, x
+
+main()
+
diff --git a/tests/varstmt/tvardecl.nim b/tests/varstmt/tvardecl.nim
new file mode 100644
index 000000000..d5ccfafb7
--- /dev/null
+++ b/tests/varstmt/tvardecl.nim
@@ -0,0 +1,19 @@
+discard """
+  output: "44"
+"""
+# Test the new variable declaration syntax
+import std/sequtils
+
+var
+  x = 0
+  s = "Hallo"
+  a, b: int = 4
+
+write(stdout, a)
+writeLine(stdout, b) #OUT 44
+
+proc p() = # bug #18104
+  var x, y = newSeqWith(10, newString(3))
+  discard (x, y)
+
+p()
diff --git a/tests/views/t19986.nim b/tests/views/t19986.nim
new file mode 100644
index 000000000..85a7cf97d
--- /dev/null
+++ b/tests/views/t19986.nim
@@ -0,0 +1,42 @@
+discard """
+  cmd: '''nim check --hints:off $file'''
+  action: reject
+nimout: '''
+t19986.nim(19, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it
+t19986.nim(28, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it
+t19986.nim(37, 7) Error: 'foo' borrows from the immutable location 'a' and attempts to mutate it
+'''
+"""
+
+{.experimental: "views".}
+
+type
+  Object = object
+    id: int
+
+proc foo() =
+  let a = Object(id: 3)
+  var foo: var Object = a
+
+  foo.id = 777
+  echo a
+
+foo()
+
+proc bar() =
+  let a = "123"
+  var foo: var string = a
+
+  foo[0] = '7'
+  echo a
+
+bar()
+
+proc main() =
+  let a = 3
+  var foo: var int = a
+
+  foo = 777
+  echo a
+
+main()
diff --git a/tests/views/tcan_compile_nim.nim b/tests/views/tcan_compile_nim.nim
new file mode 100644
index 000000000..e990606cd
--- /dev/null
+++ b/tests/views/tcan_compile_nim.nim
@@ -0,0 +1,4 @@
+discard """
+  cmd: "nim check --hints:on --experimental:strictFuncs --experimental:views compiler/nim.nim"
+  action: "compile"
+"""
diff --git a/tests/views/tcannot_borrow.nim b/tests/views/tcannot_borrow.nim
new file mode 100644
index 000000000..0b8793159
--- /dev/null
+++ b/tests/views/tcannot_borrow.nim
@@ -0,0 +1,22 @@
+discard """
+  errormsg: "cannot borrow"
+  nimout: '''tcannot_borrow.nim(20, 7) Error: cannot borrow meh; what it borrows from is potentially mutated
+tcannot_borrow.nim(21, 3) the mutation is here'''
+"""
+
+
+{.experimental: "views".}
+
+type
+  Foo = object
+    field: string
+
+proc valid(s: var seq[Foo]) =
+  let v: lent Foo = s[0]  # begin of borrow
+  echo v.field            # end of borrow
+  s.setLen 0  # valid because 'v' isn't used afterwards
+
+proc dangerous(s: var seq[Foo]) =
+  let meh: lent Foo = s[0]
+  s.setLen 0
+  echo meh.field
diff --git a/tests/views/tconst_views.nim b/tests/views/tconst_views.nim
new file mode 100644
index 000000000..a85b03864
--- /dev/null
+++ b/tests/views/tconst_views.nim
@@ -0,0 +1,37 @@
+discard """
+  cmd: "nim c --experimental:views $file"
+  output: '''(data: [1, 2, 3], other: 4)
+[1, 20, 3]'''
+"""
+
+type
+  Foo = object
+    data: openArray[int]
+    other: int
+
+const
+  c = Foo(data: [1, 2, 3], other: 4)
+
+  c2 = Foo(data: [1, 20, 3], other: 4)
+
+proc `$`(x: openArray[int]): string =
+  result = "["
+  for i in x:
+    if result.len > 1: result.add ", "
+    result.add $i
+  result.add "]"
+
+echo c
+echo c2.data
+
+
+type MyObj = object
+  data: openarray[char]
+
+const
+  val1 = Foo(data: toOpenArray([1, 2, 3], 1, 1))
+  val2 = Foo(data: toOpenArray([1, 2, 3], 0, 2))
+  val3 = MyObj(data: "Hello".toOpenArray(0, 2))
+assert val1.data == [2]
+assert val2.data == [1, 2, 3]
+assert val3.data == "Hel"
diff --git a/tests/views/tdont_mutate.nim b/tests/views/tdont_mutate.nim
new file mode 100644
index 000000000..eb5a82cbf
--- /dev/null
+++ b/tests/views/tdont_mutate.nim
@@ -0,0 +1,58 @@
+discard """
+  cmd: "nim check --hints:off $file"
+"""
+
+import tables
+
+{.experimental: "views".}
+
+const
+  Whitespace = {' ', '\t', '\n', '\r'}
+
+proc split*(s: string, seps: set[char] = Whitespace, maxsplit: int = -1): Table[int, openArray[char]] #[tt.Error
+^ 'result' borrows from the immutable location 's' and attempts to mutate it
+    ]# =
+  var last = 0
+  var splits = maxsplit
+  result = initTable[int, openArray[char]]()
+
+  while last <= len(s):
+    var first = last
+    while last < len(s) and s[last] notin seps:
+      inc(last)
+    if splits == 0: last = len(s)
+    result[first] = toOpenArray(s, first, last-1)
+
+    result[first][0] = 'c'
+
+    if splits == 0: break
+    dec(splits)
+    inc(last)
+
+proc `$`(x: openArray[char]): string =
+  result = newString(x.len)
+  for i in 0..<x.len: result[i] = x[i]
+
+proc otherTest(x: int) =
+  var y: var int = x #[tt.Error
+      ^ 'y' borrows from the immutable location 'x' and attempts to mutate it
+  ]#
+  y = 3
+
+proc main() =
+  let words = split("asdf 231")
+  for i, x in words:
+    echo i, ": ", x
+
+main()
+
+# This has to continue to work:
+
+type
+  PNode = ref object
+  TSrcGen = object
+    comStack: seq[PNode]
+
+proc pushCom(g: var TSrcGen, n: PNode) =
+  setLen(g.comStack, g.comStack.len + 1)
+  g.comStack[^1] = n
diff --git a/tests/views/tmust_borrow_from_first_parameter.nim b/tests/views/tmust_borrow_from_first_parameter.nim
new file mode 100644
index 000000000..b2decfb38
--- /dev/null
+++ b/tests/views/tmust_borrow_from_first_parameter.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "'result' must borrow from the first parameter"
+  line: 9
+"""
+
+{.experimental: "views".}
+
+proc p(a, b: openArray[char]): openArray[char] =
+  result = b
diff --git a/tests/views/tsplit_into_openarray.nim b/tests/views/tsplit_into_openarray.nim
new file mode 100644
index 000000000..3ea290d89
--- /dev/null
+++ b/tests/views/tsplit_into_openarray.nim
@@ -0,0 +1,37 @@
+discard """
+  output: '''asdf
+231
+'''
+  cmd: "nim c --gc:arc -d:useMalloc -g $file"
+  valgrind: true
+"""
+
+{.experimental: "views".}
+
+const
+  Whitespace = {' ', '\t', '\n', '\r'}
+
+iterator split*(s: string, seps: set[char] = Whitespace,
+                maxsplit: int = -1): openArray[char] =
+  var last = 0
+  var splits = maxsplit
+
+  while last <= len(s):
+    var first = last
+    while last < len(s) and s[last] notin seps:
+      inc(last)
+    if splits == 0: last = len(s)
+    yield toOpenArray(s, first, last-1)
+    if splits == 0: break
+    dec(splits)
+    inc(last)
+
+proc `$`(x: openArray[char]): string =
+  result = newString(x.len)
+  for i in 0..<x.len: result[i] = x[i]
+
+proc main() =
+  for x in split("asdf 231"):
+    echo x
+
+main()
diff --git a/tests/views/tsplit_into_seq.nim b/tests/views/tsplit_into_seq.nim
new file mode 100644
index 000000000..a0861458b
--- /dev/null
+++ b/tests/views/tsplit_into_seq.nim
@@ -0,0 +1,41 @@
+discard """
+  output: '''asdf
+asdf
+231
+231
+'''
+  cmd: "nim c --gc:orc $file"
+"""
+
+{.experimental: "views".}
+
+const
+  Whitespace = {' ', '\t', '\n', '\r'}
+
+proc split*(s: string, seps: set[char] = Whitespace,
+                maxsplit: int = -1): seq[openArray[char]] =
+  var last = 0
+  var splits = maxsplit
+  result = @[]
+
+  while last <= len(s):
+    var first = last
+    while last < len(s) and s[last] notin seps:
+      inc(last)
+    if splits == 0: last = len(s)
+    result.add toOpenArray(s, first, last-1)
+    result.add toOpenArray(s, first, last-1)
+    if splits == 0: break
+    dec(splits)
+    inc(last)
+
+proc `$`(x: openArray[char]): string =
+  result = newString(x.len)
+  for i in 0..<x.len: result[i] = x[i]
+
+proc main() =
+  let words = split("asdf 231")
+  for x in words:
+    echo x
+
+main()
diff --git a/tests/views/tsplit_into_table.nim b/tests/views/tsplit_into_table.nim
new file mode 100644
index 000000000..49371b9a7
--- /dev/null
+++ b/tests/views/tsplit_into_table.nim
@@ -0,0 +1,40 @@
+discard """
+  output: '''5: 231
+0: asdf
+'''
+"""
+
+import tables
+
+{.experimental: "views".}
+
+const
+  Whitespace = {' ', '\t', '\n', '\r'}
+
+proc split*(s: string, seps: set[char] = Whitespace,
+                maxsplit: int = -1): Table[int, openArray[char]] =
+  var last = 0
+  var splits = maxsplit
+  result = initTable[int, openArray[char]]()
+
+  while last <= len(s):
+    var first = last
+    while last < len(s) and s[last] notin seps:
+      inc(last)
+    if splits == 0: last = len(s)
+    result[first] = toOpenArray(s, first, last-1)
+
+    if splits == 0: break
+    dec(splits)
+    inc(last)
+
+proc `$`(x: openArray[char]): string =
+  result = newString(x.len)
+  for i in 0..<x.len: result[i] = x[i]
+
+proc main() =
+  let words = split("asdf 231")
+  for i, x in words:
+    echo i, ": ", x
+
+main()
diff --git a/tests/views/tviews1.nim b/tests/views/tviews1.nim
new file mode 100644
index 000000000..9785d25e5
--- /dev/null
+++ b/tests/views/tviews1.nim
@@ -0,0 +1,136 @@
+discard """
+  output: '''11
+22
+33
+3
+2
+3
+3
+15
+(oa: [1, 3, 4])'''
+  targets: "c cpp"
+"""
+
+{.experimental: "views".}
+
+proc take(a: openArray[int]) =
+  echo a.len
+
+proc main(s: seq[int]) =
+  var x: openArray[int] = s
+  for i in 0 .. high(x):
+    echo x[i]
+  take(x)
+
+  take(x.toOpenArray(0, 1))
+  let y = x
+  take y
+  take x
+
+main(@[11, 22, 33])
+
+var x: int
+
+proc foo(x: var int): var int =
+  once: x = 42
+  return x
+
+var y: var int = foo(x)
+y = 15
+echo foo(x)
+# bug #16132
+
+# bug #18690
+
+type
+  F = object
+    oa: openArray[int]
+
+let s1 = @[1,3,4,5,6]
+var test = F(oa: toOpenArray(s1, 0, 2))
+echo test
+
+type
+  Foo = object
+    x: string
+    y: seq[int]
+    data: array[10000, byte]
+
+  View[T] = object
+    x: lent T
+
+proc mainB =
+  let f = Foo(y: @[1, 2, 3])
+  let foo = View[Foo](x: f)
+  assert foo.x.x == ""
+  assert foo.x.y == @[1, 2, 3]
+
+mainB()
+
+
+# bug #15897
+type Outer = ref object 
+  value: int
+type Inner = object
+  owner: var Outer
+  
+var o = Outer(value: 1234)
+var v = Inner(owner: o).owner.value
+doAssert v == 1234
+
+block: # bug #21674
+  type
+    Lent = object
+      data: lent int
+
+  proc foo(s: Lent) =
+    var m = 12
+    discard cast[lent int](m)
+
+  proc main =
+    var m1 = 123
+    var x = Lent(data: m1)
+    foo(x)
+
+  main()
+
+block: # bug #22117
+  proc main: int =
+    var a = 10
+    defer: discard a # extend a's lifetime
+
+    var aref: var int = a
+      #└──── 'aref' borrows from location 'a' which does not live long enough
+
+    result = aref
+
+  doAssert main() == 10
+
+type
+  Slice*[T] = object
+    first, last: int
+    p: ptr UncheckedArray[T]
+
+var i = 0
+
+converter autoToOpenArray*[T](s: Slice[T]): openArray[T] =
+  inc i
+  result = toOpenArray(s.p, s.first, s.last)
+
+proc acceptOpenArray(s: openArray[byte]) = discard
+
+proc bug22597 = # bug #22597
+  acceptOpenArray(Slice[byte]())
+  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/meta.nim b/tests/vm/meta.nim
new file mode 100644
index 000000000..32a441f27
--- /dev/null
+++ b/tests/vm/meta.nim
@@ -0,0 +1,240 @@
+#
+# meta.nim
+#
+
+import tables
+import macros
+
+type
+  NodeSeq* = seq[NimNode]
+  Ident* = tuple[name: string, exported: bool]
+  Bracket* = seq[Ident]
+  Field* = tuple[identifier: Ident, type_name: string, default: string]
+  FieldSeq* = seq[Field]
+  TypeDef* = object
+    identifier*: Ident
+    fields*: FieldSeq
+    is_ref*: bool
+    object_type*: string
+    base_type*: string
+  TypeDefSeq* = seq[TypeDef]
+  Proc* = tuple[identifier: Ident, params: FieldSeq,
+                returns: Ident, generics: FieldSeq, body: NimNode]
+  ProcSeq* = seq[Proc]
+
+# Ident procs
+proc newIdent*(name: string, exported = false): Ident =
+  result.name = name
+  result.exported = exported
+
+proc newIdent*(node: NimNode): Ident =
+  case node.kind:
+    of nnkPostfix:
+      result = newIdent(node[1])
+      result.exported = true
+    of nnkIdent, nnkSym:
+      result.name = $(node)
+    else:
+      let msg = "newIdent cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(i: Ident): NimNode {.compileTime.} =
+  if i.name == "":
+    return newNimNode(nnkEmpty)
+
+  if i.exported:
+    result = newNimNode(nnkPostfix)
+    result.add(ident "*")
+    result.add(ident i.name)
+  else:
+    result = ident i.name
+
+proc `$`*(identifier: Ident): string = identifier.name
+
+converter toString*(x: Ident): string = x.name
+
+proc newBracket*(node: NimNode): Bracket =
+  result = @[]
+  case node.kind:
+    of nnkBracket:
+      for child in node:
+        if child.kind != nnkIdent:
+          let msg = "Bracket members can only be nnkIdent not kind: " & $(node.kind)
+          raise newException(ValueError, msg)
+        result.add(newIdent(child))
+    else:
+      let msg = "newBracket must initialize from node kind nnkBracket not: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+# Field procs
+proc newField*(identifier: Ident, type_name: string, default: string = ""): Field =
+  result.identifier = identifier
+  result.type_name = type_name
+  result.default = default
+
+proc newField*(node: NimNode): Field =
+  case node.kind:
+    of nnkIdentDefs:
+      if node.len > 3:
+        let msg = "newField cannot initialize from nnkIdentDefs with multiple names"
+        raise newException(ValueError, msg)
+      result.identifier = newIdent(node[0])
+      result.type_name = $(node[1])
+      case node[2].kind:
+        of nnkIdent:
+          result.default = $(node[2])
+        else:
+          result.default = ""
+    else:
+      let msg = "newField cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+# FieldSeq procs
+proc newFieldSeq*(node: NimNode): FieldSeq =
+  result = @[]
+  case node.kind:
+    of nnkIdentDefs:
+      let
+        type_name = $(node[node.len - 2])
+        default_node = node[node.len - 1]
+      var default: string
+      case default_node.kind:
+        of nnkIdent:
+          default = $(default_node)
+        else:
+          default = ""
+      for i in 0..node.len - 3:
+        let name = newIdent(node[i])
+        result.add(newField(name, type_name, default))
+    of nnkRecList, nnkVarSection, nnkGenericParams:
+      for child in node:
+        result = result & newFieldSeq(child)
+    else:
+      let msg = "newFieldSeq cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(f: Field): NimNode {.compileTime.} =
+  let identifier = f.identifier.render()
+  let type_name = if f.type_name != "": ident(f.type_name) else: newEmptyNode()
+  let default = if f.default != "": ident(f.default) else: newEmptyNode()
+  newIdentDefs(identifier, type_name, default)
+
+proc render*(fs: FieldSeq): NimNode {.compileTime.} =
+  result = newNimNode(nnkRecList)
+  for field in fs:
+    result.add(field.render())
+
+# TypeDef procs
+proc newTypeDef*(identifier: Ident, is_ref = false,
+                object_type = "object",
+                base_type: string = ""): TypeDef {.compileTime.} =
+  result.identifier = identifier
+  result.fields = @[]
+  result.is_ref = is_ref
+  result.object_type = "object"
+  result.base_type = base_type
+
+proc newTypeDef*(node: NimNode): TypeDef {.compileTime.} =
+  case node.kind:
+    of nnkTypeDef:
+      result.identifier = newIdent($(node[0]))
+      var object_node: NimNode
+      case node[2].kind:
+        of nnkRefTy:
+          object_node = node[2][0]
+          result.is_ref = true
+        of nnkObjectTy:
+          object_node = node[2]
+          result.is_ref = false
+        else:
+          let msg = "newTypeDef could not parse RefTy/ObjectTy, found: " & $(node[2].kind)
+          raise newException(ValueError, msg)
+      case object_node[1].kind:
+        of nnkOfInherit:
+          result.base_type = $(object_node[1][0])
+        else:
+          result.base_type = "object"
+      result.fields = newFieldSeq(object_node[2])
+    else:
+      let msg = "newTypeDef cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(typedef: TypeDef): NimNode {.compileTime.} =
+  result = newNimNode(nnkTypeDef)
+  result.add(typedef.identifier.render)
+  result.add(newEmptyNode())
+  let object_node = newNimNode(nnkObjectTy)
+  object_node.add(newEmptyNode())
+  if typedef.base_type == "":
+    object_node.add(newEmptyNode())
+  else:
+    var base_type = newNimNode(nnkOfInherit)
+    base_type.add(ident(typedef.base_type))
+    object_node.add(base_type)
+  let fields = typedef.fields.render()
+  object_node.add(fields)
+  if typedef.is_ref:
+    let ref_node = newNimNode(nnkRefTy)
+    ref_node.add(object_node)
+    result.add(ref_node)
+  else:
+    result.add(object_node)
+
+proc newTypeDefSeq*(node: NimNode): TypeDefSeq =
+  result = @[]
+  case node.kind:
+    of nnkTypeSection:
+      for child in node:
+        result.add(newTypeDef(child))
+    else:
+      let msg = "newTypeSection could not parse TypeDef, found: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(typeseq: TypeDefSeq): NimNode {.compileTime.} =
+  result = newNimNode(nnkTypeSection)
+  for typedef in typeseq:
+    result.add(typedef.render())
+
+proc newProc*(identifier: Ident, params: FieldSeq = @[],
+              returns: Ident, generics: FieldSeq = @[]): Proc =
+  result.identifier = identifier
+  result.params = params
+  result.returns = returns
+  result.generics = generics
+
+proc newProc*(node: NimNode): Proc =
+  case node.kind:
+    of nnkProcDef, nnkMethodDef:
+      result.identifier = newIdent(node[0])
+      case node[2].kind:
+        of nnkGenericParams:
+          result.generics = newFieldSeq(node[2])
+        else: result.generics = @[]
+      let formal_params = node[3]
+      case formal_params[0].kind:
+        of nnkIdent:
+          result.returns = newIdent(formal_params[0])
+        else: discard
+      result.params = @[]
+      for i in 1..formal_params.len - 1:
+        let param = formal_params[i]
+        for field in newFieldSeq(param):
+          result.params.add(field)
+      result.body = node[6]
+    else:
+      let msg = "newProc cannot initialize from node kind: " & $(node.kind)
+      raise newException(ValueError, msg)
+
+proc render*(procdef: Proc): NimNode {.compileTime.} =
+  result = newNimNode(nnkProcDef)
+  result.add(procdef.identifier.render())
+  result.add(newEmptyNode())
+  result.add(newEmptyNode())
+  let formal_params = newNimNode(nnkFormalParams)
+  formal_params.add(procdef.returns.render())
+  for param in procdef.params:
+    formal_params.add(param.render())
+  result.add(formal_params)
+  result.add(newEmptyNode())
+  result.add(newEmptyNode())
+  result.add(procdef.body)
diff --git a/tests/vm/mevalffi.nim b/tests/vm/mevalffi.nim
new file mode 100644
index 000000000..ad8f8b62b
--- /dev/null
+++ b/tests/vm/mevalffi.nim
@@ -0,0 +1,71 @@
+# re-enable for windows once libffi can be installed in koch.nim
+# With win32 (not yet win64), libffi on windows works and this test passes.
+
+when defined(linux) or defined(bsd):
+  {.passL: "-lm".} # for exp
+proc c_exp(a: float64): float64 {.importc: "exp", header: "<math.h>".}
+
+proc c_printf(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>", varargs, discardable.}
+
+const snprintfName = when defined(windows): "_snprintf" else: "snprintf"
+proc c_snprintf*(str: cstring, size: csize_t, format: cstring): cint {.importc: snprintfName, header: "<stdio.h>", varargs .}
+
+proc c_malloc(size: csize_t): pointer {.importc:"malloc", header: "<stdlib.h>".}
+proc c_free(p: pointer) {.importc:"free", header: "<stdlib.h>".}
+
+proc fun() =
+  block: # c_exp
+    var x = 0.3
+    let b = c_exp(x)
+    let b2 = int(b*1_000_000) # avoids floating point equality
+    doAssert b2 == 1349858
+    doAssert c_exp(0.3) == c_exp(x)
+    const x2 = 0.3
+    doAssert c_exp(x2) == c_exp(x)
+
+  block: # c_printf
+    c_printf("foo\n")
+    c_printf("foo:%d\n", 100)
+    c_printf("foo:%d\n", 101.cint)
+    c_printf("foo:%d:%d\n", 102.cint, 103.cint)
+    let temp = 104.cint
+    c_printf("foo:%d:%d:%d\n", 102.cint, 103.cint, temp)
+    var temp2 = 105.cint
+    c_printf("foo:%g:%s:%d:%d\n", 0.03, "asdf", 103.cint, temp2)
+
+  block: # c_snprintf, c_malloc, c_free
+    let n: uint = 50
+    var buffer2 = cstring(cast[ptr char](c_malloc(n)))
+
+    var s: cstring = "foobar"
+    var age: cint = 25
+    let num = c_snprintf(buffer2, n, "s1:%s s2:%s age:%d pi:%g", s, s, age, 3.14)
+    let numExp = 34 
+    doAssert num == numExp
+    c_printf("ret=[%s]\n", buffer2)
+    c_free(buffer2)
+
+  block: # c_printf bug
+    var a = 123
+    var a2 = a.addr
+    #[
+    bug: different behavior between CT RT in this case:
+    at CT, shows foo2:a=123
+    at RT, shows foo2:a=<address as int>
+    ]#
+    if false:
+      c_printf("foo2:a=%d\n", a2)
+
+
+static:
+  fun()
+fun()
+
+when not defined nimEvalffiStderrWorkaround:
+  import system/ansi_c
+  block:
+    proc fun2()=
+      c_fprintf(cstderr, "hello world stderr\n")
+      write(stderr, "hi stderr\n")
+    static: fun2()
+    fun2()
diff --git a/tests/vm/mscriptcompiletime.nim b/tests/vm/mscriptcompiletime.nim
new file mode 100644
index 000000000..ed7e7c029
--- /dev/null
+++ b/tests/vm/mscriptcompiletime.nim
@@ -0,0 +1,7 @@
+# bug.nim
+var bar* {.compileTime.} = 1
+
+proc dummy = discard
+
+static:
+  inc bar
\ No newline at end of file
diff --git a/tests/vm/t11637.nim b/tests/vm/t11637.nim
new file mode 100644
index 000000000..c061c6641
--- /dev/null
+++ b/tests/vm/t11637.nim
@@ -0,0 +1,52 @@
+type Foo = ref object
+  val: int
+
+proc `+`(a, b: Foo): Foo =
+  Foo(val: a.val + b.val)
+
+proc `*`(a: Foo, b: int): Foo =
+  Foo(val: a.val * b)
+
+proc `+=`(a: var Foo, b: Foo) =
+  a = Foo(
+    val: a.val + b.val
+  )
+
+proc foobar(a, b, c: Foo): tuple[bar, baz, buzz: Foo] =
+
+  let foo = a + b + c
+  result.bar = foo * 2
+
+  result.baz = foo * 3
+  result.buzz = result.baz
+
+  result.buzz += a * 10000
+  result.baz += b
+  result.buzz += b
+
+
+block: # Compile-Time
+  let
+    a {.compileTime.} = Foo(val: 1)
+    b {.compileTime.} = Foo(val: 2)
+    c {.compileTime.} = Foo(val: 3)
+    r {.compileTime.} = foobar(a, b, c)
+
+  static:
+    doAssert r.bar.val == 12
+    doAssert r.baz.val == 20
+    doAssert r.buzz.val == 10020
+
+####################################
+
+block: # Run-time
+  let
+    a = Foo(val: 1)
+    b = Foo(val: 2)
+    c = Foo(val: 3)
+    r = foobar(a, b, c)
+
+  # Expected values
+  doAssert r.bar.val == 12
+  doAssert r.baz.val == 20
+  doAssert r.buzz.val == 10020
diff --git a/tests/vm/t17039.nim b/tests/vm/t17039.nim
new file mode 100644
index 000000000..f92c93f30
--- /dev/null
+++ b/tests/vm/t17039.nim
@@ -0,0 +1,10 @@
+type
+  Obj1 = object
+    case kind: bool
+    of false:
+      field: seq[int]
+    else: discard
+
+static:
+  var obj1 = Obj1()
+  obj1.field.add(@[])
diff --git a/tests/vm/t17121.nim b/tests/vm/t17121.nim
new file mode 100644
index 000000000..bf2d6423f
--- /dev/null
+++ b/tests/vm/t17121.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot 'importc' variable at compile time; c_printf"
+"""
+
+proc c_printf*(frmt: cstring): cint {.importc: "printf", header: "<stdio.h>", varargs, discardable.} =
+  ## foo bar
+  runnableExamples: discard
+static:
+  let a = c_printf("abc\n")
diff --git a/tests/vm/t18103.nim b/tests/vm/t18103.nim
new file mode 100644
index 000000000..8622ab290
--- /dev/null
+++ b/tests/vm/t18103.nim
@@ -0,0 +1,35 @@
+discard """
+  targets: "c cpp"
+  matrix: "--mm:refc; --mm:arc"
+"""
+
+import base64, complex, sequtils, math, sugar
+
+type
+
+  FP = float
+  T = object
+    index: int
+    arg: FP
+    val: Complex[FP]
+  M = object
+    alpha, beta: FP
+
+func a(s: openArray[T], model: M): seq[T] =
+  let f = (tn: int) => model.alpha + FP(tn) * model.beta;
+  return mapIt s:
+    block:
+      let s = it.val * rect(1.0, - f(it.index))
+      T(index: it.index, arg: phase(s), val: s)
+
+proc b(): float64 =
+  var s = toSeq(0..10).mapIt(T(index: it, arg: 1.0, val: complex.complex(1.0)))
+  discard a(s, M(alpha: 1, beta: 1))
+  return 1.0
+
+func cc(str: cstring, offset: ptr[cdouble]): cint {.exportc.} =
+  offset[] = b()
+  return 0
+
+static:
+  echo b()
diff --git a/tests/vm/t19075.nim b/tests/vm/t19075.nim
new file mode 100644
index 000000000..89ca9cb19
--- /dev/null
+++ b/tests/vm/t19075.nim
@@ -0,0 +1,19 @@
+discard """
+  timeout: 10
+  joinable: false
+"""
+
+# bug #19075
+const size = 50_000
+
+const stuff = block:
+    var a: array[size, int]
+    a
+
+const zeugs = block:
+    var zeugs: array[size, int]
+    for i in 0..<size:
+        zeugs[i] = stuff[i]
+    zeugs
+
+doAssert zeugs[0] == 0
\ No newline at end of file
diff --git a/tests/vm/t19199.nim b/tests/vm/t19199.nim
new file mode 100644
index 000000000..6ae48cb54
--- /dev/null
+++ b/tests/vm/t19199.nim
@@ -0,0 +1,6 @@
+# bug #19199
+proc mikasa(x: float) = doAssert x == 42
+
+static:
+  mikasa 42.uint.float
+mikasa 42.uint.float
diff --git a/tests/vm/t20746.nim b/tests/vm/t20746.nim
new file mode 100644
index 000000000..bfad269ef
--- /dev/null
+++ b/tests/vm/t20746.nim
@@ -0,0 +1,13 @@
+discard """
+  timeout: 10
+  joinable: false
+  output: "fine"
+"""
+
+func addString(): string =
+  let x = newString(1000000)
+  for i in 0..<1000000:
+    discard x[i]
+
+const translationTable = addString()
+echo "fine"
diff --git a/tests/vm/t21704.nim b/tests/vm/t21704.nim
new file mode 100644
index 000000000..27f4f5b06
--- /dev/null
+++ b/tests/vm/t21704.nim
@@ -0,0 +1,69 @@
+discard """
+matrix: "--hints:off"
+nimout: '''
+Found 2 tests to run.
+Found 3 benches to compile.
+ 
+  --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow 
+ 
+  --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow 
+ 
+  --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow
+'''
+"""
+# bug #21704
+import std/strformat
+
+const testDesc: seq[string] = @[
+  "tests/t_hash_sha256_vs_openssl.nim",
+  "tests/t_cipher_chacha20.nim"
+]
+const benchDesc = [
+  "bench_sha256",
+  "bench_hash_to_curve",
+  "bench_ethereum_bls_signatures"
+]
+
+proc setupTestCommand(flags, path: string): string =
+  return "nim c -r " &
+    flags &
+    &" --nimcache:nimcache/{path} " & # Commenting this out also solves the issue
+    path
+
+proc testBatch(commands: var string, flags, path: string) =
+  commands &= setupTestCommand(flags, path) & '\n'
+
+proc setupBench(benchName: string): string =
+  var runFlags = if false: " -r "
+                 else: " " # taking this branch is needed to trigger the bug
+
+  echo runFlags # Somehow runflags isn't reset in corner cases
+  runFlags &= " --passC:-Wno-stringop-overflow --passL:-Wno-stringop-overflow "
+  echo runFlags
+
+  return "nim c " &
+       runFlags &
+       &" benchmarks/{benchName}.nim"
+
+proc buildBenchBatch(commands: var string, benchName: string) =
+  let command = setupBench(benchName)
+  commands &= command & '\n'
+
+proc addTestSet(cmdFile: var string) =
+  echo "Found " & $testDesc.len & " tests to run."
+
+  for path in testDesc:
+    var flags = "" # This is important
+    cmdFile.testBatch(flags, path)
+
+proc addBenchSet(cmdFile: var string) =
+  echo "Found " & $benchDesc.len & " benches to compile."
+  for bd in benchDesc:
+    cmdFile.buildBenchBatch(bd)
+
+proc task_bug() =
+  var cmdFile: string
+  cmdFile.addTestSet() # Comment this out and there is no bug
+  cmdFile.addBenchSet()
+
+static: task_bug()
diff --git a/tests/vm/t2574.nim b/tests/vm/t2574.nim
new file mode 100644
index 000000000..4332667b4
--- /dev/null
+++ b/tests/vm/t2574.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "cannot call method eval at compile time"
+  line: 14
+"""
+
+type
+  PExpr = ref object of RootObj
+
+method eval(e: PExpr): int =
+  discard
+
+static:
+  let x = PExpr()
+  discard x.eval
diff --git a/tests/vm/t9622.nim b/tests/vm/t9622.nim
new file mode 100644
index 000000000..fada8fe59
--- /dev/null
+++ b/tests/vm/t9622.nim
@@ -0,0 +1,30 @@
+discard """
+  targets: "c cpp"
+  matrix: "--mm:refc; --mm:arc"
+"""
+
+type
+  GlobNodeKind = enum
+    LiteralIdent,
+    Group
+
+  GlobNode = object
+    case kind: GlobNodeKind
+    of LiteralIdent:
+      value: string
+    of Group:
+      values: seq[string]
+
+  PathSegment = object
+    children: seq[GlobNode]
+
+  GlobPattern = seq[PathSegment]
+
+proc parseImpl(): GlobPattern =
+  if result.len == 0:
+    result.add PathSegment()
+  result[^1].children.add GlobNode(kind: LiteralIdent)
+
+block:
+  const pattern = parseImpl()
+  doAssert $pattern == """@[(children: @[(kind: LiteralIdent, value: "")])]"""
diff --git a/tests/vm/tableinstatic.nim b/tests/vm/tableinstatic.nim
new file mode 100644
index 000000000..934c3a8dd
--- /dev/null
+++ b/tests/vm/tableinstatic.nim
@@ -0,0 +1,38 @@
+discard """
+  nimout: '''0
+0
+0
+'''
+"""
+
+import tables
+
+# bug #5327
+
+type
+  MyType* = object
+    counter: int
+
+proc foo(t: var MyType) =
+  echo t.counter
+
+proc bar(t: MyType) =
+  echo t.counter
+
+static:
+  var myValue: MyType
+  myValue.foo # works nicely
+
+  var refValue: ref MyType
+  refValue.new
+
+  refValue[].foo # fails to compile
+  refValue[].bar # works again nicely
+
+static:
+  var otherTable = newTable[string, string]()
+
+  otherTable["hallo"] = "123"
+  otherTable["welt"]  = "456"
+
+  doAssert otherTable == {"hallo": "123", "welt": "456"}.newTable
diff --git a/tests/vm/taddrof.nim b/tests/vm/taddrof.nim
new file mode 100644
index 000000000..bbe9345d2
--- /dev/null
+++ b/tests/vm/taddrof.nim
@@ -0,0 +1,110 @@
+discard """
+nimout: '''
+true
+true
+[nil, nil, nil, nil]
+[MyObjectRef(123, 321), nil, nil, nil]
+['A', '\x00', '\x00', '\x00']
+MyObjectRef(123, 321)
+(key: 8, val: 0)
+'''
+output: '''
+true
+true
+[nil, nil, nil, nil]
+[MyObjectRef(123, 321), nil, nil, nil]
+['A', '\x00', '\x00', '\x00']
+MyObjectRef(123, 321)
+'''
+"""
+
+type
+  MyObjectRef = ref object
+    a,b: int
+
+  MyContainerObject = ref object
+    member: MyObjectRef
+
+  MySuperContainerObject = ref object
+    member: MyContainerObject
+    arr: array[4, MyObjectRef]
+
+  MyOtherObject = ref object
+    case kind: bool
+    of true:
+      member: MyObjectRef
+    else:
+      discard
+
+proc `$`(arg: MyObjectRef): string =
+  result = "MyObjectRef("
+  result.addInt arg.a
+  result.add ", "
+  result.addInt arg.b
+  result.add ")"
+
+proc foobar(dst: var MyObjectRef) =
+  dst = new(MyObjectRef)
+  dst.a = 123
+  dst.b = 321
+
+proc changeChar(c: var char) =
+  c = 'A'
+
+proc test() =
+  # when it comes from a var, it works
+  var y: MyObjectRef
+  foobar(y)
+  echo y != nil
+  # when it comes from a member, it fails on VM
+  var x = new(MyContainerObject)
+  foobar(x.member)
+  echo x.member != nil
+
+  # when it comes from an array, it fails on VM
+  var arr: array[4, MyObjectRef]
+  echo arr
+  foobar(arr[0])
+  echo arr
+
+  var arr2: array[4, char]
+  changeChar(arr2[0])
+  echo arr2
+
+
+  var z = MyOtherObject(kind: true)
+  foobar(z.member)
+  echo z.member
+
+  # this still doesn't work
+  # var sc = new(MySuperContainerObject)
+  # sc.member = new(MyContainerObject)
+  # foobar(sc.member.member)
+  # echo sc.member.member
+  # foobar(sc.arr[1])
+  # echo sc.arr
+
+  #var str = "---"
+  #changeChar(str[1])
+  #echo str
+
+test()
+static:
+  test()
+
+type T = object
+  f: seq[tuple[key, val: int]]
+
+proc foo(s: var seq[tuple[key, val: int]]; i: int) =
+  s[i].key = 4*i
+  # r4 = addr(s[i])
+  # r4[0] = 4*i
+
+proc bar() =
+  var s: T
+  s.f = newSeq[tuple[key, val: int]](3)
+  foo(s.f, 2)
+  echo s.f[2]
+
+static:
+  bar()
diff --git a/tests/vm/tanonproc.nim b/tests/vm/tanonproc.nim
new file mode 100644
index 000000000..1176c104e
--- /dev/null
+++ b/tests/vm/tanonproc.nim
@@ -0,0 +1,52 @@
+discard """
+  output: '''`Test`'''
+"""
+
+# bug #3561
+
+import macros, sugar, strutils
+
+type
+  Option[T] = ref object
+    case valid: bool
+    of true:
+      data: T
+    else:
+      discard
+
+proc some[T](v: T): Option[T] = Option[T](valid: true, data: v)
+proc none[T](v: T): Option[T] = Option[T](valid: false)
+proc none(T: typedesc): Option[T] = Option[T](valid: false)
+
+proc map[T,U](o: Option[T], f: T -> U): Option[U] =
+  case o.valid
+  of true:
+    f(o.data).some
+  else:
+    U.none
+
+proc notEmpty(o: Option[string]): Option[string] =
+  case o.valid
+  of true:
+    if o.data.strip == "": string.none else: o.data.strip.some
+  else:
+    o
+
+proc getOrElse[T](o: Option[T], def: T): T =
+  case o.valid
+  of true:
+    o.data
+  else:
+    def
+
+proc quoteStr(s: string): Option[string] =
+  s.some.notEmpty.map(v => "`" & v & "`")
+
+macro str(s: string): void =
+  let x = s.strVal
+  let y = quoteStr(x)
+  let sn = newStrLitNode(y.getOrElse("NONE"))
+  result = quote do:
+    echo `sn`
+
+str"Test"
diff --git a/tests/vm/tarrayboundeval.nim b/tests/vm/tarrayboundeval.nim
new file mode 100644
index 000000000..dc8c7ebdc
--- /dev/null
+++ b/tests/vm/tarrayboundeval.nim
@@ -0,0 +1,31 @@
+discard """
+  output: '''7
+8 8
+-2'''
+"""
+
+#bug 1063
+
+const
+  KeyMax = 227
+  myconst = int((KeyMax + 31) / 32)
+
+type
+  FU = array[int((KeyMax + 31) / 32), cuint]
+
+echo FU.high
+
+type
+  PKeyboard* = ptr object
+  TKeyboardState* = object
+    display*: pointer
+    internal: array[int((KeyMax + 31)/32), cuint]
+
+echo myconst, " ", int((KeyMax + 31) / 32)
+
+#bug 1304 or something:
+
+const constArray: array[-3..2, int] = [-3, -2, -1, 0, 1, 2]
+
+echo constArray[-2]
+
diff --git a/tests/vm/tasmparser.nim b/tests/vm/tasmparser.nim
new file mode 100644
index 000000000..d70c629b6
--- /dev/null
+++ b/tests/vm/tasmparser.nim
@@ -0,0 +1,174 @@
+
+# bug #1513
+
+import os, parseutils, strutils, ropes, macros
+
+var
+  code {.compileTime.} = ""
+  start {.compileTime.} = 0
+  line {.compileTime.} = 1
+  cpp {.compileTime.} = ""
+  token {.compileTime.} = ""
+
+proc log(msg: string) {.compileTime.} =
+    echo msg
+
+proc asmx64() {.compileTime} =
+
+  #log "code = $1" % code
+
+  const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {"
+  const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} "
+
+  const xp = "x."
+
+  const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' }
+  const symbol = { '0'..'9' } + symbolStart
+  const eolComment = { ';' }
+  const endOfLine = { '\l', '\r' }
+  const leadingWhiteSpace = { ' ' }
+
+  const end_or_comment = endOfLine + eolComment + { '\0' }
+
+  const passthrough_start = { '{', '`' }
+  const passthrough_end = { '}', '`', '\0' }
+
+  const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start
+
+
+  proc abortAsmParse(err:string) =
+    discard
+
+  let codeLen = code.len
+  #let codeEnd = codeLen-1
+  cpp.add asmx64pre
+
+  #log "{$1}\n" % [code]
+
+  type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine
+
+  var state:asmParseState = leading
+
+  proc checkEnd(err:string) =
+    let ch = code[start]
+    if int(ch) == 0:
+      abortAsmParse(err)
+
+  proc get_passthrough() =
+    inc start
+    let prev_start = start
+    let prev_token = token
+    start += code.parseUntil(token, passthrough_end, start)
+    checkEnd("Failed to find passthrough end delimiter from offset $1 for:$2\n$3" % [$prev_start, $(code[prev_start-prev_token.len..prev_start]), token[1..token.len-1]])
+    inc start
+    cpp.add "`"
+    cpp.add token
+    cpp.add "`"
+
+  var inparse = true
+
+  proc checkCmdEnd() =
+    if codeLen == start:
+      state = endCmd
+      inparse = false
+
+  while inparse:
+    checkCmdEnd()
+
+    log("state=$1 start=$2" % [$state, $start])
+
+    case state:
+    of leading:
+
+      echo "b100 ", start
+      start += code.skipWhile(leadingWhiteSpace, start)
+      echo "b200 ", start
+      let ch = code[start]
+      if ch in endOfLine:
+        inc(line)
+        #echo "c100 ", start, ' ', code
+        start += code.skipWhile(endOfline, start)
+        #echo "c200 ", start, ' ', code
+        continue
+      elif ch in symbolStart:
+        state = mnemonic
+      elif ch in eolComment:
+        state = skipToEndOfLine
+      elif ch in passthrough_start:
+        get_passthrough()
+        echo "d100 ", start
+        start += code.parseUntil(token, end_or_symbol_or_comment_or_passthrough, start)
+        echo "d200 ", start
+        cpp.add token
+        state = mnemonic
+      elif int(ch) == 0:
+        break
+      else:
+        abortAsmParse("after '$3' illegal character at offset $1: $2" % [$start, $(int(ch)), token])
+
+    of mnemonic:
+      echo "e100 ", start
+      start += code.parseWhile(token, symbol, start)
+      echo "e200 ", start
+      cpp.add xp
+      cpp.add token
+      cpp.add "("
+      state = betweenArguments
+
+    of betweenArguments:
+      let tmp = start
+      let rcode = code
+      start += rcode.parseUntil(token, end_or_symbol_or_comment_or_passthrough, tmp)
+      cpp.add token
+
+      if codeLen <= start:
+        state = endCmd
+        continue
+
+      let ch = code[start]
+      if ch in passthrough_start:
+        get_passthrough()
+        continue
+      if(ch in {'x', 'X'}) and('0' == code[start-1]):
+        token = $(code[start])
+        cpp.add token
+        inc start
+        continue
+      state = arguments
+
+    of arguments:
+      if code[start] in end_or_comment:
+        state = endCmd
+        continue
+      start += code.parseWhile(token, symbol, start)
+      cpp.add xp
+      cpp.add token
+      state = betweenArguments
+
+    of endCmd:
+      cpp.add ");\n"
+      state = skipToEndOfLine
+
+    of skipToEndOfLine:
+      echo "a100 ", start
+      start += code.skipUntil(endOfLine, start)
+      echo "a200 ", start
+      start += code.skipWhile(endOfline, start)
+      echo "a300 ", start
+      inc line
+      state = leading
+
+  cpp.add asmx64post
+
+  echo($cpp)
+
+macro asmx64x(code_in:untyped) : typed =
+  code = $code_in
+  echo("code.len = $1, code = >>>$2<<<" % [$code.len, code])
+  asmx64()
+  discard result
+
+asmx64x """
+    mov rax, {m}
+    ret
+"""
diff --git a/tests/vm/tbitops.nim b/tests/vm/tbitops.nim
new file mode 100644
index 000000000..90d463ec9
--- /dev/null
+++ b/tests/vm/tbitops.nim
@@ -0,0 +1,45 @@
+discard """
+output: ""
+"""
+
+import strutils
+
+const x  = [1'i32, -1, -10, 10, -10, 10, -20, 30, -40, 50, 7 shl 28, -(7 shl 28), 7 shl 28, -(7 shl 28)]
+const y  = [-1'i32, 1, -10, -10, 10, 10, -20, -30, 40, 50, 1 shl 30, 1 shl 30, -(1 shl 30), -(1 shl 30)]
+
+const res_xor = block:
+  var tmp: seq[int64]
+  for i in 0 ..< x.len:
+    tmp.add(int64(x[i] xor y[i]))
+  tmp
+
+const res_and = block:
+  var tmp: seq[int64]
+  for i in 0 ..< x.len:
+    tmp.add(int64(x[i] and y[i]))
+  tmp
+
+const res_or = block:
+  var tmp: seq[int64]
+  for i in 0 ..< x.len:
+    tmp.add(int64(x[i] or y[i]))
+  tmp
+
+const res_not = block:
+  var tmp: seq[int64]
+  for i in 0 ..< x.len:
+    tmp.add(not x[i])
+  tmp
+
+let xx = x
+let yy = y
+
+for i in 0..<xx.len:
+  let z_xor = int64(xx[i] xor yy[i])
+  let z_and = int64(xx[i] and yy[i])
+  let z_or = int64(xx[i] or yy[i])
+  let z_not = int64(not xx[i])
+  doAssert(z_xor == res_xor[i], $i & ": " & $res_xor[i] & "  " & $z_xor)
+  doAssert(z_and == res_and[i], $i & ": " & $res_and[i] & "  " & $z_and)
+  doAssert(z_or == res_or[i], $i & ": " & $res_or[i] & "  " & $z_or)
+  doAssert(z_not == res_not[i], $i & ": " & $res_not[i] & "  " & $z_not)
diff --git a/tests/vm/tcastint.nim b/tests/vm/tcastint.nim
new file mode 100644
index 000000000..c306e4a31
--- /dev/null
+++ b/tests/vm/tcastint.nim
@@ -0,0 +1,309 @@
+import macros
+from stdtest/testutils import disableVM
+type
+  Dollar = distinct int
+  XCoord = distinct int32
+  Digit = range[-9..0]
+
+# those are necessary for comparisons below.
+proc `==`(x, y: Dollar): bool {.borrow.}
+proc `==`(x, y: XCoord): bool {.borrow.}
+
+proc dummy[T](x: T): T = x
+
+template roundTrip(a, T) =
+  let a2 = a # sideeffect safe
+  let b = cast[T](a2)
+  let c = cast[type(a2)](b)
+  doAssert c == a2
+
+proc test() =
+  let U8 = 0b1011_0010'u8
+  let I8 = 0b1011_0010'i8
+  let C8 = 0b1011_0010'u8.char
+  let C8_1 = 0b1011_0011'u8.char
+  let U16 = 0b10100111_00101000'u16
+  let I16 = 0b10100111_00101000'i16
+  let U32 = 0b11010101_10011100_11011010_01010000'u32
+  let I32 = 0b11010101_10011100_11011010_01010000'i32
+  let U64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'u64
+  let I64A = 0b11000100_00111111_01111100_10001010_10011001_01001000_01111010_00010001'i64
+  let U64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'u64
+  let I64B = 0b00110010_11011101_10001111_00101000_00000000_00000000_00000000_00000000'i64
+  when sizeof(int) == 8:
+    let UX = U64A.uint
+    let IX = I64A.int
+  elif sizeof(int) == 4:
+    let UX = U32.uint
+    let IX = I32.int
+  elif sizeof(int) == 2:
+    let UX = U16.uint
+    let IX = I16.int
+  else:
+    let UX = U8.uint
+    let IX = I8.int
+
+  doAssert(cast[char](I8) == C8)
+  doAssert(cast[uint8](I8) == U8)
+  doAssert(cast[uint16](I16) == U16)
+  doAssert(cast[uint32](I32) == U32)
+  doAssert(cast[uint64](I64A) == U64A)
+  doAssert(cast[uint64](I64B) == U64B)
+  doAssert(cast[int8](U8) == I8)
+  doAssert(cast[int16](U16) == I16)
+  doAssert(cast[int32](U32) == I32)
+  doAssert(cast[int64](U64A) == I64A)
+  doAssert(cast[int64](U64B) == I64B)
+  doAssert(cast[uint](IX) == UX)
+  doAssert(cast[int](UX) == IX)
+
+  doAssert(cast[char](I8 + 1) == C8_1)
+  doAssert(cast[uint8](I8 + 1) == U8 + 1)
+  doAssert(cast[uint16](I16 + 1) == U16 + 1)
+  doAssert(cast[uint32](I32 + 1) == U32 + 1)
+  doAssert(cast[uint64](I64A + 1) == U64A + 1)
+  doAssert(cast[uint64](I64B + 1) == U64B + 1)
+  doAssert(cast[int8](U8 + 1) == I8 + 1)
+  doAssert(cast[int16](U16 + 1) == I16 + 1)
+  doAssert(cast[int32](U32 + 1) == I32 + 1)
+  doAssert(cast[int64](U64A + 1) == I64A + 1)
+  doAssert(cast[int64](U64B + 1) == I64B + 1)
+  doAssert(cast[uint](IX + 1) == UX + 1)
+  doAssert(cast[int](UX + 1) == IX + 1)
+
+  doAssert(cast[char](I8.dummy) == C8.dummy)
+  doAssert(cast[uint8](I8.dummy) == U8.dummy)
+  doAssert(cast[uint16](I16.dummy) == U16.dummy)
+  doAssert(cast[uint32](I32.dummy) == U32.dummy)
+  doAssert(cast[uint64](I64A.dummy) == U64A.dummy)
+  doAssert(cast[uint64](I64B.dummy) == U64B.dummy)
+  doAssert(cast[int8](U8.dummy) == I8.dummy)
+  doAssert(cast[int16](U16.dummy) == I16.dummy)
+  doAssert(cast[int32](U32.dummy) == I32.dummy)
+  doAssert(cast[int64](U64A.dummy) == I64A.dummy)
+  doAssert(cast[int64](U64B.dummy) == I64B.dummy)
+  doAssert(cast[uint](IX.dummy) == UX.dummy)
+  doAssert(cast[int](UX.dummy) == IX.dummy)
+
+
+  doAssert(cast[int64](if false: U64B else: 0'u64) == (if false: I64B else: 0'i64))
+
+  block:
+    let raw = 3
+    let money = Dollar(raw) # this must be a variable, is otherwise constant folded.
+    doAssert(cast[int](money) == raw)
+    doAssert(cast[Dollar](raw) == money)
+  block:
+    let raw = 150'i32
+    let position = XCoord(raw) # this must be a variable, is otherwise constant folded.
+    doAssert(cast[int32](position) == raw)
+    doAssert(cast[XCoord](raw) == position)
+  block:
+    let raw = -2
+    let digit = Digit(raw)
+    doAssert(cast[int](digit) == raw)
+    doAssert(cast[Digit](raw) == digit)
+
+  block:
+    roundTrip(I64A, float)
+    roundTrip(I8, uint16)
+    roundTrip(I8, uint32)
+    roundTrip(I8, uint64)
+    doAssert cast[uint16](I8) == 65458'u16
+    doAssert cast[uint32](I8) == 4294967218'u32
+    doAssert cast[uint64](I8) == 18446744073709551538'u64
+    doAssert cast[uint32](I64A) == 2571663889'u32
+    doAssert cast[uint16](I64A) == 31249
+    doAssert cast[char](I64A).ord == 17
+    doAssert compiles(cast[float32](I64A))
+
+  disableVM: # xxx Error: VM does not support 'cast' from tyInt64 to tyFloat32
+    doAssert cast[uint32](cast[float32](I64A)) == 2571663889'u32
+
+const prerecordedResults = [
+  # cast to char
+  "\0", "\255",
+  "\0", "\255",
+  "\0", "\255",
+  "\0", "\255",
+  "\0", "\255",
+  "\128", "\127",
+  "\0", "\255",
+  "\0", "\255",
+  "\0", "\255",
+  # cast to uint8
+  "0", "255",
+  "0", "255",
+  "0", "255",
+  "0", "255",
+  "0", "255",
+  "128", "127",
+  "0", "255",
+  "0", "255",
+  "0", "255",
+  # cast to uint16
+  "0", "255",
+  "0", "255",
+  "0", "65535",
+  "0", "65535",
+  "0", "65535",
+  "65408", "127",
+  "32768", "32767",
+  "0", "65535",
+  "0", "65535",
+  # cast to uint32
+  "0", "255",
+  "0", "255",
+  "0", "65535",
+  "0", "4294967295",
+  "0", "4294967295",
+  "4294967168", "127",
+  "4294934528", "32767",
+  "2147483648", "2147483647",
+  "0", "4294967295",
+  # cast to uint64
+  "0", "255",
+  "0", "255",
+  "0", "65535",
+  "0", "4294967295",
+  "0", "18446744073709551615",
+  "18446744073709551488", "127",
+  "18446744073709518848", "32767",
+  "18446744071562067968", "2147483647",
+  "9223372036854775808", "9223372036854775807",
+  # cast to int8
+  "0", "-1",
+  "0", "-1",
+  "0", "-1",
+  "0", "-1",
+  "0", "-1",
+  "-128", "127",
+  "0", "-1",
+  "0", "-1",
+  "0", "-1",
+  # cast to int16
+  "0", "255",
+  "0", "255",
+  "0", "-1",
+  "0", "-1",
+  "0", "-1",
+  "-128", "127",
+  "-32768", "32767",
+  "0", "-1",
+  "0", "-1",
+  # cast to int32
+  "0", "255",
+  "0", "255",
+  "0", "65535",
+  "0", "-1",
+  "0", "-1",
+  "-128", "127",
+  "-32768", "32767",
+  "-2147483648", "2147483647",
+  "0", "-1",
+  # cast to int64
+  "0", "255",
+  "0", "255",
+  "0", "65535",
+  "0", "4294967295",
+  "0", "-1",
+  "-128", "127",
+  "-32768", "32767",
+  "-2147483648", "2147483647",
+  "-9223372036854775808", "9223372036854775807",
+]
+
+proc free_integer_casting() =
+  # cast from every integer type to every type and ensure same
+  # behavior in vm and execution time.
+  macro bar(arg: untyped) =
+    result = newStmtList()
+    var i = 0
+    for it1 in arg:
+      let typA = it1[0]
+      for it2 in arg:
+        let lowB = it2[1]
+        let highB = it2[2]
+        let castExpr1 = nnkCast.newTree(typA, lowB)
+        let castExpr2 = nnkCast.newTree(typA, highB)
+        let lit1 = newLit(prerecordedResults[i*2])
+        let lit2 = newLit(prerecordedResults[i*2+1])
+        result.add quote do:
+          doAssert($(`castExpr1`) == `lit1`)
+          doAssert($(`castExpr2`) == `lit2`)
+        i += 1
+
+  bar([
+    (char, '\0', '\255'),
+    (uint8, 0'u8, 0xff'u8),
+    (uint16, 0'u16, 0xffff'u16),
+    (uint32, 0'u32, 0xffffffff'u32),
+    (uint64, 0'u64, 0xffffffffffffffff'u64),
+    (int8,  0x80'i8, 0x7f'i8),
+    (int16, 0x8000'i16, 0x7fff'i16),
+    (int32, 0x80000000'i32, 0x7fffffff'i32),
+    (int64, 0x8000000000000000'i64, 0x7fffffffffffffff'i64)
+  ])
+
+proc test_float_cast =
+
+  const
+    exp_bias = 1023'i64
+    exp_shift = 52
+    exp_mask = 0x7ff'i64 shl exp_shift
+    mantissa_mask = 0xfffffffffffff'i64
+
+  let f = 8.0
+  let fx = cast[int64](f)
+  let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
+  let mantissa = fx and mantissa_mask
+  doAssert(exponent == 3, $exponent)
+  doAssert(mantissa == 0, $mantissa)
+
+  # construct 2^N float, where N is integer
+  let x = -2'i64
+  let xx = (x + exp_bias) shl exp_shift
+  let xf = cast[float](xx)
+  doAssert(xf == 0.25, $xf)
+
+proc test_float32_cast =
+
+  const
+    exp_bias = 127'i32
+    exp_shift = 23
+    exp_mask = 0x7f800000'i32
+    mantissa_mask = 0x007ffff'i32
+
+  let f = -0.5'f32
+  let fx = cast[int32](f)
+  let exponent = ((fx and exp_mask) shr exp_shift) - exp_bias
+  let mantissa = fx and mantissa_mask
+  doAssert(exponent == -1, $exponent)
+  doAssert(mantissa == 0, $mantissa)
+
+  # construct 2^N float32 where N is integer
+  let x = 4'i32
+  let xx = (x + exp_bias) shl exp_shift
+  let xf = cast[float32](xx)
+  doAssert(xf == 16.0'f32, $xf)
+
+proc test_float32_castB() =
+  let a: float32 = -123.125
+  let b = cast[int32](a)
+  let c = cast[uint32](a)
+  doAssert b == -1024049152
+  doAssert cast[uint64](b) == 18446744072685502464'u64
+  doAssert c == 3270918144'u32
+  # ensure the unused bits in the internal representation don't have
+  # any surprising content.
+  doAssert cast[uint64](c) == 3270918144'u64
+
+template main() =
+  test()
+  test_float_cast()
+  test_float32_cast()
+  free_integer_casting()
+  test_float32_castB()
+
+static: main()
+main()
diff --git a/tests/vm/tcgemptycallarg.nim b/tests/vm/tcgemptycallarg.nim
new file mode 100644
index 000000000..1bedb5070
--- /dev/null
+++ b/tests/vm/tcgemptycallarg.nim
@@ -0,0 +1,3 @@
+static:
+  doAssertRaises(ValueError):
+    raise newException(ValueError, "Yes")
diff --git a/tests/vm/tclosureiterator.nim b/tests/vm/tclosureiterator.nim
new file mode 100644
index 000000000..c909392d5
--- /dev/null
+++ b/tests/vm/tclosureiterator.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "Closure iterators are not supported by VM!"
+"""
+
+iterator iter*(): int {.closure.} =
+  yield 3
+
+static:
+  var x = iter
diff --git a/tests/vm/tcnstseq.nim b/tests/vm/tcnstseq.nim
new file mode 100644
index 000000000..5679a6e37
--- /dev/null
+++ b/tests/vm/tcnstseq.nim
@@ -0,0 +1,68 @@
+discard """
+output: '''
+AngelikaAnneAnnaAnkaAnja
+AngelikaAnneAnnaAnkaAnja
+AngelikaAnneAnnaAnkaAnja
+onetwothree
+onetwothree
+onetwothree
+one1two2three3
+'''
+"""
+# Test the new implicit conversion from sequences to arrays in a constant
+# context.
+
+import strutils
+
+
+block t1:
+  const
+    myWords = "Angelika Anne Anna Anka Anja".split()
+
+  for x in items(myWords):
+    write(stdout, x) #OUT AngelikaAnneAnnaAnkaAnja
+  echo ""
+
+
+block t2:
+  const
+    myWords = @["Angelika", "Anne", "Anna", "Anka", "Anja"]
+
+  for i in 0 .. high(myWords):
+    write(stdout, myWords[i]) #OUT AngelikaAnneAnnaAnkaAnja
+  echo ""
+
+
+block t3:
+  for w in items(["Angelika", "Anne", "Anna", "Anka", "Anja"]):
+    write(stdout, w) #OUT AngelikaAnneAnnaAnkaAnja
+  echo ""
+
+
+block t2656:
+  iterator it1(args: seq[string]): string =
+    for s in args: yield s
+  iterator it2(args: seq[string]): string {.closure.} =
+    for s in args: yield s
+  iterator it3(args: openArray[string]): string {.closure.} =
+    for s in args: yield s
+  iterator it4(args: openArray[(string, string)]): string {.closure.} =
+    for s1, s2 in items(args): yield s1 & s2
+
+  block:
+    const myConstSeq = @["one", "two", "three"]
+    for s in it1(myConstSeq):
+      stdout.write s
+    echo ""
+    for s in it2(myConstSeq):
+      stdout.write s
+    echo ""
+    for s in it3(myConstSeq):
+      stdout.write s
+    echo ""
+
+  block:
+    const myConstSeq = @[("one", "1"), ("two", "2"), ("three", "3")]
+    for s in it4(myConstSeq):
+      stdout.write s
+    echo ""
diff --git a/tests/vm/tcompilesetting.nim b/tests/vm/tcompilesetting.nim
new file mode 100644
index 000000000..d6c08e70f
--- /dev/null
+++ b/tests/vm/tcompilesetting.nim
@@ -0,0 +1,18 @@
+discard """
+cmd: "nim c --nimcache:build/myNimCache --nimblePath:myNimblePath --gc:arc $file"
+joinable: false
+"""
+
+import std/[strutils,compilesettings]
+from std/os import fileExists, `/`
+
+template main =
+  doAssert querySetting(nimcacheDir) == nimcacheDir.querySetting
+  doAssert "myNimCache" in nimcacheDir.querySetting
+  doAssert "myNimblePath" in nimblePaths.querySettingSeq[0]
+  doAssert querySetting(backend) == "c"
+  doAssert fileExists(libPath.querySetting / "system.nim")
+  doAssert querySetting(mm) == "arc"
+
+static: main()
+main()
diff --git a/tests/vm/tcompiletimerange.nim b/tests/vm/tcompiletimerange.nim
new file mode 100644
index 000000000..cd675b4a3
--- /dev/null
+++ b/tests/vm/tcompiletimerange.nim
@@ -0,0 +1,28 @@
+discard """
+"""
+
+# issue #8199
+
+const rangesGCHoldEnabled = true # not defined(rangesDisableGCHold)
+
+type
+  # A view into immutable array
+  Range*[T] {.shallow.} = object
+    when rangesGCHoldEnabled:
+      gcHold: seq[T] # 0
+    start: ptr T # 1
+    mLen: int32 # 2
+
+type
+  BytesRange* = Range[byte]
+  NibblesRange* = object
+    bytes: BytesRange
+
+const
+  zeroBytesRange* = BytesRange()
+
+proc initNibbleRange*(bytes: BytesRange): NibblesRange =
+  result.bytes = bytes
+
+const
+  zeroNibblesRange* = initNibbleRange(zeroBytesRange)
diff --git a/tests/vm/tcompiletimesideeffects.nim b/tests/vm/tcompiletimesideeffects.nim
new file mode 100644
index 000000000..4cd57b3bd
--- /dev/null
+++ b/tests/vm/tcompiletimesideeffects.nim
@@ -0,0 +1,42 @@
+discard """
+  output:
+'''
+@[0, 1, 2]
+@[3, 4, 5]
+@[0, 1, 2]
+3
+4
+'''
+"""
+
+template runNTimes(n: int, f : untyped) : untyped =
+  var accum: seq[type(f)]
+  for i in 0..n-1:
+    accum.add(f)
+  accum
+
+var state {.compileTime.} : int = 0
+proc fill(): int {.compileTime.} =
+  result = state
+  inc state
+
+# invoke fill() at compile time as a compile time expression
+const C1 = runNTimes(3, fill())
+echo C1
+
+# invoke fill() at compile time as a set of compile time statements
+const C2 =
+  block:
+    runNTimes(3, fill())
+echo C2
+
+# invoke fill() at compile time after a compile time reset of state
+const C3 =
+  block:
+    state = 0
+    runNTimes(3, fill())
+echo C3
+
+# evaluate fill() at compile time and use the results at runtime
+echo fill()
+echo fill()
diff --git a/tests/vm/tcompiletimetable.nim b/tests/vm/tcompiletimetable.nim
new file mode 100644
index 000000000..1db490f1a
--- /dev/null
+++ b/tests/vm/tcompiletimetable.nim
@@ -0,0 +1,62 @@
+discard """
+  nimout: '''
+2
+3
+4:2
+Got Hi
+Got Hey
+'''
+  output:'''
+a
+b
+c
+'''
+"""
+
+# bug #404
+
+import macros, tables, strtabs
+
+var ZOOT{.compileTime.} = initTable[int, int](2)
+var iii {.compiletime.} = 1
+
+macro zoo: untyped =
+  ZOOT[iii] = iii*2
+  inc iii
+  echo iii
+
+zoo
+zoo
+
+
+macro tupleUnpack: untyped =
+  var (y,z) = (4, 2)
+  echo y, ":", z
+
+tupleUnpack
+
+# bug #903
+
+var x {.compileTime.}: StringTableRef
+
+macro addStuff(stuff, body: untyped): untyped =
+  result = newNimNode(nnkStmtList)
+
+  if x.isNil:
+    x = newStringTable(modeStyleInsensitive)
+  x[$stuff] = ""
+
+macro dump(): untyped =
+  result = newNimNode(nnkStmtList)
+  for y in x.keys: echo "Got ", y
+
+addStuff("Hey"): echo "Hey"
+addStuff("Hi"): echo "Hi"
+dump()
+
+# ensure .compileTime vars can be used at runtime:
+import macros
+
+var xzzzz {.compileTime.}: array[3, string] = ["a", "b", "c"]
+
+for i in 0..high(xzzzz): echo xzzzz[i]
diff --git a/tests/vm/tcomponent.nim b/tests/vm/tcomponent.nim
new file mode 100644
index 000000000..b509bc5d7
--- /dev/null
+++ b/tests/vm/tcomponent.nim
@@ -0,0 +1,132 @@
+discard """
+  output: '''`:)` @ 0,0
+FOO: blah'''
+"""
+
+#
+# magic.nim
+#
+
+# bug #3729
+
+import macros, sequtils, tables
+import strutils
+import sugar, meta
+
+type
+  Component = object
+    fields: FieldSeq
+    field_index: seq[string]
+    procs: ProcSeq
+    procs_index: seq[string]
+
+  Registry = object
+    field_index: seq[string]
+    procs_index: seq[string]
+    components: Table[string, Component]
+    builtin: Component
+
+proc newRegistry(): Registry =
+  result.field_index = @[]
+  result.procs_index = @[]
+  result.components = initTable[string, Component]()
+
+var registry {.compileTime.} = newRegistry()
+
+proc validateComponent(r: var Registry, name: string, c: Component) =
+  if r.components.hasKey(name):
+    let msg = "`component` macro cannot consume duplicated identifier: " & name
+    raise newException(ValueError, msg)
+
+  for field_name in c.field_index:
+    if r.field_index.contains(field_name):
+      let msg = "`component` macro cannot delcare duplicated field: " & field_name
+      raise newException(ValueError, msg)
+    r.field_index.add(field_name)
+
+  for proc_name in c.procs_index:
+    if r.procs_index.contains(proc_name):
+      let msg = "`component` macro cannot delcare duplicated proc: " & proc_name
+      raise newException(ValueError, msg)
+    r.procs_index.add(proc_name)
+
+proc addComponent(r: var Registry, name: string, c: Component) =
+  r.validateComponent(name, c)
+  r.components.add(name, c)
+
+proc parse_component(body: NimNode): Component =
+  result.field_index = @[]
+  result.procs_index = @[]
+  for node in body:
+    case node.kind:
+      of nnkVarSection:
+        result.fields = newFieldSeq(node)
+        for field in result.fields:
+          result.field_index.add(field.identifier.name)
+      of nnkMethodDef, nnkProcDef:
+        let new_proc = meta.newProc(node)
+        result.procs = result.procs & @[new_proc]
+        for procdef in result.procs:
+          result.procs_index.add(procdef.identifier.name)
+      else: discard
+
+macro component*(name, body: untyped): typed =
+  let component = parse_component(body)
+  registry.addComponent($name, component)
+  parseStmt("discard")
+
+macro component_builtins(body: untyped): typed =
+  let builtin = parse_component(body)
+  registry.field_index = builtin.field_index
+  registry.procs_index = builtin.procs_index
+  registry.builtin = builtin
+
+proc bind_methods*(component: var Component, identifier: Ident): seq[NimNode] =
+  result = @[]
+  for procdef in component.procs.mitems:
+    let this_field = newField(newIdent("this"), identifier)
+    procdef.params.insert(this_field, 0)
+    result.add(procdef.render())
+
+macro bind_components*(type_name, component_names: untyped): typed =
+  result = newStmtList()
+  let identifier = newIdent(type_name)
+  let components = newBracket(component_names)
+  var entity_type = newTypeDef(identifier, true, "object", "RootObj")
+  entity_type.fields = registry.builtin.fields
+  for component_name, component in registry.components:
+    if components.contains(newIdent(component_name)):
+      entity_type.fields = entity_type.fields & component.fields
+  # TODO why doesn't the following snippet work instead of the one above?
+  # for name in components:
+  #   echo "Registering $1 to $2" % [name.name, identifier.name]
+  #   let component = registry.components[name.name]
+  #   entity_type.fields = entity_type.fields & component.fields
+  let type_section: TypeDefSeq = @[entity_type]
+  result.add type_section.render
+  var builtin = registry.builtin
+  let builtin_methods = bind_methods(builtin, identifier)
+  for builtin_proc in builtin_methods:
+    result.add(builtin_proc)
+  echo "SIGSEV here"
+  for component in registry.components.mvalues():
+    for method_proc in bind_methods(component, identifier):
+      result.add(method_proc)
+
+component_builtins:
+  proc foo(msg: string) =
+    echo "FOO: $1" % msg
+
+component position:
+  var x*, y*: int
+
+component name:
+  var name*: string
+  proc render*(x, y: int) = echo "`$1` @ $2,$3" % [this.name, $x, $y]
+
+bind_components(Entity, [position, name])
+
+var e = new(Entity)
+e.name = ":)"
+e.render(e.x, e.y)
+e.foo("blah")
diff --git a/tests/vm/tconst.nim b/tests/vm/tconst.nim
new file mode 100644
index 000000000..5cfe7533e
--- /dev/null
+++ b/tests/vm/tconst.nim
@@ -0,0 +1,58 @@
+discard """
+  targets: "c cpp js"
+"""
+
+import std/strutils
+
+template forceConst(a: untyped): untyped =
+  ## Force evaluation at CT, but `static(a)` is simpler
+  const ret = a
+  ret
+
+proc isNimVm(): bool =
+  when nimvm: result = true
+  else: result = false
+
+block:
+  doAssert forceConst(isNimVm())
+  doAssert not isNimVm()
+  doAssert forceConst(isNimVm()) == static(isNimVm())
+  doAssert forceConst(isNimVm()) == isNimVm().static
+
+template main() =
+  # xxx merge more const related tests here
+  const ct = CompileTime
+    # refs https://github.com/timotheecour/Nim/issues/718, apparently `CompileTime`
+    # isn't cached, which seems surprising.
+  block:
+    const
+      a = """
+    Version $1|
+    Compiled at: $2, $3
+    """ % [NimVersion & spaces(44-len(NimVersion)), CompileDate, ct]
+    let b = $a
+    doAssert ct in b, $(b, ct)
+    doAssert NimVersion in b
+
+  block: # Test for fix on broken const unpacking
+    template mytemp() =
+      const
+        (x, increment) = (4, true)
+        a = 100
+      discard (x, increment, a)
+    mytemp()
+
+  block: # bug #12334
+    block:
+      const b: cstring = "foo"
+      var c = b
+      doAssert c == "foo"
+    block:
+      const a = "foo"
+      const b: cstring = a
+      var c = b
+      doAssert c == "foo"
+
+
+static: main()
+main()
diff --git a/tests/vm/tconst_float_as_int.nim b/tests/vm/tconst_float_as_int.nim
new file mode 100644
index 000000000..ed84ec194
--- /dev/null
+++ b/tests/vm/tconst_float_as_int.nim
@@ -0,0 +1,3 @@
+
+# bug #4619
+const x: float = 0
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/tconstobj.nim b/tests/vm/tconstobj.nim
new file mode 100644
index 000000000..7dc20a0ba
--- /dev/null
+++ b/tests/vm/tconstobj.nim
@@ -0,0 +1,95 @@
+discard """
+  output: '''
+(name: "hello")
+(-1, 0)
+(FirstName: "James", LastName: "Franco")
+[1, 2, 3]
+'''
+"""
+
+# bug #2774, bug #3195
+type Foo = object
+  name: string
+
+const fooArray = [
+  Foo(name: "hello")
+]
+
+echo fooArray[0]
+
+type
+    Position = object
+        x, y: int
+
+proc `$`(pos: Position): string =
+    result = "(" & $pos.x & ", " & $pos.y & ")"
+
+proc newPos(x, y: int): Position =
+    result = Position(x: x, y: y)
+
+const
+     offset: array[1..4, Position] = [
+         newPos(-1, 0),
+         newPos(1, 0),
+         newPos(0, -1),
+         newPos(0, 1)
+     ]
+
+echo offset[1]
+
+# bug #1547
+import tables
+
+type Person* = object
+    FirstName*: string
+    LastName*: string
+
+let people = {
+    "001": Person(FirstName: "James", LastName: "Franco")
+}.toTable()
+
+echo people["001"]
+
+# Object downconversion should not copy
+
+type
+  SomeBaseObj  {.inheritable.} = object of RootObj
+    txt : string
+  InheritedFromBase = object of SomeBaseObj
+    other : string
+
+proc initBase(sbo: var SomeBaseObj) =
+  sbo.txt = "Initialized string from base"
+
+static:
+  var ifb2: InheritedFromBase
+  initBase(SomeBaseObj(ifb2))
+  echo repr(ifb2)
+  doAssert(ifb2.txt == "Initialized string from base")
+
+static: # issue #11861
+  var ifb2: InheritedFromBase
+  initBase(ifb2)
+  doAssert(ifb2.txt == "Initialized string from base")
+
+
+static: # issue #15662
+  proc a(T: typedesc) = echo T.type
+  a((int, int))
+
+# bug #16069
+type
+  E = enum
+    val1, val2
+  Obj = object
+    case k: E
+    of val1:
+      x: array[3, int]
+    of val2:
+      y: uint32
+
+const
+  foo = [1, 2, 3]
+  arr = Obj(k: val1, x: foo)
+
+echo arr.x
diff --git a/tests/vm/tconstprocassignments.nim b/tests/vm/tconstprocassignments.nim
new file mode 100644
index 000000000..0e2d2ed16
--- /dev/null
+++ b/tests/vm/tconstprocassignments.nim
@@ -0,0 +1,18 @@
+discard """
+  output: '''
+100
+100
+'''
+"""
+
+proc f():int {.compileTime.} = 100
+
+const F = f
+echo F()
+
+const G = proc ():int =
+  let x = f
+  let y = x
+  y()
+
+echo G()
diff --git a/tests/vm/tconstresem.nim b/tests/vm/tconstresem.nim
new file mode 100644
index 000000000..4526cb891
--- /dev/null
+++ b/tests/vm/tconstresem.nim
@@ -0,0 +1,10 @@
+block: # issue #19849
+  type
+    Vec2[T] = object
+      x, y: T
+    Vec2i = Vec2[int]
+  template getX(p: Vec2i): int = p.x
+  let x = getX:
+    const t = Vec2i(x: 1, y: 2)
+    t
+  doAssert x == 1
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
new file mode 100644
index 000000000..152a33cba
--- /dev/null
+++ b/tests/vm/tconsttable.nim
@@ -0,0 +1,34 @@
+discard """
+  output: '''is
+finally
+nice!'''
+"""
+
+import tables
+
+const
+  foo = {"ah": "finally", "this": "is", "possible.": "nice!"}.toTable()
+
+# protect against overly smart compiler:
+var x = "this"
+
+echo foo[x]
+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/tconsttable2.nim b/tests/vm/tconsttable2.nim
new file mode 100644
index 000000000..5a392fb66
--- /dev/null
+++ b/tests/vm/tconsttable2.nim
@@ -0,0 +1,81 @@
+discard """
+  nimout: '''61'''
+"""
+
+# bug #2297
+
+import tables
+
+proc html5tags*(): TableRef[string, string] =
+  var html5tagsCache: Table[string,string]
+  if true:
+    new(result)
+    html5tagsCache = initTable[string, string]()
+    html5tagsCache["a"] = "a"
+    html5tagsCache["abbr"] = "abbr"
+    html5tagsCache["b"] = "b"
+    html5tagsCache["element"] = "element"
+    html5tagsCache["embed"] = "embed"
+    html5tagsCache["fieldset"] = "fieldset"
+    html5tagsCache["figcaption"] = "figcaption"
+    html5tagsCache["figure"] = "figure"
+    html5tagsCache["footer"] = "footer"
+    html5tagsCache["header"] = "header"
+    html5tagsCache["form"] = "form"
+    html5tagsCache["head"] = "head"
+    html5tagsCache["hr"] = "hr"
+    html5tagsCache["html"] = "html"
+    html5tagsCache["iframe"] = "iframe"
+    html5tagsCache["img"] = "img"
+    html5tagsCache["input"] = "input"
+    html5tagsCache["keygen"] = "keygen"
+    html5tagsCache["label"] = "label"
+    html5tagsCache["legend"] = "legend"
+    html5tagsCache["li"] = "li"
+    html5tagsCache["link"] = "link"
+    html5tagsCache["main"] = "main"
+    html5tagsCache["map"] = "map"
+    html5tagsCache["menu"] = "menu"
+    html5tagsCache["menuitem"] = "menuitem"
+    html5tagsCache["meta"] = "meta"
+    html5tagsCache["meter"] = "master"
+    html5tagsCache["noscript"] = "noscript"
+    html5tagsCache["object"] = "object"
+    html5tagsCache["ol"] = "ol"
+    html5tagsCache["optgroup"] = "optgroup"
+    html5tagsCache["option"] = "option"
+    html5tagsCache["output"] = "output"
+    html5tagsCache["p"] = "p"
+    html5tagsCache["pre"] = "pre"
+    html5tagsCache["param"] = "param"
+    html5tagsCache["progress"] = "progress"
+    html5tagsCache["q"] = "q"
+    html5tagsCache["rp"] = "rp"
+    html5tagsCache["rt"] = "rt"
+    html5tagsCache["ruby"] = "ruby"
+    html5tagsCache["s"] = "s"
+    html5tagsCache["script"] = "script"
+    html5tagsCache["select"] = "select"
+    html5tagsCache["source"] = "source"
+    html5tagsCache["style"] = "style"
+    html5tagsCache["summary"] = "summary"
+    html5tagsCache["table"] = "table"
+    html5tagsCache["tbody"] = "tbody"
+    html5tagsCache["thead"] = "thead"
+    html5tagsCache["td"] = "td"
+    html5tagsCache["th"] = "th"
+    html5tagsCache["template"] = "template"
+    html5tagsCache["textarea"] = "textarea"
+    html5tagsCache["time"] = "time"
+    html5tagsCache["title"] = "title"
+    html5tagsCache["tr"] = "tr"
+    html5tagsCache["track"] = "track"
+    html5tagsCache["ul"] = "ul"
+    html5tagsCache["video"] = "video"
+  result[] = html5tagsCache
+
+static:
+  var i = 0
+  for key, value in html5tags().pairs():
+    inc i
+  echo i
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/tcopy_global_var.nim b/tests/vm/tcopy_global_var.nim
new file mode 100644
index 000000000..eadd27b9a
--- /dev/null
+++ b/tests/vm/tcopy_global_var.nim
@@ -0,0 +1,30 @@
+discard """
+  nimout: "static done"
+"""
+
+# bug #5269
+
+proc assertEq[T](arg0, arg1: T): void =
+  assert arg0 == arg1, $arg0 & " == " & $arg1
+
+type
+  MyType = object
+    str: string
+    a: int
+
+block:
+  var localValue = MyType(str: "Original strning, (OK)", a: 0)
+  var valueCopy = localValue
+  valueCopy.a = 123
+  valueCopy.str = "Modified strning, (not OK when in localValue)"
+  assertEq(localValue.str, "Original strning, (OK)")
+  assertEq(localValue.a,   0)
+
+static:
+  var localValue = MyType(str: "Original strning, (OK)", a: 0)
+  var valueCopy = localValue
+  valueCopy.a = 123
+  valueCopy.str = "Modified strning, (not OK when in localValue)"
+  assertEq(localValue.str, "Original strning, (OK)")
+  assertEq(localValue.a,   0)
+  echo "static done"
diff --git a/tests/vm/teval1.nim b/tests/vm/teval1.nim
new file mode 100644
index 000000000..0316ea238
--- /dev/null
+++ b/tests/vm/teval1.nim
@@ -0,0 +1,42 @@
+
+discard """
+nimout: "##"
+"""
+
+import macros
+
+proc testProc: string {.compileTime.} =
+  result = ""
+  result = result & ""
+
+when true:
+  macro test(n: untyped): untyped =
+    result = newNimNode(nnkStmtList)
+    echo "#", testProc(), "#"
+  test:
+    "hi"
+
+const
+  x = testProc()
+
+doAssert x == ""
+
+# bug #1310
+static:
+  var i, j: set[int8] = {}
+  var k = i + j
+
+type
+  Obj = object
+    x: int
+
+converter toObj(x: int): Obj = Obj(x: x)
+
+# bug #10514
+block:
+  const
+    b: Obj = 42
+    bar = [b]
+
+  let i_runtime = 0
+  doAssert bar[i_runtime] == b
diff --git a/tests/vm/texception.nim b/tests/vm/texception.nim
new file mode 100644
index 000000000..65a781281
--- /dev/null
+++ b/tests/vm/texception.nim
@@ -0,0 +1,14 @@
+proc someFunc() =
+  try:
+    raise newException(ValueError, "message")
+  except ValueError as err:
+    doAssert err.name == "ValueError"
+    doAssert err.msg == "message"
+    raise
+
+static:
+  try:
+    someFunc()
+  except:
+    discard
+  
\ No newline at end of file
diff --git a/tests/vm/texcl.nim b/tests/vm/texcl.nim
new file mode 100644
index 000000000..41975f27b
--- /dev/null
+++ b/tests/vm/texcl.nim
@@ -0,0 +1,27 @@
+discard """
+  output: '''false'''
+"""
+
+import macros
+
+type
+  nlOptions = enum
+    nloNone
+    nloDebug
+
+var nlOpts {.compileTime.} = {nloDebug}
+
+proc initOpts(): set[nlOptions] =
+  result.incl nloDebug
+  result.incl nloNone
+  result.excl nloDebug
+
+const cOpts = initOpts()
+
+macro nlo() =
+  nlOpts.incl(nloNone)
+  nlOpts.excl(nloDebug)
+  result = newEmptyNode()
+
+nlo()
+echo nloDebug in cOpts
diff --git a/tests/vm/textensionmap.nim b/tests/vm/textensionmap.nim
new file mode 100644
index 000000000..7ada1880d
--- /dev/null
+++ b/tests/vm/textensionmap.nim
@@ -0,0 +1,13 @@
+
+# bug #5237
+
+import tables
+import sets
+import sequtils
+
+
+const EXTENSIONMAP = {
+  "c": @["*.c", "*.h"],
+}.toTable()
+
+const EXTENSIONS = toHashSet(concat(toSeq(EXTENSIONMAP.values())))
diff --git a/tests/vm/tfarjump.nim b/tests/vm/tfarjump.nim
new file mode 100644
index 000000000..f5798b8d2
--- /dev/null
+++ b/tests/vm/tfarjump.nim
@@ -0,0 +1,14 @@
+# Test a VM relative jump with an offset larger then 32767 instructions.
+
+import macros
+
+static:
+  var a = 0
+  macro foo(): untyped =
+    let s = newStmtList()
+    for i in 1..6554:
+      s.add nnkCommand.newTree(ident("inc"), ident("a"))
+    quote do:
+      if true:
+        `s`
+  foo()
diff --git a/tests/vm/tfibconst.nim b/tests/vm/tfibconst.nim
new file mode 100644
index 000000000..cca6dd84f
--- /dev/null
+++ b/tests/vm/tfibconst.nim
@@ -0,0 +1,43 @@
+discard """
+  nimout: '''
+Fibonacci sequence: 0, 1, 1, 2, 3
+Sequence continues: 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610
+'''
+"""
+
+
+import strformat
+
+var fib_n {.compileTime.}: int
+var fib_prev {.compileTime.}: int
+var fib_prev_prev {.compileTime.}: int
+
+proc next_fib(): int {.compileTime.} =
+  let fib = if fib_n < 2:
+    fib_n
+  else:
+    fib_prev_prev + fib_prev
+  inc(fib_n)
+  fib_prev_prev = fib_prev
+  fib_prev = fib
+  fib
+
+const f0 = next_fib()
+const f1 = next_fib()
+const f2 = next_fib()
+const f3 = next_fib()
+const f4 = next_fib()
+
+static:
+  echo fmt"Fibonacci sequence: {f0}, {f1}, {f2}, {f3}, {f4}"
+
+const fib_continues = block:
+  var result = fmt"Sequence continues: "
+  for i in 0..10:
+    if i > 0:
+      add(result, ", ")
+    add(result, $next_fib())
+  result
+
+static:
+  echo fib_continues
\ No newline at end of file
diff --git a/tests/vm/tfile_rw.nim b/tests/vm/tfile_rw.nim
new file mode 100644
index 000000000..439886e49
--- /dev/null
+++ b/tests/vm/tfile_rw.nim
@@ -0,0 +1,22 @@
+# test file read write in vm
+
+import os, strutils
+
+const filename  = splitFile(currentSourcePath).dir / "tfile_rw.txt"
+
+const mytext = "line1\nline2\nline3"
+static:
+  writeFile(filename, mytext)
+const myfile_str = staticRead(filename)
+const myfile_str2 = readFile(filename)
+const myfile_str_seq = readLines(filename, 3)
+
+static:
+  doAssert myfile_str == mytext
+  doAssert myfile_str2 == mytext
+  doAssert myfile_str_seq[0] == "line1"
+  doAssert myfile_str_seq[1] == "line2"
+  doAssert myfile_str_seq.join("\n") == mytext
+
+
+removeFile(filename)
diff --git a/tests/vm/tforwardproc.nim b/tests/vm/tforwardproc.nim
new file mode 100644
index 000000000..bcd929f0e
--- /dev/null
+++ b/tests/vm/tforwardproc.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "cannot evaluate at compile time: initArray"
+  line: 11
+"""
+
+# bug #3066
+
+proc initArray(): array[10, int]
+
+const
+  someTable = initArray()
+
+proc initArray(): array[10, int] =
+  for f in 0..<10:
+    result[f] = 3
+
+when true: echo repr(someTable)
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/tgloballetfrommacro.nim b/tests/vm/tgloballetfrommacro.nim
new file mode 100644
index 000000000..4be09b56e
--- /dev/null
+++ b/tests/vm/tgloballetfrommacro.nim
@@ -0,0 +1,13 @@
+discard """
+errormsg: "cannot evaluate at compile time: BUILTIN_NAMES"
+line: 11
+"""
+
+import sets
+
+let BUILTIN_NAMES = toHashSet(["int8", "int16", "int32", "int64"])
+
+macro test*(): bool =
+  echo "int64" notin BUILTIN_NAMES
+
+echo test()
diff --git a/tests/vm/tgorge.bat b/tests/vm/tgorge.bat
new file mode 100644
index 000000000..24d365842
--- /dev/null
+++ b/tests/vm/tgorge.bat
@@ -0,0 +1 @@
+@echo gorge test
\ No newline at end of file
diff --git a/tests/vm/tgorge.nim b/tests/vm/tgorge.nim
new file mode 100644
index 000000000..1f77d2c95
--- /dev/null
+++ b/tests/vm/tgorge.nim
@@ -0,0 +1,29 @@
+discard """
+disabled: "windows"
+"""
+
+# If your os is windows and this test fails for you locally, please
+# check what is going wrong.
+
+import os
+
+template getScriptDir(): string =
+  parentDir(instantiationInfo(-1, true).filename)
+
+# See also simpler test in Nim/tests/vm/tvmops.nim for a simpler
+# cross platform way.
+block gorge:
+  const
+    execName = when defined(windows): "tgorge.bat" else: "./tgorge.sh"
+    relOutput = gorge(execName)
+    absOutput = gorge(getScriptDir() / execName)
+
+  doAssert relOutput == "gorge test"
+  doAssert absOutput == "gorge test"
+
+block gorgeEx:
+  const
+    execName = when defined(windows): "tgorgeex.bat" else: "./tgorgeex.sh"
+    res = gorgeEx(execName)
+  doAssert res.output == "gorgeex test"
+  doAssert res.exitCode == 1
diff --git a/tests/vm/tgorge.sh b/tests/vm/tgorge.sh
new file mode 100755
index 000000000..ba47afeae
--- /dev/null
+++ b/tests/vm/tgorge.sh
@@ -0,0 +1,2 @@
+#!/bin/sh
+echo "gorge test"
\ No newline at end of file
diff --git a/tests/vm/tgorgeex.bat b/tests/vm/tgorgeex.bat
new file mode 100644
index 000000000..57f11fdd1
--- /dev/null
+++ b/tests/vm/tgorgeex.bat
@@ -0,0 +1,2 @@
+@echo gorgeex test
+@exit /b 1
diff --git a/tests/vm/tgorgeex.sh b/tests/vm/tgorgeex.sh
new file mode 100755
index 000000000..36ba0a02f
--- /dev/null
+++ b/tests/vm/tgorgeex.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+echo "gorgeex test"
+exit 1
diff --git a/tests/vm/tinheritance.nim b/tests/vm/tinheritance.nim
new file mode 100644
index 000000000..2a98ed923
--- /dev/null
+++ b/tests/vm/tinheritance.nim
@@ -0,0 +1,94 @@
+discard """
+  nimout: '''Hello fred, managed by sally
+Hello sally, managed by bob
+0'''
+"""
+# bug #3973
+
+type
+  EmployeeCode = enum
+    ecCode1,
+    ecCode2
+
+  Person* = object of RootObj
+    name*: string
+    last_name*: string
+
+  Employee* = object of Person
+    empl_code*: EmployeeCode
+    mgr_name*: string
+
+proc test() =
+  var
+    empl1 = Employee(name: "fred", last_name: "smith", mgr_name: "sally", empl_code: ecCode1)
+    empl2 = Employee(name: "sally", last_name: "jones", mgr_name: "bob", empl_code: ecCode2)
+
+  echo "Hello ", empl1.name, ", managed by ", empl1.mgr_name
+  echo "Hello ", empl2.name, ", managed by ", empl2.mgr_name
+
+static:
+  test()
+
+#----------------------------------------------
+# Bugs #9701 and #9702
+type
+  MyKind = enum
+    kA, kB, kC
+
+  Base = ref object of RootObj
+    x: string
+
+  A = ref object of Base
+    a: string
+
+  B = ref object of Base
+    b: string
+
+  C = ref object of B
+    c: string
+
+template check_templ(n: Base, k: MyKind) =
+  if k == kA: doAssert(n of A) else: doAssert(not (n of A))
+  if k in {kB, kC}: doAssert(n of B) else: doAssert(not (n of B))
+  if k == kC: doAssert(n of C) else: doAssert(not (n of C))
+  doAssert(n of Base)
+
+proc check_proc(n: Base, k: MyKind) =
+  if k == kA: doAssert(n of A) else: doAssert(not (n of A))
+  if k in {kB, kC}: doAssert(n of B) else: doAssert(not (n of B))
+  if k == kC: doAssert(n of C) else: doAssert(not (n of C))
+  doAssert(n of Base)
+
+static:
+  let aa = new(A)
+  check_templ(aa, kA)
+  check_proc(aa, kA)
+  let bb = new(B)
+  check_templ(bb, kB)
+  check_proc(bb, kB)
+  let cc = new(C)
+  check_templ(cc, kC)
+  check_proc(cc, kC)
+
+let aa = new(A)
+check_templ(aa, kA)
+check_proc(aa, kA)
+let bb = new(B)
+check_templ(bb, kB)
+check_proc(bb, kB)
+let cc = new(C)
+check_templ(cc, kC)
+check_proc(cc, kC)
+
+type
+  BBar = object of RootObj
+    bbarField: set[char]
+    xbarField: string
+    d, e: int
+  FooBar = object of BBar
+    a: int
+    b: string
+
+static:
+  var fb: FooBar
+  echo fb.a
diff --git a/tests/vm/tissues.nim b/tests/vm/tissues.nim
new file mode 100644
index 000000000..f0ae6c296
--- /dev/null
+++ b/tests/vm/tissues.nim
@@ -0,0 +1,76 @@
+import macros
+
+block t9043: # bug #9043
+  proc foo[N: static[int]](dims: array[N, int]): string =
+    const N1 = N
+    const N2 = dims.len
+    const ret = $(N, dims.len, N1, N2)
+    static: doAssert ret == $(N, dims.len, N1, N2)
+    ret
+
+  doAssert foo([1, 2]) == "(2, 2, 2, 2)"
+
+block t4952:
+  proc doCheck(tree: NimNode) =
+    let res: tuple[n: NimNode] = (n: tree)
+    assert: tree.kind == res.n.kind
+    for sub in tree:
+      doCheck(sub)
+
+  macro id(body: untyped): untyped =
+    doCheck(body)
+
+  id(foo((i: int)))
+
+  static:
+    let tree = newTree(nnkExprColonExpr)
+    let t = (n: tree)
+    doAssert: t.n.kind == tree.kind
+
+
+# bug #19909
+type
+  SinglyLinkedList[T] = ref object
+  SinglyLinkedListObj[T] = ref object
+
+
+proc addMoved[T](a, b: var SinglyLinkedList[T]) =
+  if a.addr != b.addr: discard
+
+proc addMoved[T](a, b: var SinglyLinkedListObj[T]) =
+  if a.addr != b.addr: discard
+
+proc main =
+  var a: SinglyLinkedList[int]; new a
+  var b: SinglyLinkedList[int]; new b
+  a.addMoved b
+
+  var a0: SinglyLinkedListObj[int]
+  var b0: SinglyLinkedListObj[int]
+  a0.addMoved b0
+
+static: main()
+
+
+# bug #18641
+
+type A = object
+  ha1: int
+static:
+  var a = A()
+  var a2 = a.addr
+  a2.ha1 = 11
+  doAssert a2.ha1 == 11
+  a.ha1 = 12
+  doAssert a.ha1 == 12
+  doAssert a2.ha1 == 12 # ok
+static:
+  proc fn() =
+    var a = A()
+    var a2 = a.addr
+    a2.ha1 = 11
+    doAssert a2.ha1 == 11
+    a.ha1 = 12
+    doAssert a.ha1 == 12
+    doAssert a2.ha1 == 12 # fails
+  fn()
diff --git a/tests/vm/tldconst.nim b/tests/vm/tldconst.nim
new file mode 100644
index 000000000..7df3143c9
--- /dev/null
+++ b/tests/vm/tldconst.nim
@@ -0,0 +1,14 @@
+# Passes if it compiles
+# From issue #1946
+
+type
+  Part = object
+    index: int ## array index of argument to be accessed
+
+proc foobar(): int =
+    var x: Part
+    if x.index < high(int):
+        discard
+    0
+
+const x = foobar()
diff --git a/tests/vm/tmanyregs.nim b/tests/vm/tmanyregs.nim
new file mode 100644
index 000000000..711c69285
--- /dev/null
+++ b/tests/vm/tmanyregs.nim
@@ -0,0 +1,16 @@
+import macros
+
+# Generate a proc with more then 255 registers. Should not generate an error at
+# compile time
+
+static:
+  macro mkFoo() =
+    let ss = newStmtList()
+    for i in 1..256:
+      ss.add parseStmt "var x" & $i & " = " & $i
+      ss.add parseStmt "inc x" & $i
+    quote do:
+      proc foo() =
+        `ss`
+  mkFoo()
+  foo()
diff --git a/tests/vm/tmaxloopiterations.nim b/tests/vm/tmaxloopiterations.nim
new file mode 100644
index 000000000..c256df518
--- /dev/null
+++ b/tests/vm/tmaxloopiterations.nim
@@ -0,0 +1,15 @@
+discard """
+errormsg: "interpretation requires too many iterations; if you are sure this is not a bug in your code"
+"""
+
+# issue #9829
+
+macro foo(): untyped  =
+  let lines = ["123", "5423"]
+  var idx = 0
+  while idx < lines.len():
+    if lines[idx].len() < 1:
+      inc(idx)
+      continue
+
+foo()
diff --git a/tests/vm/tmisc_vm.nim b/tests/vm/tmisc_vm.nim
new file mode 100644
index 000000000..1ad830b5f
--- /dev/null
+++ b/tests/vm/tmisc_vm.nim
@@ -0,0 +1,459 @@
+discard """
+  targets: "c js"
+  output: '''
+[127, 127, 0, 255][127, 127, 0, 255]
+(data: 1)
+(2, 1)
+(2, 1)
+(2, 1)
+(f0: 5)
+'''
+
+  nimout: '''caught Exception
+main:begin
+main:end
+@[{0}]
+(width: 0, height: 0, path: "")
+@[(width: 0, height: 0, path: ""), (width: 0, height: 0, path: "")]
+Done!
+foo4
+foo4
+foo4
+(a: 0, b: 0)
+(a: 0, b: 0)
+(a: 0, b: 0)
+z1 m: (lo: 12)
+z2 a: (lo: 3)
+x1 a: (lo: 3)
+x2 a: (lo: 6)
+x3 a: (lo: 0)
+z3 a: (lo: 3)
+x1 a: (lo: 3)
+x2 a: (lo: 6)
+x3 a: (lo: 0)
+(2, 1)
+(2, 1)
+(2, 1)
+(f0: 5)
+'''
+"""
+import std/sets
+
+#bug #1009
+type
+  TAggRgba8* = array[4, byte]
+
+template R*(self: TAggRgba8): byte = self[0]
+template G*(self: TAggRgba8): byte = self[1]
+template B*(self: TAggRgba8): byte = self[2]
+template A*(self: TAggRgba8): byte = self[3]
+
+template `R=`*(self: TAggRgba8, val: byte) =
+  self[0] = val
+template `G=`*(self: TAggRgba8, val: byte) =
+  self[1] = val
+template `B=`*(self: TAggRgba8, val: byte) =
+  self[2] = val
+template `A=`*(self: TAggRgba8, val: byte) =
+  self[3] = val
+
+proc ABGR*(val: int | int64): TAggRgba8 =
+  var V = val
+  result.R = byte(V and 0xFF)
+  V = V shr 8
+  result.G = byte(V and 0xFF)
+  V = V shr 8
+  result.B = byte(V and 0xFF)
+  result.A = byte((V shr 8) and 0xFF)
+
+const
+  c1 = ABGR(0xFF007F7F)
+echo ABGR(0xFF007F7F).repr, c1.repr
+
+
+# bug 8740
+
+static:
+  try:
+    raise newException(ValueError, "foo")
+  except Exception:
+    echo "caught Exception"
+  except Defect:
+    echo "caught Defect"
+  except ValueError:
+    echo "caught ValueError"
+
+# bug #10538
+
+block:
+  proc fun1(): seq[int] =
+    try:
+      try:
+        result.add(1)
+        return
+      except:
+        result.add(-1)
+      finally:
+        result.add(2)
+    finally:
+      result.add(3)
+    result.add(4)
+
+  let x1 = fun1()
+  const x2 = fun1()
+  doAssert(x1 == x2)
+
+# bug #11610
+proc simpleTryFinally()=
+  try:
+    echo "main:begin"
+  finally:
+    echo "main:end"
+
+static: simpleTryFinally()
+
+# bug #10981
+
+proc main =
+  for i in 0..<15:
+    var someSets = @[initHashSet[int]()]
+    someSets[^1].incl(0) # <-- segfaults
+    if i == 0:
+      echo someSets
+
+static:
+  main()
+
+# bug #7261
+const file = """
+sprites.png
+size: 1024,1024
+format: RGBA8888
+filter: Linear,Linear
+repeat: none
+char/slide_down
+  rotate: false
+  xy: 730, 810
+  size: 204, 116
+  orig: 204, 116
+  offset: 0, 0
+  index: -1
+"""
+
+type
+  AtlasPage = object
+    width, height: int
+    path: string
+
+  CtsStream = object
+    data: string
+    pos: int
+
+proc atEnd(stream: CtsStream): bool =
+  stream.pos >= stream.data.len
+
+proc readChar(stream: var CtsStream): char =
+  if stream.atEnd:
+    result = '\0'
+  else:
+    result = stream.data[stream.pos]
+    inc stream.pos
+
+proc readLine(s: var CtsStream, line: var string): bool =
+  # This is pretty much copied from the standard library:
+  line.setLen(0)
+  while true:
+    var c = readChar(s)
+    if c == '\c':
+      c = readChar(s)
+      break
+    elif c == '\L': break
+    elif c == '\0':
+      if line.len > 0: break
+      else: return false
+    line.add(c)
+  result = true
+
+proc peekLine(s: var CtsStream, line: var string): bool =
+  let oldPos = s.pos
+  result = s.readLine(line)
+  s.pos = oldPos
+
+proc initCtsStream(data: string): CtsStream =
+  CtsStream(
+    pos: 0,
+    data: data
+  )
+
+# ********************
+# Interesting stuff happens here:
+# ********************
+
+proc parseAtlas(stream: var CtsStream) =
+  var pages = @[AtlasPage(), AtlasPage()]
+  var line = ""
+
+  block:
+    let page = addr pages[^1]
+    discard stream.peekLine(line)
+    discard stream.peekLine(line)
+    echo page[]
+  echo pages
+
+static:
+  var stream = initCtsStream(file)
+  parseAtlas(stream)
+  echo "Done!"
+
+
+# bug #12244
+
+type
+  Apple = object
+    data: int
+
+func what(x: var Apple) =
+  x = Apple(data: 1)
+
+func oh_no(): Apple =
+  what(result)
+
+const
+  vmCrash = oh_no()
+
+debugEcho vmCrash
+
+
+# bug #12310
+
+proc someTransform(s: var array[8, uint64]) =
+  var s1 = 5982491417506315008'u64
+  s[1] += s1
+
+static:
+  var state: array[8, uint64]
+  state[1] = 7105036623409894663'u64
+  someTransform(state)
+
+  doAssert state[1] == 13087528040916209671'u64
+
+import macros
+# bug #12670
+
+macro fooImpl(arg: untyped) =
+  result = quote do:
+    `arg`
+
+proc foo(): string {.compileTime.} =
+  fooImpl:
+    result = "foo"
+    result.addInt 4
+
+static:
+  echo foo()
+  echo foo()
+  echo foo()
+
+# bug #12488
+type
+  MyObject = object
+    a,b: int
+  MyObjectRef = ref MyObject
+
+static:
+  let x1 = new(MyObject)
+  echo x1[]
+  let x2 = new(MyObjectRef)
+  echo x2[]
+  let x3 = new(ref MyObject) # cannot generate VM code for ref MyObject
+  echo x3[]
+
+# bug #19464
+type
+  Wrapper = object
+    inner: int
+
+proc assign(r: var Wrapper, a: Wrapper) =
+  r = a
+
+proc myEcho(a: Wrapper) =
+  var tmp = a
+  assign(tmp, Wrapper(inner: 0)) # this shouldn't modify `a`
+  doAssert a.inner == 1
+
+static:
+  var result: Wrapper
+  assign(result, Wrapper(inner: 1))
+  myEcho(result)
+
+when true:
+  # bug #15974
+  type Foo = object
+    f0: int
+
+  proc fn(a: var Foo) =
+    var s: Foo
+    a = Foo(f0: 2)
+    s = a
+    doAssert s.f0 == 2
+    a = Foo(f0: 3)
+    doAssert s.f0 == 2
+
+  proc test2()=
+    var a = Foo(f0: 1)
+    fn(a)
+
+  static: test2()
+  test2()
+
+# bug #12551
+type
+  StUint = object
+    lo: uint64
+
+func `+=`(x: var Stuint, y: Stuint) =
+  x.lo += y.lo
+
+func `-`(x, y: Stuint): Stuint =
+  result.lo = x.lo - y.lo
+
+func `+`(x, y: Stuint): Stuint =
+  result.lo = x.lo + y.lo
+
+func `-=`(x: var Stuint, y: Stuint) =
+  x = x - y
+
+func `<`(x, y: Stuint): bool=
+  x.lo < y.lo
+
+func `==`(x, y: Stuint): bool =
+  x.lo == y.lo
+
+func `<=`(x, y: Stuint): bool =
+  x.lo <= y.lo
+
+proc div3n2n(r: var Stuint, b: Stuint) =
+  var d: Stuint
+  r = d
+  r += b
+
+func div2n1n(r: var Stuint, b: Stuint) =
+  div3n2n(r, b)
+
+func divmodBZ(x, y: Stuint, r: var Stuint)=
+  div2n1n(r, y)
+  r.lo = 3
+
+func `mod`(x, y: Stuint): Stuint =
+  divmodBZ(x, y, result)
+
+func doublemod_internal(a, m: Stuint): Stuint =
+  result = a
+  if a >= m - a:
+    result -= m
+  result += a
+
+func mulmod_internal(a, b, m: Stuint): Stuint =
+  var (a, b) = (a, b)
+  swap(a, b)
+  debugEcho "x1 a: ", a
+  a = doublemod_internal(a, m)
+  debugEcho "x2 a: ", a
+  a = doublemod_internal(a, m)
+  debugEcho "x3 a: ", a
+
+func powmod_internal(a, m: Stuint): Stuint =
+  var a = a
+  debugEcho "z1 m: ", m
+  debugEcho "z2 a: ", a
+  result = mulmod_internal(result, a, m)
+  debugEcho "z3 a: ", a
+  a = mulmod_internal(a, a, m)
+
+func powmod*(a, m: Stuint) =
+  discard powmod_internal(a mod m, m)
+
+static:
+  var x = Stuint(lo: high(uint64))
+  var y = Stuint(lo: 12)
+
+  powmod(x, y)
+
+# bug #16780
+when true:
+  template swap*[T](a, b: var T) =
+    var a2 = addr(a)
+    var b2 = addr(b)
+    var aOld = a2[]
+    a2[] = b2[]
+    b2[] = aOld
+
+  proc rather =
+    block:
+      var a = 1
+      var b = 2
+      swap(a, b)
+      echo (a,b)
+
+    block:
+      type Foo = ref object
+        x: int
+      var a = Foo(x:1)
+      var b = Foo(x:2)
+      swap(a, b)
+      echo (a.x, b.x)
+
+    block:
+      type Foo = object
+        x: int
+      var a = Foo(x:1)
+      var b = Foo(x:2)
+      swap(a, b)
+      echo (a.x,b.x)
+
+  static: rather()
+  rather()
+
+# bug #16020
+when true:
+  block:
+    type Foo = object
+      f0: int
+    proc main=
+      var f = Foo(f0: 3)
+      var f2 = f.addr
+      f2[].f0 += 1
+      f2.f0 += 1
+      echo f
+    static: main()
+    main()
+
+import tables, strutils
+
+# bug #14553
+const PpcPatterns = @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")]
+
+static:
+    var
+        needSecondIdentifier = initTable[uint32, seq[(string, string)]]()
+
+    for (name, pattern) in PpcPatterns:
+        let
+            firstPart = 0'u32
+            lastPart = "test"
+
+        needSecondIdentifier.mgetOrPut(firstPart, @[]).add((name, pattern))
+
+    doAssert needSecondIdentifier[0] == @[("aaaa", "bbbb"), ("aaaaa", "bbbbb"), ("aaaaaa", "bbbbbb"), ("aaaaaaa", "bbbbbbb"), ("aaaaaaaa", "bbbbb")]
+
+# bug #17864
+macro transform*(fn: typed) =
+  quote do:
+    `fn`
+
+var map: Table[string, HashSet[string]]
+proc publish*(): void {.transform.} =
+  map["k"] = init_hash_set[string]()
+  map["k"].incl "d"
+
+publish()
diff --git a/tests/vm/tmitems_vm.nim b/tests/vm/tmitems_vm.nim
new file mode 100644
index 000000000..787d52cc6
--- /dev/null
+++ b/tests/vm/tmitems_vm.nim
@@ -0,0 +1,45 @@
+discard """
+  nimout: '''13'''
+  output: '''3
+3
+3'''
+"""
+# bug #3731
+var list {.compileTime.} = newSeq[int]()
+
+macro calc*(): void =
+  list.add(1)
+  for c in list.mitems:
+    c = 13
+
+  for c in list:
+    echo c
+
+calc()
+
+# bug #3859
+import macros
+macro m: void =
+  var s = newseq[NimNode](3)
+  # var s: array[3,NimNode]                 # not working either
+  for i in 0..<s.len: s[i] = newLit(3)    # works
+  #for x in s.mitems: x = newLit(3)
+  result = newStmtList()
+  for i in s:
+    result.add newCall(bindsym"echo", i)
+
+m()
+
+# bug 4741 & 5013
+proc test() =
+  var s = [("baz", 42), ("bath", 42)]
+  for i in s.mitems:
+    i[1] = 3
+  doAssert(s == [("baz", 3), ("bath", 3)])
+
+static:
+  test()
+  var s = [("baz", 42), ("bath", 42)]
+  for i in s.mitems:
+    i[1] = 3
+  doAssert(s == [("baz", 3), ("bath", 3)])
diff --git a/tests/vm/tnewseqofcap.nim b/tests/vm/tnewseqofcap.nim
new file mode 100644
index 000000000..a7dc07aa6
--- /dev/null
+++ b/tests/vm/tnewseqofcap.nim
@@ -0,0 +1,14 @@
+const
+  foo = @["aaa", "bbb", "ccc"]
+
+proc myTuple: tuple[n: int, bar: seq[string]] =
+  result.n = 42
+  result.bar = newSeqOfCap[string](foo.len)
+  for f in foo:
+    result.bar.add(f)
+
+# It works if you change the below `const` to `let`
+const
+  (n, bar) = myTuple()
+
+doAssert bar == @["aaa", "bbb", "ccc"]
\ No newline at end of file
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/tnilref.nim b/tests/vm/tnilref.nim
new file mode 100644
index 000000000..5e27cf0cb
--- /dev/null
+++ b/tests/vm/tnilref.nim
@@ -0,0 +1,7 @@
+discard """
+  errormsg: "attempt to access a nil address"
+"""
+
+static:
+    var s: ref int
+    s[] = 1
\ No newline at end of file
diff --git a/tests/vm/tnimnode.nim b/tests/vm/tnimnode.nim
new file mode 100644
index 000000000..f1c4d5e5a
--- /dev/null
+++ b/tests/vm/tnimnode.nim
@@ -0,0 +1,80 @@
+import macros
+
+proc assertEq(arg0,arg1: string): void =
+  if arg0 != arg1:
+    raiseAssert("strings not equal:\n" & arg0 & "\n" & arg1)
+
+# a simple assignment of stmtList to another variable
+var node {.compileTime.}: NimNode
+# an assignment of stmtList into an array
+var nodeArray {.compileTime.}: array[1, NimNode]
+# an assignment of stmtList into a seq
+var nodeSeq {.compileTime.} = newSeq[NimNode](2)
+
+proc checkNode(arg: NimNode; name: string): void {. compileTime .} =
+  echo "checking ", name
+
+  assertEq arg.lispRepr, """(StmtList (DiscardStmt (Empty)))"""
+
+  node = arg
+  nodeArray = [arg]
+  nodeSeq[0] = arg
+  var seqAppend = newSeq[NimNode](0)
+  seqAppend.add([arg]) # at the time of this writing this works
+  seqAppend.add(arg)   # bit this creates a copy
+  arg.add newCall(ident"echo", newLit("Hello World"))
+
+  assertEq arg.lispRepr,          """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq node.lispRepr,         """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq nodeArray[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq nodeSeq[0].lispRepr,   """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq seqAppend[0].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+  assertEq seqAppend[1].lispRepr, """(StmtList (DiscardStmt (Empty)) (Call (Ident "echo") (StrLit "Hello World")))"""
+
+  echo "OK"
+
+# the root node that is used to generate the Ast
+var stmtList {.compileTime.}: NimNode
+
+static:
+  stmtList = newStmtList(nnkDiscardStmt.newTree(newEmptyNode()))
+
+  checkNode(stmtList, "direct construction")
+
+
+macro foo(stmtList: untyped): untyped =
+  checkNode(stmtList, "untyped macro argument")
+
+foo:
+  discard
+
+
+static:
+  stmtList = quote do:
+    discard
+
+  checkNode(newTree(nnkStmtList, stmtList), "create with quote")
+
+
+static:
+  echo "testing body from loop"
+  var loop = quote do:
+    for i in 0 ..< 10:
+      discard
+
+  let innerBody = loop[2]
+  innerBody.add newCall(ident"echo", newLit("Hello World"))
+
+  assertEq loop[2].lispRepr, innerBody.lispRepr
+
+  echo "OK"
+
+
+static:
+  echo "testing creation of comment node"
+  var docComment: NimNode = newNimNode(nnkCommentStmt)
+  docComment.strVal = "This is a doc comment"
+
+  assertEq repr(docComment), "## This is a doc comment"
+
+  echo "OK"
diff --git a/tests/vm/tnocompiletimefunc.nim b/tests/vm/tnocompiletimefunc.nim
new file mode 100644
index 000000000..a95648c0f
--- /dev/null
+++ b/tests/vm/tnocompiletimefunc.nim
@@ -0,0 +1,14 @@
+discard """
+  errormsg: "request to generate code for .compileTime proc: foo"
+"""
+
+# ensure compileTime funcs can't be called from runtime
+
+func foo(a: int): int {.compileTime.} =
+  a * a
+
+proc doAThing(): int =
+  for i in 0..2:
+    result += foo(i)
+
+echo doAThing()
diff --git a/tests/vm/tnocompiletimefunclambda.nim b/tests/vm/tnocompiletimefunclambda.nim
new file mode 100644
index 000000000..d134eea40
--- /dev/null
+++ b/tests/vm/tnocompiletimefunclambda.nim
@@ -0,0 +1,6 @@
+discard """
+  errormsg: "request to generate code for .compileTime proc: :anonymous"
+"""
+
+let a = func(a: varargs[int]) {.compileTime, closure.} =
+  discard a[0]
\ No newline at end of file
diff --git a/tests/vm/tnoreturn.nim b/tests/vm/tnoreturn.nim
new file mode 100644
index 000000000..d4f8601a9
--- /dev/null
+++ b/tests/vm/tnoreturn.nim
@@ -0,0 +1,32 @@
+block: # issue #22216
+  type
+    Result[T, E] = object
+      case oVal: bool
+      of false:
+        eVal: E
+      of true:
+        vVal: T
+
+  func raiseResultDefect(m: string) {.noreturn, noinline.} =
+    raise (ref Defect)(msg: m)
+
+  template withAssertOk(self: Result, body: untyped): untyped =
+    case self.oVal
+    of false:
+      raiseResultDefect("Trying to access value with err Result")    
+    else:
+      body
+
+  func value[T, E](self: Result[T, E]): T {.inline.} =    
+    withAssertOk(self):  
+      self.vVal
+      
+  const
+    x = Result[int, string](oVal: true, vVal: 123)
+    z = x.value()
+    
+  let
+    xx = Result[int, string](oVal: true, vVal: 123)
+    zz = x.value()
+  
+  doAssert z == zz
diff --git a/tests/vm/topenarrays.nim b/tests/vm/topenarrays.nim
new file mode 100644
index 000000000..375d2523d
--- /dev/null
+++ b/tests/vm/topenarrays.nim
@@ -0,0 +1,89 @@
+proc mutate(a: var openarray[int]) =
+  var i = 0
+  for x in a.mitems:
+    x = i
+    inc i
+
+proc mutate(a: var openarray[char]) =
+  var i = 1
+  for ch in a.mitems:
+    ch = 'a'
+
+
+static:
+  var a = [10, 20, 30]
+  assert a.toOpenArray(1, 2).len == 2
+
+  mutate(a)
+  assert a.toOpenArray(0, 2) == [0, 1, 2]
+  assert a.toOpenArray(0, 0) == [0]
+  assert a.toOpenArray(1, 2) == [1, 2]
+  assert "Hello".toOpenArray(1, 4) == "ello"
+  var str = "Hello"
+  str.toOpenArray(2, 4).mutate()
+  assert str.toOpenArray(0, 4).len == 5
+  assert str.toOpenArray(0, 0).len == 1
+  assert str.toOpenArray(0, 0).high == 0
+  assert str == "Heaaa"
+  assert str.toOpenArray(0, 4) == "Heaaa"
+
+  var arr: array[3..4, int] = [1, 2]
+  assert arr.toOpenArray(3, 4) == [1, 2]
+  assert arr.toOpenArray(3, 4).len == 2
+  assert arr.toOpenArray(3, 3).high == 0
+
+  assert arr.toOpenArray(3, 4).toOpenArray(0, 0) == [1]
+
+
+proc doThing(s: static openArray[int]) = discard
+
+doThing([10, 20, 30].toOpenArray(0, 0))
+
+# bug #19969
+proc f(): array[1, byte] =
+  var a: array[1, byte]
+  result[0..0] = a.toOpenArray(0, 0)
+
+doAssert static(f()) == [byte(0)]
+
+
+# bug #15952
+proc main1[T](a: openArray[T]) = discard
+proc main2[T](a: var openArray[T]) = discard
+
+proc main =
+  var a = [1,2,3,4,5]
+  main1(a.toOpenArray(1,3))
+  main2(a.toOpenArray(1,3))
+static: main()
+main()
+
+# bug #16306
+{.experimental: "views".}
+proc test(x: openArray[int]): tuple[id: int] =
+  let y: openArray[int] = toOpenArray(x, 0, 2)
+  result = (y[0],)
+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/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim
new file mode 100644
index 000000000..4ff614e5b
--- /dev/null
+++ b/tests/vm/toverflowopcaddimmint.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.high
+    discard x + 1
+    doAssert false
+  p()
diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim
new file mode 100644
index 000000000..d494245b1
--- /dev/null
+++ b/tests/vm/toverflowopcaddint.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.high
+      y = 1
+    discard x + y
+    doAssert false
+  p()
diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim
new file mode 100644
index 000000000..936eea6c2
--- /dev/null
+++ b/tests/vm/toverflowopcmulint.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = 1'i64 shl 62
+    discard x * 2
+    doAssert false
+  p()
diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim
new file mode 100644
index 000000000..08356590c
--- /dev/null
+++ b/tests/vm/toverflowopcsubimmint.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var x = int64.low
+    discard x - 1
+    doAssert false
+  p()
diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim
new file mode 100644
index 000000000..74e34c6a4
--- /dev/null
+++ b/tests/vm/toverflowopcsubint.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.low
+      y = 1
+    discard x - y
+    doAssert false
+  p()
diff --git a/tests/vm/tquadplus.nim b/tests/vm/tquadplus.nim
new file mode 100644
index 000000000..acf20cd96
--- /dev/null
+++ b/tests/vm/tquadplus.nim
@@ -0,0 +1,14 @@
+# bug #1023
+
+
+type Quadruple = tuple[a, b, c, d: int]
+
+proc `+`(s, t: Quadruple): Quadruple =
+  (a: s.a + t.a, b: s.b + t.b, c: s.c + t.c, d: s.d + t.d)
+
+const
+  A = (a: 0, b: -1, c: 0, d: 1)
+  B = (a: 0, b: -2, c: 1, d: 0)
+  C = A + B
+
+doAssert $C.d & " == " & $(A+B).d == "1 == 1"
diff --git a/tests/vm/tref.nim b/tests/vm/tref.nim
new file mode 100644
index 000000000..e70305225
--- /dev/null
+++ b/tests/vm/tref.nim
@@ -0,0 +1,71 @@
+static:
+  var
+    a: ref string
+    b: ref string
+  new a
+
+  a[] = "Hello world"
+  b = a
+
+  b[5] = 'c'
+  doAssert a[] == "Hellocworld"
+  doAssert b[] == "Hellocworld"
+
+  proc notGlobal() =
+    var
+      a: ref string
+      b: ref string
+    new a
+
+    a[] = "Hello world"
+    b = a
+
+    b[5] = 'c'
+    doAssert a[] == "Hellocworld"
+    doAssert b[] == "Hellocworld"
+  notGlobal()
+
+static: # bug 6081
+  block:
+    type Obj = object
+      field: ref int
+    var i: ref int
+    new(i)
+    var r = Obj(field: i)
+    var rr = r
+    r.field = nil
+    doAssert rr.field != nil
+
+  proc foo() = # Proc to avoid special global logic
+    var s: seq[ref int]
+    var i: ref int
+    new(i)
+    s.add(i)
+    var head = s[0]
+    s[0] = nil
+    doAssert head != nil
+
+  foo()
+
+static:
+
+  block: # global alias
+    var s: ref int
+    new(s)
+    var ss = s
+    s[] = 1
+    doAssert ss[] == 1
+
+static: # bug #8402
+  type R = ref object
+  var empty: R
+  let otherEmpty = empty
+
+block:
+  # fix https://github.com/timotheecour/Nim/issues/88
+  template fun() =
+    var s = @[10,11,12]
+    var a = s[0].addr
+    a[] += 100 # was giving SIGSEGV
+    doAssert a[] == 110
+  static: fun()
diff --git a/tests/vm/treset.nim b/tests/vm/treset.nim
new file mode 100644
index 000000000..32fbc7f04
--- /dev/null
+++ b/tests/vm/treset.nim
@@ -0,0 +1,50 @@
+static:
+  type Obj = object
+    field: int
+  var o = Obj(field: 1)
+  reset(o)
+  doAssert o.field == 0
+
+  var x = 4
+  reset(x)
+  doAssert x == 0
+
+static:
+  type ObjB = object
+    field: int
+  var o = ObjB(field: 1)
+  o = default(ObjB)
+  doAssert o.field == 0
+
+static:
+  var i = 2
+  reset(i)
+  doAssert i == 0
+
+static:
+  var i = new int
+  reset(i)
+  doAssert i.isNil
+
+static:
+  var s = @[1, 2, 3]
+  reset(s)
+  doAssert s == @[]
+
+static:
+  proc f() =
+    var i = 2
+    reset(i)
+    doAssert i == 0
+  f()
+
+proc main =
+  var y = [1, 2, 3, 4]
+  y = default(array[4, int])
+  for a in y: doAssert(a == 0)
+
+  var x = 4
+  x = default(int)
+  doAssert x == 0
+
+main()
diff --git a/tests/vm/triangle_array.nim b/tests/vm/triangle_array.nim
new file mode 100644
index 000000000..0704239c6
--- /dev/null
+++ b/tests/vm/triangle_array.nim
@@ -0,0 +1,13 @@
+# bug #1781
+
+proc initCombinations: array[11, array[11, int]] =
+  result[0]          = [1,2,3,4,5,6,7,8,9,10,11]
+  result[1][1 .. 10] =   [12,13,14,15,16,17,18,19,20,21]
+  result[2][2 .. 10] =     [22,23,24,25,26,27,28,29,30]
+  result[3][3 .. 10] =       [31,32,33,34,35,36,37,38]
+  result[4][4 .. 10] =         [39,40,41,42,43,44,45]
+  result[5][5 .. 10] =           [46,47,48,49,50,51]
+  result[6][6 .. 10] =             [52,53,54,55,56]
+
+const combinations = initCombinations()
+doAssert combinations[6][10] == 56
diff --git a/tests/vm/tscriptcompiletime.nims b/tests/vm/tscriptcompiletime.nims
new file mode 100644
index 000000000..daec54bf7
--- /dev/null
+++ b/tests/vm/tscriptcompiletime.nims
@@ -0,0 +1,9 @@
+discard """
+  cmd: "nim e $file"
+"""
+
+import mscriptcompiletime
+
+macro foo =
+  doAssert bar == 2
+foo()
diff --git a/tests/vm/tseq_badinit.nim b/tests/vm/tseq_badinit.nim
new file mode 100644
index 000000000..5fa223c85
--- /dev/null
+++ b/tests/vm/tseq_badinit.nim
@@ -0,0 +1,58 @@
+
+type
+  AObj = object
+    i: int
+    d: float
+  ATup = tuple
+    i: int
+    d: float
+  MyEnum = enum
+    E01, E02, E03
+  Myrange = range[0..10]
+
+  MyProc = proc (x: int): bool
+  MyInt = distinct int
+  MyAlias = MyInt
+  MySet = set[char]
+  MyArray = array[4, char]
+  MySeq = seq[string]
+
+template test(typename, default: untyped) =
+  proc `abc typename`(): seq[typename] =
+    result = newSeq[typename]()
+    result.add(default)
+    result.setLen(3)
+    for i in 0 ..< 2:
+      result[i] = default
+
+  const constval = `abc typename`()
+  doAssert(constval == `abc typename`())
+
+  proc `arr typename`(): array[4, typename] =
+    for i in 0 ..< 2:
+      result[i] = default
+  const constarr = `arr typename`()
+  doAssert(constarr == `arr typename`())
+
+proc even(x: int): bool = x mod 2 == 0
+proc `==`(x, y: MyInt): bool = ord(x) == ord(y)
+proc `$`(x: MyInt): string = $ord(x)
+proc `$`(x: proc): string =
+  if x.isNil: "(nil)" else: "funcptr"
+
+test(int, 0)
+test(uint, 0)
+test(float, 0.1)
+test(char, '0')
+test(bool, false)
+test(uint8, 2)
+test(string, "data")
+test(MyProc, even)
+test(MyEnum, E02)
+test(AObj, AObj())
+test(ATup, (i:11, d:9.99))
+test(Myrange, 4)
+test(MyInt, MyInt(4))
+test(MyAlias, MyAlias(4))
+test(MyArray, ['0','1','2','3'])
+test(MySeq, @["data"])
diff --git a/tests/vm/tsetlen.nim b/tests/vm/tsetlen.nim
new file mode 100644
index 000000000..9fd30f331
--- /dev/null
+++ b/tests/vm/tsetlen.nim
@@ -0,0 +1,30 @@
+type Foo = object
+  index: int
+
+block:
+  proc fun[T]() =
+    var foo: T
+    var n = 10
+
+    var foos: seq[T]
+    foos.setLen n
+
+    n.inc
+    foos.setLen n
+
+    for i in 0 ..< n:
+      let temp = foos[i]
+      when T is object:
+        doAssert temp.index == 0
+      when T is ref object:
+        doAssert temp == nil
+      doAssert temp == foo
+
+  static:
+    fun[Foo]()
+    fun[int]()
+    fun[float]()
+    fun[string]()
+    fun[(int, string)]()
+    fun[ref Foo]()
+    fun[seq[int]]()
diff --git a/tests/vm/tsignaturehash.nim b/tests/vm/tsignaturehash.nim
new file mode 100644
index 000000000..972ec6fb0
--- /dev/null
+++ b/tests/vm/tsignaturehash.nim
@@ -0,0 +1,20 @@
+# test sym digest is computable at compile time
+
+import macros, algorithm
+import ../../dist/checksums/src/checksums/md5
+
+macro testmacro(s: typed{nkSym}): string =
+  let s = getMD5(signaturehash(s) & " - " & symBodyHash(s))
+  result = newStrLitNode(s)
+
+macro testmacro(s: typed{nkOpenSymChoice|nkClosedSymChoice}): string =
+  var str = ""
+  for sym in s:
+    str &= symBodyHash(sym)
+  result = newStrLitNode(getMD5(str))
+
+# something recursive and/or generic
+discard testmacro(testmacro)
+discard testmacro(`[]`)
+discard testmacro(binarySearch)
+discard testmacro(sort)
diff --git a/tests/vm/tsimpleglobals.nim b/tests/vm/tsimpleglobals.nim
new file mode 100644
index 000000000..7ab665070
--- /dev/null
+++ b/tests/vm/tsimpleglobals.nim
@@ -0,0 +1,16 @@
+discard """
+  nimout: "abc xyz bb"
+"""
+
+# bug #2473
+type
+  Test = tuple[a,b: string]
+
+static:
+  var s:seq[Test] = @[(a:"a", b:"b")]
+  s[0] = (a:"aa", b:"bb")
+
+  var x: Test
+  x.a = "abc"
+  x.b = "xyz"
+  echo x.a, " ", x.b, " ", s[0].b
diff --git a/tests/vm/tslow_tables.nim b/tests/vm/tslow_tables.nim
new file mode 100644
index 000000000..e40187f18
--- /dev/null
+++ b/tests/vm/tslow_tables.nim
@@ -0,0 +1,30 @@
+discard """
+  timeout: "7"
+  action: "compile"
+  nimout: '''create
+search
+done'''
+"""
+
+# bug #12195
+
+import tables
+
+type Flop = object
+  a: array[128, int]  # <-- compile time is proportional to array size
+
+proc hop(): bool =
+  var v: Table[int, Flop]
+
+  echo "create"
+  for i in 1..1000:
+    v.add i, Flop()
+
+  echo "search"
+  for i in 1..1000:
+    discard contains(v, i)
+
+  echo "done"
+
+const r {.used.} = hop()
+
diff --git a/tests/vm/tslurp.nim b/tests/vm/tslurp.nim
new file mode 100644
index 000000000..d762eb079
--- /dev/null
+++ b/tests/vm/tslurp.nim
@@ -0,0 +1,12 @@
+import os
+
+template getScriptDir(): string =
+  parentDir(instantiationInfo(-1, true).filename)
+
+const
+  relRes = slurp"./tslurp.nim"
+  absRes = slurp(getScriptDir() / "tslurp.nim")
+
+doAssert relRes.len > 200
+doAssert absRes.len > 200
+doAssert relRes == absRes
diff --git a/tests/vm/tstaticprintseq.nim b/tests/vm/tstaticprintseq.nim
new file mode 100644
index 000000000..f4aab6b7e
--- /dev/null
+++ b/tests/vm/tstaticprintseq.nim
@@ -0,0 +1,92 @@
+discard """
+  nimout: '''1
+2
+3
+1
+2
+3
+1
+2
+3
+1
+2
+3
+aa
+bb
+11
+22
+aa
+bb
+24
+2147483647 2147483647
+5'''
+"""
+
+const s = @[1,2,3]
+
+macro foo() =
+  for e in s:
+    echo e
+
+foo()
+
+static:
+  for e in s:
+    echo e
+
+macro bar(x: static[seq[int]]): untyped =
+  for e in x:
+    echo e
+
+bar s
+bar(@[1, 2, 3])
+
+type
+  TData = tuple
+    letters: seq[string]
+    numbers: seq[int]
+
+const data: TData = (@["aa", "bb"], @[11, 22])
+
+static:
+  var m1 = data
+  for x in m1.letters: echo x
+
+  var m2: TData = data
+  for x in m2.numbers: echo x
+
+macro ff(d: static[TData]) =
+  for x in d.letters:
+    echo x
+
+ff(data)
+
+# bug #1010
+
+proc `*==`(x: var int, y: int) {.inline, noSideEffect.} =
+  ## Binary `*=` operator for ordinals
+  x = x * y
+
+proc fac: int =
+  var x = 1;
+  for i in 1..4:
+    x *== i;
+  return x
+
+const y = fac()
+
+static:
+  echo y
+
+static:
+  var foo2 = int32.high
+  echo foo2, " ", int32.high
+
+# bug #1329
+
+static:
+    var a: ref int
+    new(a)
+    a[] = 5
+
+    echo a[]
diff --git a/tests/vm/tstring_openarray.nim b/tests/vm/tstring_openarray.nim
new file mode 100644
index 000000000..9318344f8
--- /dev/null
+++ b/tests/vm/tstring_openarray.nim
@@ -0,0 +1,33 @@
+
+# tests various bug when passing string to openArray argument in VM.
+# bug #6086
+proc map*[T, S](data: openArray[T], op: proc (x: T): S {.closure.}):
+                                                            seq[S]{.inline.} =
+# map inlined from sequtils
+  newSeq(result, data.len)
+  for i in 0..data.len-1: result[i] = op(data[i])
+
+
+proc set_all[T](s: var openArray[T]; val: T) =
+  for i in 0..<s.len:
+    s[i] = val
+
+proc main() =
+  var a0 = "hello_world"
+  var a1 = [1,2,3,4,5,6,7,8,9]
+  var a2 = @[1,2,3,4,5,6,7,8,9]
+  a0.set_all('i')
+  a1.set_all(4)
+  a2.set_all(4)
+  doAssert a0 == "iiiiiiiiiii"
+  doAssert a1 == [4,4,4,4,4,4,4,4,4]
+  doAssert a2 == @[4,4,4,4,4,4,4,4,4]
+
+const constval0 = "hello".map(proc(x: char): char = x)
+const constval1 = [1,2,3,4].map(proc(x: int): int = x)
+
+doAssert("hello".map(proc(x: char): char = x) == constval0)
+doAssert([1,2,3,4].map(proc(x: int): int = x) == constval1)
+
+static: main()
+main()
diff --git a/tests/vm/tstringnil.nim b/tests/vm/tstringnil.nim
new file mode 100644
index 000000000..d5dd4f4c9
--- /dev/null
+++ b/tests/vm/tstringnil.nim
@@ -0,0 +1,50 @@
+# bug #1744
+
+import macros
+
+type
+  SuiteTest = object
+    suiteName: string
+    suiteDesc: string
+    testName: string
+    testDesc: string
+    testBlock: NimNode
+
+proc buildSuiteContents(suiteName, suiteDesc, suiteBloc: NimNode): tuple[tests: seq[SuiteTest]]  {.compileTime.} =
+  var
+    tests:seq[SuiteTest] = @[]
+
+  for child in suiteBloc.children():
+    case $child[0].ident:
+    of "test":
+
+      var testObj = SuiteTest()
+      if suiteName.kind == nnkNilLit:
+        testObj.suiteName = ""
+      else:
+        testObj.suiteName = $suiteName
+      if suiteDesc.kind == nnkNilLit:
+        testObj.suiteDesc = ""
+      else:
+        testObj.suiteDesc = suiteDesc.strVal
+      testObj.testName = $child[1] # should not ever be nil
+      if child[2].kind == nnkNilLit:
+        testObj.testDesc = ""
+      else:
+        testObj.testDesc = child[2].strVal
+      testObj.testBlock = child[1]
+
+      tests.add(testObj)
+
+    else:
+      discard
+
+  return (tests: tests)
+
+macro suite(suiteName, suiteDesc, suiteBloc: untyped): typed =
+  let contents = buildSuiteContents(suiteName, suiteDesc, suiteBloc)
+
+# Test above
+suite basics, "Description of such":
+  test(t5, ""):
+    doAssert false
diff --git a/tests/vm/tswap.nim b/tests/vm/tswap.nim
new file mode 100644
index 000000000..bdbe5528c
--- /dev/null
+++ b/tests/vm/tswap.nim
@@ -0,0 +1,34 @@
+discard """
+nimout: '''
+x.data = @[10]
+y = @[11]
+x.data = @[11]
+y = @[10]
+@[3, 2, 1]
+'''
+"""
+
+# bug #2946
+
+proc testSwap(): int {.compiletime.} =
+  type T = object
+    data: seq[int]
+  var x: T
+  x.data = @[10]
+  var y = @[11]
+  echo "x.data = ", x.data
+  echo "y = ", y
+  swap(y, x.data)
+  echo "x.data = ", x.data
+  echo "y = ", y
+  result = 99
+
+const something = testSwap()
+
+# bug #15463
+block:
+  static:
+    var s = @[1, 2, 3]
+    swap(s[0], s[2])
+
+    echo s
diff --git a/tests/vm/ttouintconv.nim b/tests/vm/ttouintconv.nim
new file mode 100644
index 000000000..8c43a3adb
--- /dev/null
+++ b/tests/vm/ttouintconv.nim
@@ -0,0 +1,84 @@
+import macros
+
+discard """
+nimout: '''
+8 9 17
+239 255
+61439 65534 65535
+4026531839 4294967294
+17293822569102704639
+18446744073709551614
+18446744073709551615
+127
+32767
+2147483647
+9223372036854775807
+0
+128
+4294967287'''
+"""
+
+#bug #2514
+
+macro foo() =
+  var x = 8'u8
+  var y = 9'u16
+  var z = 17'u32
+
+  echo x," ", y," ", z
+
+  var a = 0xEF'u8
+  var aa = 0xFF'u8
+  echo a, " ", aa
+
+  var b = 0xEFFF'u16
+  var bb = 0xFFFE'u16
+  var bbb = 0xFFFF'u16
+  echo b, " ", bb, " ", bbb
+
+  var c = 0xEFFFFFFF'u32
+  var cc = 0xFFFFFFFE'u32
+  echo c, " ", cc
+
+  var d = 0xEFFFFFFFFFFFFFFF'u64
+  echo d
+
+  var f = 0xFFFFFFFFFFFFFFFE'u64
+  echo f
+
+  var g = 0xFFFFFFFFFFFFFFFF'u64
+  echo g
+
+  var xx = 0x7F'u8 and 0xFF
+  echo xx
+
+  var yy = 0x7FFF'u16
+  echo yy
+
+  var zz = 0x7FFFFFFF'u32
+  echo zz
+
+macro foo2() =
+  var xx = 0x7FFFFFFFFFFFFFFF
+  echo xx
+
+  var yy = 0
+  echo yy
+
+  var zz = 0x80'u8
+  echo zz
+
+  var ww = -9
+  var vv = cast[uint](ww)
+  var kk = cast[uint32](vv)
+  echo kk
+
+foo()
+foo2()
+
+block:
+  const neg5VM = block:
+    let x = -5'i8
+    uint64(x)
+  let y = -5'i8
+  doAssert uint64(y) == neg5VM
diff --git a/tests/vm/ttypedesc.nim b/tests/vm/ttypedesc.nim
new file mode 100644
index 000000000..d799e5adb
--- /dev/null
+++ b/tests/vm/ttypedesc.nim
@@ -0,0 +1,31 @@
+block: # issue #15760
+  type
+    Banana = object
+    SpecialBanana = object
+    
+  proc getName(_: type Banana): string = "Banana"
+  proc getName(_: type SpecialBanana): string = "SpecialBanana"
+
+  proc x[T](): string = 
+    const n = getName(T) # this one works
+    result = n
+    
+  proc y(T: type): string =
+    const n = getName(T) # this one failed to compile
+    result = n
+
+  doAssert x[SpecialBanana]() == "SpecialBanana"
+  doAssert y(SpecialBanana) == "SpecialBanana"
+
+import macros
+
+block: # issue #23112
+  type Container = object
+    foo: string
+
+  proc canBeImplicit(t: typedesc) {.compileTime.} =
+    let tDesc = getType(t)
+    doAssert tDesc.kind == nnkObjectTy
+
+  static:
+    canBeImplicit(Container)
diff --git a/tests/vm/tunsupportedintfloatcast.nim b/tests/vm/tunsupportedintfloatcast.nim
new file mode 100644
index 000000000..d65f10d86
--- /dev/null
+++ b/tests/vm/tunsupportedintfloatcast.nim
@@ -0,0 +1,3 @@
+static:
+  echo cast[int32](12.0) #[tt.Error
+       ^ VM does not support 'cast' from tyFloat with size 8 to tyInt32 with size 4 due to different sizes]#
diff --git a/tests/vm/tvarsection.nim b/tests/vm/tvarsection.nim
new file mode 100644
index 000000000..cd34bd02e
--- /dev/null
+++ b/tests/vm/tvarsection.nim
@@ -0,0 +1,11 @@
+var
+  a {.compileTime.} = 2
+  b = -1
+  c {.compileTime.} = 3
+  d = "abc"
+
+static:
+  doAssert a == 2
+  doAssert c == 3
+
+doAssert ($b & $d) == "-1abc"
diff --git a/tests/vm/tvmmisc.nim b/tests/vm/tvmmisc.nim
new file mode 100644
index 000000000..6aeac5529
--- /dev/null
+++ b/tests/vm/tvmmisc.nim
@@ -0,0 +1,796 @@
+import macros
+import os
+
+# bug #4462
+block:
+  proc foo(t: typedesc) {.compileTime.} =
+    assert sameType(getType(t), getType(int))
+
+  static:
+    foo(int)
+
+# bug #4412
+block:
+  proc default[T](t: typedesc[T]): T {.inline.} = discard
+
+  static:
+    var x = default(type(0))
+
+# bug #6379
+import algorithm
+
+static:
+  var numArray = [1, 2, 3, 4, -1]
+  numArray.sort(cmp)
+  doAssert numArray == [-1, 1, 2, 3, 4]
+
+  var str = "cba"
+  str.sort(cmp)
+  doAssert str == "abc"
+
+# bug #6086
+import math, sequtils, sugar
+
+block:
+  proc f: int =
+    toSeq(10..<10_000).filter(
+      a => a == ($a).map(
+        d => (d.ord-'0'.ord).int^4
+      ).sum
+    ).sum
+
+  var a = f()
+  const b = f()
+
+  doAssert a == b
+
+block:
+  proc f(): seq[char] =
+    result = "hello".map(proc(x: char): char = x)
+
+  var runTime = f()
+  const compTime = f()
+  doAssert runTime == compTime
+
+# #6083
+block:
+  proc abc(): seq[int] =
+    result = @[0]
+    result.setLen(2)
+    var tmp: int
+
+    for i in 0 ..< 2:
+      inc tmp
+      result[i] = tmp
+
+  const fact1000 = abc()
+  doAssert fact1000 == @[1, 2]
+
+# Tests for VM ops
+block:
+  static:
+    # for joint test, the project path is different, so I disabled it:
+    when false:
+      doAssert "vm" in getProjectPath()
+
+    let b = getEnv("UNSETENVVAR")
+    doAssert b == ""
+    doAssert existsEnv("UNSERENVVAR") == false
+    putEnv("UNSETENVVAR", "VALUE")
+    doAssert getEnv("UNSETENVVAR") == "VALUE"
+    doAssert existsEnv("UNSETENVVAR") == true
+
+    doAssert fileExists("MISSINGFILE") == false
+    doAssert dirExists("MISSINGDIR") == false
+    doAssert fileExists(currentSourcePath())
+    doAssert dirExists(currentSourcePath().parentDir)
+
+# bug #7210
+block:
+  static:
+    proc f(size: int): int =
+      var some = newStringOfCap(size)
+      result = size
+    doAssert f(4) == 4
+
+# bug #6689
+block:
+  static:
+    proc foo(): int = 0
+    var f: proc(): int
+    doAssert f.isNil
+    f = foo
+    doAssert(not f.isNil)
+
+block:
+  static:
+    var x: ref ref int
+    new(x)
+    doAssert(not x.isNil)
+
+# bug #7871
+static:
+  type Obj = object
+    field: int
+  var s = newSeq[Obj](1)
+  var o = Obj()
+  s[0] = o
+  o.field = 2
+  doAssert s[0].field == 0
+
+# bug #8125
+static:
+   let def_iter_var = ident("it")
+
+# bug #8142
+static:
+  type Obj = object
+    names: string
+
+  proc pushName(o: var Obj) =
+    var s = ""
+    s.add("FOOBAR")
+    o.names.add(s)
+
+  var o = Obj()
+  o.names = ""
+  o.pushName()
+  o.pushName()
+  doAssert o.names == "FOOBARFOOBAR"
+
+# bug #8154
+import parseutils
+
+static:
+  type Obj = object
+    i: int
+
+  proc foo(): Obj =
+    discard parseInt("1", result.i, 0)
+
+  static:
+    doAssert foo().i == 1
+
+# bug #10333
+block:
+  const
+    encoding: auto = [
+      ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"],
+      ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"],
+      ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"],
+      ["", "M", "MM", "MMM", "--", "-", "--", "---", "----", "--"],
+    ]
+  doAssert encoding.len == 4
+
+# bug #10886
+
+proc tor(): bool =
+  result = true
+  result = false or result
+
+proc tand(): bool =
+  result = false
+  result = true and result
+
+const
+  ctor = tor()
+  ctand = not tand()
+
+static:
+  doAssert ctor
+  doAssert ctand
+
+block: # bug #13081
+  type Kind = enum
+    k0, k1, k2, k3
+
+  type Foo = object
+    x0: float
+    case kind: Kind
+    of k0: discard
+    of k1: x1: int
+    of k2: x2: string
+    of k3: x3: string
+
+  const j1 = Foo(x0: 1.2, kind: k1, x1: 12)
+  const j2 = Foo(x0: 1.3, kind: k2, x2: "abc")
+  const j3 = Foo(x0: 1.3, kind: k3, x3: "abc2")
+  static:
+    doAssert $j1 == "(x0: 1.2, kind: k1, x1: 12)"
+    doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")"""
+    doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")"""
+  doAssert $j1 == "(x0: 1.2, kind: k1, x1: 12)"
+  doAssert $j2 == """(x0: 1.3, kind: k2, x2: "abc")"""
+  doAssert $j3 == """(x0: 1.3, kind: k3, x3: "abc2")"""
+
+  doAssert j1.x1 == 12
+  static:
+    doAssert j1.x1 == 12
+
+block: # bug #15595
+  proc fn0()=echo 0
+  proc fn1()=discard
+  proc main=
+    var local = 0
+    proc fn2()=echo local
+    var a0 = fn0
+    var a1 = fn1
+    var a2 = fn2
+    var a3: proc()
+    var a4: proc()
+    doAssert a0 == fn0 # bugfix
+    doAssert a1 == fn1 # ditto
+    doAssert a2 == fn2 # ditto
+
+    doAssert fn0 != fn1
+
+    doAssert a2 != nil
+    doAssert a3 == nil # bugfix
+
+    doAssert a3 == a4 # bugfix
+  static: main()
+  main()
+
+block: # issue #20543
+  type F = proc()
+  const myArray = block:
+    var r: array[1, F]
+    r[0] = nil
+    r
+  doAssert isNil(myArray[0])
+
+# bug #15363
+import sequtils
+
+block:
+  func identity(a: bool): bool = a
+
+  var a: seq[bool] = static:
+      newSeq[bool](0).mapIt(it) # segfaults
+  var b: seq[bool] = static:
+      newSeq[bool](0).filterIt(it) # does not segfault
+  var c: seq[bool] = static:
+      newSeq[bool](0).map(identity) # does not segfault
+  var d: seq[bool] = static:
+      newSeq[bool](0).map(proc (a: bool): bool = false) # segfaults
+  var e: seq[bool] = static:
+      newSeq[bool](0).filter(identity) # does not segfault
+  var f: seq[bool] = static:
+      newSeq[bool](0).filter(proc (a: bool): bool = false) # segfaults
+
+  doAssert a == @[]
+  doAssert b == @[]
+  doAssert c == @[]
+  doAssert d == @[]
+  doAssert e == @[]
+  doAssert f == @[]
+
+
+block: # bug #18310
+  macro t() : untyped =
+    let
+      x = nnkTupleConstr.newTree(newLit(1))
+      y = nnkTupleConstr.newTree(newLit(2))
+    doAssert not (x == y) # not using != intentionally
+    doAssert not(cast[int](x) == cast[int](y))
+    doAssert not(system.`==`(x, y))
+    doAssert system.`==`(x, x)
+  t()
+
+block: # bug #10815
+  type
+    Opcode = enum
+      iChar, iSet
+
+    Inst = object
+      case code: Opcode
+        of iChar:
+          c: char
+        of iSet:
+          cs: set[char]
+
+    Patt = seq[Inst]
+
+
+  proc `$`(p: Patt): string =
+    discard
+
+  proc P(): Patt =
+    result.add Inst(code: iSet)
+
+  const a = P()
+  doAssert $a == ""
+
+import tables
+
+block: # bug #8007
+  type
+    CostKind = enum
+      Fixed,
+      Dynamic
+
+    Cost = object
+      case kind*: CostKind
+      of Fixed:
+        cost*: int
+      of Dynamic:
+        handler*: proc(value: int): int {.nimcall.}
+
+  proc foo(value: int): int {.nimcall.} =
+    sizeof(value)
+
+  const a: array[2, Cost] =[
+    Cost(kind: Fixed, cost: 999),
+    Cost(kind: Dynamic, handler: foo)
+  ]
+
+  # OK with arrays & object variants
+  doAssert $a == "[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]"
+
+  const b: Table[int, Cost] = {
+    0: Cost(kind: Fixed, cost: 999),
+    1: Cost(kind: Dynamic, handler: foo)
+  }.toTable
+
+  # KO with Tables & object variants
+  # echo b # {0: (kind: Fixed, cost: 0), 1: (kind: Dynamic, handler: ...)} # <----- wrong behaviour
+  doAssert $b == "{0: (kind: Fixed, cost: 999), 1: (kind: Dynamic, handler: ...)}"
+
+  const c: Table[int, int] = {
+    0: 100,
+    1: 999
+  }.toTable
+
+  # OK with Tables and primitive int
+  doAssert $c == "{0: 100, 1: 999}"
+
+  # For some reason the following gives
+  #    Error: invalid type for const: Cost
+  const d0 = Cost(kind: Fixed, cost: 999)
+
+  # OK with seq & object variants
+  const d = @[Cost(kind: Fixed, cost: 999), Cost(kind: Dynamic, handler: foo)]
+  doAssert $d == "@[(kind: Fixed, cost: 999), (kind: Dynamic, handler: ...)]"
+
+block: # bug #14340
+  block:
+    proc opl3EnvelopeCalcSin0() = discard
+    type EnvelopeSinfunc = proc() {.nimcall.} # todo: fixme 
+    # const EnvelopeCalcSin0 = opl3EnvelopeCalcSin0 # ok
+    const EnvelopeCalcSin0: EnvelopeSinfunc = opl3EnvelopeCalcSin0 # was bug
+    const envelopeSin = [EnvelopeCalcSin0]
+    var a = 0
+    envelopeSin[a]()
+
+  block:
+    type Mutator = proc() {.noSideEffect, gcsafe.}
+    proc mutator0() = discard
+    const mTable = [Mutator(mutator0)]
+    var i=0
+    mTable[i]()
+
+block: # VM wrong register free causes errors in unrelated code
+  block: # bug #15597
+    #[
+    Error: unhandled exception: 'sym' is not accessible using discriminant 'kind' of type 'TNode' [FieldDefect]
+    in /Users/timothee/git_clone/nim/Nim_prs/compiler/vm.nim(1176) rawExecute
+    in opcIndCall
+    in let prc = if not isClosure: bb.sym else: bb[0].sym
+    ]#
+    proc bar2(head: string): string = "asdf"
+    proc zook(u1: int) = discard
+
+    type PathEntry = object
+      kind: int
+      path: string
+
+    iterator globOpt(): int =
+      var u1: int
+
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+      zook(u1)
+
+      var entry = PathEntry()
+      entry.path = bar2("")
+      if false:
+        echo "here2"
+
+    proc processAux(a: float) = discard
+
+    template bar(iter: untyped): untyped =
+      var ret: float
+      for x in iter: break
+      ret
+
+    proc main() =
+      processAux(bar(globOpt()))
+    static: main()
+
+  block: # ditto
+    # D20201024T133245
+    type Deque = object
+    proc initDeque2(initialSize: int = 4): Deque = Deque()
+    proc len2(a: Deque): int = 2
+    proc baz(dir: string): bool = true
+    proc bar2(head: string): string = "asdf"
+    proc bar3(path: var string) = path = path
+
+    type PathEntry = object
+      kind: int
+      path: string
+
+    proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string = dir
+
+    iterator globOpt(dir: string): int =
+      var stack = initDeque2()
+      doAssert baz("")
+      let z = stack.len2
+      if stack.len2 >= 0:
+        var entry = PathEntry()
+        let current = if true: stack.len2 else: stack.len2
+        entry.path = bar2("")
+        bar3(entry.path)
+      if false:
+        echo "here2" # comment here => you get same error as https://github.com/nim-lang/Nim/issues/15704
+
+    proc processAux(a: float) = discard
+
+    template bar(iter: untyped): untyped =
+      var ret: float
+      for x in iter: break
+      ret
+    proc main() =
+      processAux(bar(globOpt(initGlobOpt("."))))
+    static: main()
+
+  block: # bug #15704
+    #[
+    Error: attempt to access a nil address kind: rkFloat
+    ]#
+    type Deque = object
+    proc initDeque2(initialSize: int = 4): Deque = Deque()
+    proc len2(a: Deque): int = 2
+
+    proc baz(dir: string): bool = true
+    proc bar2(head: string): string = "asdf"
+    proc bar3(path: var string) = path = path
+
+    type PathEntry = object
+      kind: int
+      path: string
+      depth: int
+
+    proc initGlobOpt(dir: string, a1=false,a2=false,a3=false,a4=false): string =
+      dir
+
+    iterator globOpt(dir: string): int =
+      var stack = initDeque2()
+      doAssert baz("")
+      let z = stack.len2
+      var a5: int
+      if stack.len2 >= 0:
+        var entry = PathEntry()
+        if false:
+          echo "here"
+        let current = if true: stack.len2 else: stack.len2
+        entry.depth = 1
+        entry.path = bar2("")
+        bar3(entry.path)
+    proc processAux(a: float) = discard
+    template bar(iter: untyped): untyped =
+      var ret: float
+      for x in iter:
+        break
+      ret
+    const dir = "."
+    proc main() =
+      processAux(bar(globOpt(initGlobOpt(dir))))
+    static: main()
+
+block: # bug #8015
+  block:
+    type Foo = object
+      case b: bool
+      of false: v1: int
+      of true: v2: int
+    const t = [Foo(b: false, v1: 1), Foo(b: true, v2: 2)]
+    doAssert $t == "[(b: false, v1: 1), (b: true, v2: 2)]"
+    doAssert $t[0] == "(b: false, v1: 1)" # was failing
+
+  block:
+    type
+      CostKind = enum
+        Fixed,
+        Dynamic
+
+      Cost = object
+        case kind*: CostKind
+        of Fixed:
+          cost*: int
+        of Dynamic:
+          handler*: proc(): int {.nimcall.}
+
+    proc foo1(): int {.nimcall.} =
+      100
+
+    proc foo2(): int {.nimcall.} =
+      200
+
+    # Change to `let` and it doesn't crash
+    const costTable = [
+      0: Cost(kind: Fixed, cost: 999),
+      1: Cost(kind: Dynamic, handler: foo1),
+      2: Cost(kind: Dynamic, handler: foo2)
+    ]
+
+    doAssert $costTable[0] == "(kind: Fixed, cost: 999)"
+    doAssert costTable[1].handler() == 100
+    doAssert costTable[2].handler() == 200
+
+    # Now trying to carry the table as an object field
+    type
+      Wrapper = object
+        table: array[3, Cost]
+
+    proc procNewWrapper(): Wrapper =
+      result.table = costTable
+
+    # Alternatively, change to `const` and it doesn't crash
+    let viaProc = procNewWrapper()
+
+    doAssert viaProc.table[1].handler != nil
+    doAssert viaProc.table[2].handler != nil
+    doAssert $viaProc.table[0] == "(kind: Fixed, cost: 999)"
+    doAssert viaProc.table[1].handler() == 100
+    doAssert viaProc.table[2].handler() == 200
+
+
+# bug #19198
+
+block:
+  type
+    Foo[n: static int] = int
+
+block:
+  static:
+    let x = int 1
+    doAssert $(x.type) == "int"  # Foo
+
+block:
+  static:
+    let x = int 1
+    let y = x + 1
+    # Error: unhandled exception: value out of range: -8 notin 0 .. 65535 [RangeDefect]
+    doAssert y == 2
+
+
+type Atom* = object
+  bar: int
+
+proc main() = # bug #12994
+  var s: seq[Atom]
+  var atom: Atom
+  var checked = 0
+  for i in 0..<2:
+    atom.bar = 5
+    s.add atom
+    atom.reset
+    if i == 0:
+      checked += 1
+      doAssert $s == "@[(bar: 5)]"
+    else:
+      checked += 1
+      doAssert $s == "@[(bar: 5), (bar: 5)]"
+  doAssert checked == 2
+
+static: main()
+main()
+
+# bug #19201
+proc foo(s: sink string) = doAssert s.len == 3
+
+static:
+  foo("abc")
+
+
+static:
+  for i in '1' .. '2': # bug #10938
+    var s: set[char]
+    doAssert s == {}
+    incl(s, i)
+
+  for _ in 0 ..< 3: # bug #13312
+    var s: string
+    s.add("foo")
+    doAssert s == "foo"
+
+  for i in 1 .. 5: # bug #13918
+    var arr: array[3, int]
+    var val: int
+    doAssert arr == [0, 0, 0] and val == 0
+    for j in 0 ..< len(arr):
+      arr[j] = i
+      val = i
+
+# bug #20985
+let a = block:
+  var groups: seq[seq[int]]
+  for i in 0 ..< 3:
+    var group: seq[int]
+    for j in 0 ..< 3:
+      group.add j
+    groups.add group
+  groups
+
+const b = block:
+  var groups: seq[seq[int]]
+  for i in 0 ..< 3:
+    var group: seq[int]
+    for j in 0 ..< 3:
+      group.add j
+    groups.add group
+  groups
+
+doAssert a == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]]
+doAssert b == @[@[0, 1, 2], @[0, 1, 2], @[0, 1, 2]]
+
+macro m1(s: string): int =
+  var ProcID {.global, compileTime.}: int
+  inc(ProcID)
+  result = newLit(ProcID)
+
+proc macroGlobal =
+  doAssert m1("Macro argument") == 1
+  doAssert m1("Macro argument") == 2
+  doAssert m1("Macro argument") == 3
+
+static: macroGlobal()
+macroGlobal()
+
+block: # bug #10108
+  template reject(x) =
+    static: doAssert(not compiles(x))
+
+  static:
+    let x: int = 2
+    proc deliver_x(): int = x
+    var y2 = deliver_x()
+    discard y2
+    reject:
+      const c5 = deliver_x()
+
+block: # bug #7590
+  proc doInit[T]():auto=
+    var a: T
+    return a
+
+  proc fun2[T](tup1:T)=
+    const tup0=doInit[T]()
+
+    # var tup=tup0 #ok
+    const tup=tup0 #causes bug
+
+    doAssert tup is tuple
+    doAssert tup[0] is tuple
+    for ai in tup.fields:
+      doAssert ai is tuple, "BUG2"
+
+  # const c=(foo:(bar1: 0.0))
+  const c=(foo:(bar1:"foo1"))
+  fun2(c)
+
+block: # bug #21708
+  type
+    Tup = tuple[name: string]
+
+  const X: array[2, Tup] = [(name: "foo",), (name: "bar",)]
+
+  static:
+    let s = X[0]
+    doAssert s[0] == "foo"
+
+block:
+  proc swap[T](x: var T): T =
+    result = x
+    x = default(T)
+
+  proc merge[T](a, b: var openArray[T]) =
+    a[0] = swap b[0]
+
+  static:
+    var x = "abc"
+    var y = "356"
+    merge(x, y)
+    doAssert x == "3bc"
+
+block: # bug #22190
+  type
+    EVMFork = enum
+      Berlin
+      Istanbul
+      Shanghai
+
+  const
+    Vm2OpAllForks =
+      {EVMFork.low .. EVMFork.high}
+
+    vm2OpExecBlockData = [(forks: Vm2OpAllForks)]
+
+  proc mkOpTable(selected: EVMFork): bool =
+    selected notin vm2OpExecBlockData[0].forks
+
+  const
+    tab = mkOpTable(Berlin)
+
+  doAssert not tab
+
+block: # issue #22524
+  const cnst = cstring(nil)
+  doAssert cnst.isNil
+  doAssert cnst == nil
+  let b = cnst
+  doAssert b.isNil
+  doAssert b == nil
+
+  let a = static: cstring(nil)
+  doAssert a.isNil
+
+  static:
+    var x: cstring
+    doAssert x.isNil
+    doAssert x == nil
+    doAssert x != ""
+
+block: # issue #15730
+  const s: cstring = ""
+  doAssert s != nil
+
+  static:
+    let s: cstring = ""
+    doAssert not s.isNil
+    doAssert s != nil
+    doAssert s == ""
+
+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/tvmops.nim b/tests/vm/tvmops.nim
new file mode 100644
index 000000000..3d8d5a9ac
--- /dev/null
+++ b/tests/vm/tvmops.nim
@@ -0,0 +1,46 @@
+discard """
+  targets: "c cpp js"
+"""
+
+#[
+test for vmops.nim
+]#
+import os
+import math
+import strutils
+
+static:
+  # TODO: add more tests
+  block: #getAppFilename, gorgeEx, gorge
+    const nim = getCurrentCompilerExe()
+    let ret = gorgeEx(nim & " --version")
+    doAssert ret.exitCode == 0
+    doAssert ret.output.contains "Nim Compiler"
+    let ret2 = gorgeEx(nim & " --nonxistent")
+    doAssert ret2.exitCode != 0
+    let output3 = gorge(nim & " --version")
+    doAssert output3.contains "Nim Compiler"
+
+  block:
+    const key = "D20181210T175037"
+    const val = "foo"
+    putEnv(key, val)
+    doAssert existsEnv(key)
+    doAssert getEnv(key) == val
+
+  block:
+    # sanity check (we probably don't need to test for all ops)
+    const a1 = arcsin 0.3
+    let a2 = arcsin 0.3
+    doAssert a1 == a2
+
+  block bitxor:
+    let x = -1'i32
+    let y = 1'i32
+    doAssert (x xor y) == -2
+
+block:
+  # Check against bugs like #9176
+  doAssert getCurrentCompilerExe() == getCurrentCompilerExe().static
+  if false: #pending #9176
+    doAssert gorgeEx("nonxistent") == gorgeEx("nonxistent").static
diff --git a/tests/vm/tvmopsDanger.nim b/tests/vm/tvmopsDanger.nim
new file mode 100644
index 000000000..966feffe6
--- /dev/null
+++ b/tests/vm/tvmopsDanger.nim
@@ -0,0 +1,13 @@
+discard """
+  cmd: "nim c --experimental:vmopsDanger -r $file"
+"""
+when defined(nimPreviewSlimSystem):
+  import std/assertions
+import std/[times, os]
+
+const foo = getTime()
+let bar = foo
+doAssert bar > low(Time)
+
+static: # bug #23932
+  doAssert getCurrentDir().len > 0
diff --git a/tests/vm/twrong_concat.nim b/tests/vm/twrong_concat.nim
new file mode 100644
index 000000000..59a10bdb9
--- /dev/null
+++ b/tests/vm/twrong_concat.nim
@@ -0,0 +1,22 @@
+# bug #3804
+
+#import sequtils
+
+type AnObj = ref object
+  field: string
+
+#proc aBug(objs: seq[AnObj]) {.compileTime.} =
+#  discard objs.mapIt(it.field & " bug")
+
+proc sameBug(objs: seq[AnObj]) {.compileTime.} =
+  var strSeq = newSeq[string](objs.len)
+  strSeq[0] = objs[0].field & " bug"
+
+static:
+  var objs: seq[AnObj] = @[]
+  objs.add(AnObj(field: "hello"))
+
+  sameBug(objs)
+  # sameBug(objs)
+  echo objs[0].field
+  doAssert(objs[0].field == "hello") # fails, because (objs[0].field == "hello bug") - mutated!
diff --git a/tests/vm/twrongarray.nim b/tests/vm/twrongarray.nim
new file mode 100644
index 000000000..7f24290e2
--- /dev/null
+++ b/tests/vm/twrongarray.nim
@@ -0,0 +1,17 @@
+discard """
+  errormsg: "cannot evaluate at compile time: size"
+  line: 16
+"""
+
+#bug #1343
+
+when false:
+  proc one(dummy: int, size: int) =
+    var x: array[size, int] # compile error: constant expression expected
+
+  proc three(size: int) =
+    var x: array[size * 1, int] # compile error: cannot evaluate at compile time: size
+
+proc two(dummy: int, size: int) =
+  var x: array[size * 1, int] # compiles, but shouldn't?
+  # doAssert(x.len == size) # just for fun
diff --git a/tests/vm/twrongconst.nim b/tests/vm/twrongconst.nim
new file mode 100644
index 000000000..a329cb578
--- /dev/null
+++ b/tests/vm/twrongconst.nim
@@ -0,0 +1,9 @@
+discard """
+  errormsg: "cannot evaluate at compile time: x"
+  line: 7
+"""
+
+var x: array[100, char]
+template foo : char = x[42]
+
+const myConst = foo
diff --git a/tests/vm/twrongwhen.nim b/tests/vm/twrongwhen.nim
new file mode 100644
index 000000000..d67e42883
--- /dev/null
+++ b/tests/vm/twrongwhen.nim
@@ -0,0 +1,13 @@
+discard """
+  errormsg: "cannot evaluate at compile time: x"
+  line: 7
+"""
+
+proc bla(x:int) =
+  when x == 0:
+    echo "oops"
+  else:
+    echo "good"
+
+bla(2)  # echos "oops"
+
diff --git a/tests/vm/tyaytypedesc.nim b/tests/vm/tyaytypedesc.nim
new file mode 100644
index 000000000..8cb402bff
--- /dev/null
+++ b/tests/vm/tyaytypedesc.nim
@@ -0,0 +1,17 @@
+# bug #3357
+
+type NodeType* = enum
+  ntWhitespace
+
+type TokenType* = enum
+  ttWhitespace
+
+proc enumTable*[A, B, C](a: openArray[tuple[key: A, val: B]], ret: typedesc[C]): C =
+  for item in a:
+    result[item.key] = item.val
+
+const tokenTypeToNodeType = {
+  ttWhitespace: ntWhitespace,
+}.enumTable(array[ttWhitespace..ttWhitespace, NodeType])
+
+doAssert tokenTypeToNodeType[ttWhitespace] == ntWhitespace
diff --git a/tests/vm/tzero_extend.nim b/tests/vm/tzero_extend.nim
new file mode 100644
index 000000000..418dbc486
--- /dev/null
+++ b/tests/vm/tzero_extend.nim
@@ -0,0 +1,44 @@
+
+const RANGE = -384.. -127
+
+proc get_values(): (seq[int8], seq[int16], seq[int32]) =
+  let i8 = -3'i8
+  let i16 = -3'i16
+  let i32 = -3'i32
+  doAssert int(cast[uint8](i8)) == 0xFD
+  doAssert int64(cast[uint8](i8)) == 0xFD
+  doAssert int(cast[uint16](i16)) == 0xFFFD
+  doAssert int64(cast[uint16](i16)) == 0xFFFD
+
+  result[0] = @[]; result[1] = @[]; result[2] = @[]
+
+  for offset in RANGE:
+    let i8  = -(1'i64 shl  9) + offset
+    let i16 = -(1'i64 shl 17) + offset
+    let i32 = -(1'i64 shl 33) + offset
+
+    # higher bits are masked. these should be exactly equal to offset.
+    result[0].add cast[int8](cast[uint64](i8))
+    result[1].add cast[int16](cast[uint64](i16))
+    result[2].add cast[int32](cast[uint64](i32))
+
+
+# these values this computed by VM
+const COMPILETIME_VALUES = get_values()
+
+# these values this computed by compiler
+let RUNTIME_VALUES = get_values()
+
+template check_values(int_type: static[int]) =
+  var index = 0
+  let cvalues = COMPILETIME_VALUES[int_type]
+  let rvalues = RUNTIME_VALUES[int_type]
+  for offset in RANGE:
+    let moffset = cast[type(rvalues[0])](offset)
+    doAssert(moffset == rvalues[index] and moffset == cvalues[index],
+      "expected: " & $moffset & " got runtime: " & $rvalues[index] & " && compiletime: " & $cvalues[index] )
+    inc(index)
+
+check_values(0) # uint8
+check_values(1) # uint16
+check_values(2) # uint32
diff --git a/tests/whenstmt/t12517.nim b/tests/whenstmt/t12517.nim
new file mode 100644
index 000000000..8be0171e1
--- /dev/null
+++ b/tests/whenstmt/t12517.nim
@@ -0,0 +1,21 @@
+# Test based on issue #12517
+
+discard """
+  nimout: '''
+nimvm
+both
+'''
+  output: '''
+both
+'''
+"""
+
+proc test() =
+  when nimvm:
+    echo "nimvm"
+  echo "both"
+
+static:
+  test()
+test()
+
diff --git a/tests/whenstmt/t19426.nim b/tests/whenstmt/t19426.nim
new file mode 100644
index 000000000..95fb54a9e
--- /dev/null
+++ b/tests/whenstmt/t19426.nim
@@ -0,0 +1,16 @@
+type
+  MyInt = object
+    bitWidth: int
+
+template toRealType*(t: MyInt): typedesc =
+  when t.bitWidth == 32: int32
+  elif t.bitWidth == 64: int64
+  else: {.error.}
+
+proc doFail(T: typedesc): T = default(T)
+
+proc test =
+  const myInt = MyInt(bitWidth:32)
+  discard doFail(toRealType(myInt))
+
+test()
\ No newline at end of file
diff --git a/tests/whenstmt/twhen.nim b/tests/whenstmt/twhen.nim
new file mode 100644
index 000000000..b155ddcfb
--- /dev/null
+++ b/tests/whenstmt/twhen.nim
@@ -0,0 +1,47 @@
+discard """
+  nimout: '''
+nimvm - when
+nimvm - whenElif
+nimvm - whenElse
+'''
+  output: '''
+when
+whenElif
+whenElse
+'''
+"""
+
+# test both when and when nimvm to ensure proper evaluation
+
+proc compileOrRuntimeProc(s: string) =
+  when nimvm:
+    echo "nimvm - " & s
+  else:
+     echo s
+
+template output(s: string) =
+  static:
+    compileOrRuntimeProc(s)
+  compileOrRuntimeProc(s)
+
+when compiles(1):
+  output("when")
+elif compiles(2):
+  output("fail - whenElif")
+else:
+  output("fail - whenElse")
+
+when compiles(nonexistent):
+  output("fail - when")
+elif compiles(1):
+  output("whenElif")
+else:
+  output("fail - whenElse")
+
+when compiles(nonexistent):
+  output("fail - when")
+elif compiles(nonexistent):
+  output("fail - whenElif")
+else:
+  output("whenElse")
+
diff --git a/tests/whenstmt/twhen_macro.nim b/tests/whenstmt/twhen_macro.nim
new file mode 100644
index 000000000..deb1dddc9
--- /dev/null
+++ b/tests/whenstmt/twhen_macro.nim
@@ -0,0 +1,18 @@
+import macros
+
+# test that when stmt works from within a macro
+
+macro output(s: string, xs: varargs[untyped]): auto =
+  result = quote do:
+    when compiles(`s`):
+      "when - " & `s`
+    elif compiles(`s`):
+      "elif - " & `s`
+      # should never get here so this should not break
+      broken.xs
+    else:
+      "else - " & `s`
+      # should never get here so this should not break
+      more.broken.xs
+
+doAssert output("test") == "when - test"
\ No newline at end of file
diff --git a/tests/wingui.nim b/tests/wingui.nim
deleted file mode 100755
index f4941bcc7..000000000
--- a/tests/wingui.nim
+++ /dev/null
@@ -1,9 +0,0 @@
-# test a Windows GUI application
-
-import
-  windows, shellapi, nb30, mmsystem, shfolder
-
-#proc MessageBox(hWnd: int, lpText, lpCaption: CString, uType: uint): int
-#  {stdcall, import: "MessageBox", header: "<windows.h>"}
-
-discard MessageBox(0, "Hallo World!", "Nimrod GUI application", 0)
diff --git a/tests/x11test.nim b/tests/x11test.nim
deleted file mode 100755
index 2769b6c74..000000000
--- a/tests/x11test.nim
+++ /dev/null
@@ -1,71 +0,0 @@
-import xlib, xutil, x, keysym
-
-const
-  WINDOW_WIDTH = 400
-  WINDOW_HEIGHT = 300
-  
-var
-  width, height: int
-  display: PDisplay
-  screen: cint
-  depth: int
-  win: TWindow
-  sizeHints: TXSizeHints
-
-proc create_window = 
-  width = WINDOW_WIDTH
-  height = WINDOW_HEIGHT
-
-  display = XOpenDisplay(nil)
-  if display == nil:
-    echo("Verbindung zum X-Server fehlgeschlagen")
-    quit(1)
-
-  screen = XDefaultScreen(display)
-  depth = XDefaultDepth(display, screen)
-  var rootwin = XRootWindow(display, screen)
-  win = XCreateSimpleWindow(display, rootwin, 100, 10,
-                            width, height, 5,
-                            XBlackPixel(display, screen),
-                            XWhitePixel(display, screen))
-  size_hints.flags = PSize or PMinSize or PMaxSize
-  size_hints.min_width =  width
-  size_hints.max_width =  width
-  size_hints.min_height = height
-  size_hints.max_height = height
-  discard XSetStandardProperties(display, win, "Simple Window", "window",
-                         0, nil, 0, addr(size_hints))
-  discard XSelectInput(display, win, ButtonPressMask or KeyPressMask or 
-                                     PointerMotionMask)
-  discard XMapWindow(display, win)
-
-proc close_window =
-  discard XDestroyWindow(display, win)
-  discard XCloseDisplay(display)
-    
-var
-  xev: TXEvent
-
-proc process_event =
-  var key: TKeySym
-  case int(xev.theType)
-  of KeyPress:
-    key = XLookupKeysym(cast[ptr TXKeyEvent](addr(xev)), 0)
-    if key != 0:
-      echo("keyboard event")
-  of ButtonPressMask, PointerMotionMask:
-    Echo("Mouse event")
-  else: nil
-
-proc eventloop =
-  discard XFlush(display)
-  var num_events = int(XPending(display))
-  while num_events != 0:
-     dec(num_events)
-     discard XNextEvent(display, addr(xev))
-     process_event()
-
-create_window()
-while true:
-  eventloop()
-close_window()
diff --git a/tests/xml/ttree_add.nim b/tests/xml/ttree_add.nim
new file mode 100644
index 000000000..4c6ef6cf9
--- /dev/null
+++ b/tests/xml/ttree_add.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+var baseDocHead = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+</xml>
+"""
+var baseDocHeadTree = parseXml(baseDocHead)
+var baseDocBody = """
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+"""
+var baseDocBodyTree = parseXml(baseDocBody)
+
+proc test_add() =
+  var testDoc = baseDocHeadTree
+  var newBody = newElement("body")
+  for item in baseDocBodyTree.items():
+    newBody.add(item)
+  
+  echo $newBody
+  
+  testDoc.add(newBody)
+  echo $testDoc
+
+test_add()
diff --git a/tests/xml/ttree_add1.nim b/tests/xml/ttree_add1.nim
new file mode 100644
index 000000000..30ec83c02
--- /dev/null
+++ b/tests/xml/ttree_add1.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+var baseDocHead = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+</xml>
+"""
+var baseDocHeadTree = parseXml(baseDocHead)
+var baseDocBody = """
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+"""
+var baseDocBodyTree = parseXml(baseDocBody)
+
+proc test_add() =
+  var testDoc = baseDocHeadTree
+  var newBody = newElement("body")
+  var bodyItems: seq[XmlNode] = @[]
+  for item in baseDocBodyTree.items():
+    bodyItems.add(item)
+  newBody.add(bodyItems)
+  
+  echo $newBody
+  
+  testDoc.add(newBody)
+  echo $testDoc
+
+test_add()
diff --git a/tests/xml/ttree_delete.nim b/tests/xml/ttree_delete.nim
new file mode 100644
index 000000000..32b477839
--- /dev/null
+++ b/tests/xml/ttree_delete.nim
@@ -0,0 +1,47 @@
+discard """
+  output: '''
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+let initialDocBase = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <tag>
+    <div>MORE TEXT </div>
+    <div>MORE TEXT Some more text</div>
+  </tag>
+  <tag>
+    <div>MORE TEXT </div>
+    <div>MORE TEXT Some more text</div>
+  </tag>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+"""
+var initialDocBaseTree = parseXml(initialDocBase)
+
+proc test_delete() =
+  var testDoc = initialDocBaseTree
+  
+  testDoc.delete(1..2)
+  echo $testDoc
+
+test_delete()
diff --git a/tests/xml/ttree_delete1.nim b/tests/xml/ttree_delete1.nim
new file mode 100644
index 000000000..a8442a093
--- /dev/null
+++ b/tests/xml/ttree_delete1.nim
@@ -0,0 +1,48 @@
+discard """
+  output: '''
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+let initialDocBase = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <tag>
+    <div>MORE TEXT </div>
+    <div>MORE TEXT Some more text</div>
+  </tag>
+  <tag>
+    <div>MORE TEXT </div>
+    <div>MORE TEXT Some more text</div>
+  </tag>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+"""
+var initialDocBaseTree = parseXml(initialDocBase)
+
+proc test_delete() =
+  var testDoc = initialDocBaseTree
+  
+  testDoc.delete(1)
+  testDoc.delete(1)
+  echo $testDoc
+
+test_delete()
diff --git a/tests/xml/ttree_insert.nim b/tests/xml/ttree_insert.nim
new file mode 100644
index 000000000..b2941395b
--- /dev/null
+++ b/tests/xml/ttree_insert.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+var baseDocHead = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+</xml>
+"""
+var baseDocHeadTree = parseXml(baseDocHead)
+var baseDocBody = """
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+"""
+var baseDocBodyTree = parseXml(baseDocBody)
+
+proc test_insert() =
+  var testDoc = baseDocHeadTree
+  var newBody = newElement("body")
+  var bodyItems: seq[XmlNode] = @[]
+  for item in baseDocBodyTree.items():
+    bodyItems.insert(item, len(bodyItems))
+  newBody.insert(bodyItems, 1)
+  
+  echo $newBody
+  
+  testDoc.insert(newBody, 1)
+  echo $testDoc
+
+test_insert()
diff --git a/tests/xml/ttree_insert1.nim b/tests/xml/ttree_insert1.nim
new file mode 100644
index 000000000..9aa3faf69
--- /dev/null
+++ b/tests/xml/ttree_insert1.nim
@@ -0,0 +1,51 @@
+discard """
+  output: '''
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+var baseDocHead = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+</xml>
+"""
+var baseDocHeadTree = parseXml(baseDocHead)
+var baseDocBody = """
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+"""
+var baseDocBodyTree = parseXml(baseDocBody)
+
+proc test_insert() =
+  var testDoc = baseDocHeadTree
+  var newBody = newElement("body")
+  for item in baseDocBodyTree.items():
+    newBody.insert(item, len(newBody))
+  
+  echo $newBody
+  
+  testDoc.insert(newBody, 1)
+  echo $testDoc
+
+test_insert()
diff --git a/tests/xml/ttree_replace.nim b/tests/xml/ttree_replace.nim
new file mode 100644
index 000000000..97d2db638
--- /dev/null
+++ b/tests/xml/ttree_replace.nim
@@ -0,0 +1,46 @@
+discard """
+  output: '''
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+var baseDocBody = """
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+"""
+var baseDocBodyTree = parseXml(baseDocBody)
+let initialDocBase = """
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body before replace </div>
+    <div>Some more text in body before replace </div>
+  </body>
+</xml>
+"""
+var initialDocBaseTree = parseXml(initialDocBase)
+
+proc test_replace() =
+  var testDoc = initialDocBaseTree
+  
+  testDoc.replace(1, @[baseDocBodyTree])
+  echo $testDoc
+
+test_replace()
diff --git a/tests/xml/ttree_replace1.nim b/tests/xml/ttree_replace1.nim
new file mode 100644
index 000000000..059ce2085
--- /dev/null
+++ b/tests/xml/ttree_replace1.nim
@@ -0,0 +1,53 @@
+discard """
+  output: '''
+<xml>
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+  <body>
+    <div>Some text in body</div>
+    <div>Some more text in body </div>
+  </body>
+</xml>
+'''
+"""
+
+# Test xmltree add/insert/delete/replace operations
+import xmlparser
+import xmltree
+var baseDocHead = """
+  <head>
+    <div>Some text</div>
+    <div>Some more text </div>
+  </head>
+"""
+var baseDocHeadTree = parseXml(baseDocHead)
+var baseDocBody = """
+<body>
+  <div>Some text in body</div>
+  <div>Some more text in body </div>
+</body>
+"""
+var baseDocBodyTree = parseXml(baseDocBody)
+let initialDocBase = """
+<xml>
+  <head>
+    <div>Some text before replace </div>
+    <div>Some more text before replace </div>
+  </head>
+  <body>
+    <div>Some text in body before replace </div>
+    <div>Some more text in body before replace </div>
+  </body>
+</xml>
+"""
+var initialDocBaseTree = parseXml(initialDocBase)
+
+proc test_replace() =
+  var testDoc = initialDocBaseTree
+  
+  testDoc.replace(0..1, @[baseDocHeadTree, baseDocBodyTree])
+  echo $testDoc
+
+test_replace()