A closure's environment type — and the `=destroy`/`=copy`/`=sink` the compiler lifts for it — is minted by the BACKEND and exists in no module's semmed NIF. Grinding a corpus of closure programs against `nim c` as the oracle turned up three ways the per-module backend gets those wrong. `tests/closure` is now green under `--ic:on`, and `tests/iter` goes from 13 failures to 9. * **The env hook is emitted by nobody.** `emitsBodyInThisModule` walks up to the outermost enclosing routine to pick the TU that emits a body. For the env `=destroy` of a generic closure iterator defined in one module and instantiated in another, that walk lands on the module of the ORIGINAL generic — a module that never sees the instance — so the routine was emitted nowhere (`undefined reference to eqdestroy__c485__…`). A backend-minted routine has no owning module NIF at all: it is written into the `.t.bif` of every module that references it, re-homed there with `@bk`. Every referencing TU emits it now and the merge stage keeps one, like any other content-addressed definition. * **The `:up` link is stored without an increment.** `env.:up = enclosingEnv` has to go through `=copy` (with the cyclic incref) or the parent's refcount is one too low, and at teardown the two envs' mutually recursive `=destroy`s each believe they hold the last reference and recurse until the stack is gone — a SIGSEGV after the program's own output has already been printed (`tests/iter/tnestedclosures`, "Test 3"). Whether it becomes a `=copy` depends on the up-field type's hooks existing at injection time. Whole-program cgen got that for free: a LATER lifting pass creates them and it runs before any routine's injection. The per-module backend injects a routine right after lifting it (`lower`), long before the module's top level is transformed at all (`cg`) — so both up-field assignment sites create the ops themselves. * **Two backend hooks collide on one C name.** A backend-minted symbol is named `_c<itemId.item>`, a PER-PROCESS counter — fine while "nifc lifts, emits and compiles them in one run", which is what `mangleProcNameExt` assumed. But `lower` mints the env hooks of nested routines and `cg` mints those of the module's top level, and both land in the same translation unit: two unrelated `=destroy`s became one C function. `mangleProcNameExt` already makes an exception for hooks whose `disamb` is content-derived (`HookDisambBit`); `toNifSymName` now mirrors it, so the content-derived value survives the round trip instead of being overwritten by the loader. `InstanceDisambBit`/`HookDisambBit` move to `astdef` — `ast2nif` names symbols by them and cannot import `modulegraphs`. Two new metamorphic tests, both of which fail on the previous compiler: `tclosure_hooks` (generic closure iterator instantiated across modules) and `tclosure_nested_iter` (closure iterator nested in a closure iterator). `icFormatVersion` 37 -> 38 for the hook naming. `koch bootic` reaches its byte-identical fixed point; `tests/closure`, `tests/destructor` (3 known `--newruntime` failures), `tests/cpp` and the classic categories are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This directory contains the test cases.
Each test must have a filename of the form: t*.nim
Note: Testament 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 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.