`nim ic` was a command of its own, which made it the C backend only and cut it
off from everything the ordinary compile commands accept. `--ic:on` is a switch
on `nim c` / `nim cpp` / `nim objc` instead, so `-r`, `-d:release`,
`--exceptions:`, and a project-wide opt-in from `nim.cfg` / `config.nims` all
work. `nim ic` still resolves to the same driver; `koch bootic`, `koch ic` and
`testament --ic` now go through the switch.
The switch was already parsed into a `conf.ic` nobody read. It is now read in
`passCmd1` as well, because `nim.nim` has to decide whether this run is an IC
DRIVER before config loading (`ensureIcConfig` produces the precompiled config
the driver itself replays); when the switch comes from a config file instead,
`main.nim` produces it late.
**C++.** `tests/cpp` passes under `--ic:on`, matching its classic result. Four
fixes, three of them the shape of every "C++ needs the whole program" problem the
per-module backend has:
* The driver DECLARES each module's translation unit to nifmake without loading a
module, so it cannot ask `cgen.getCFile` — and it hardcoded `.nim.c`, so the
merge stage went looking for `.c.nif` next to the `.cpp.nif` the children had
written. `options.icCFileExt` mirrors the formula at backend granularity.
* C++ has no designated initializers, so the RTTI record is a bare variable that
`DatInit` fills field by field. A bare `TNimTypeV2 x;` is a tentative
definition — C's linker merges those, C++'s does not — so every TU that
demanded the type defined it ("multiple definition of NTIv2__…"). It now gets
the same extern-declaration + owned-`'d'`-definition split the C flavour has.
* `memberProcsPerType` / `initializersPerType` live only in the sem process, so
the backend emitted a struct WITHOUT its in-class member declarations and the
out-of-class definitions did not match ("no declaration matches
'void Doo::memberProc()'"). They are replayed from a new `(repcppmember …)`
log entry; `replayCppMember` re-derives the type from the routine's signature
exactly as `semCppMember` does, so no type key has to survive the round trip.
* Two follow-ons for members: `loc.snippet` is a CALL PATTERN (`#->salute(@)`),
and only `genMemberProcHeader` derives it — whole-program cgen got it for free
by generating the defining module first, but the per-module backend emits that
body in another process, leaving the caller with the mangled Nim name
(`loo->salute_u0__vireouyks1()`). And that pattern is not a linker name: every
`salute` member in every class mints the same one, so the merge stage handed
them all to one artifact and dropped the rest (undefined vtable at link).
Member definitions are keyed by their NIF name there instead.
`--run` is now dropped when re-invoking for the config artifact: the producer has
no output binary and `nim.nim`'s run step asserted on the empty `outFile`.
testament's `--ic` appends the switch rather than rewriting the compile verb, so
a test that overrides `cmd:` wholesale keeps its verb, and the C++ corpus is
covered too (it never was — the old rewrite only matched `nim c `).
`icFormatVersion` 36 -> 37 for the new log entry. `koch bootic` reaches its
byte-identical fixed point through the new entry point; `koch ic` passes;
`tests/ic`, `tests/destructor` (3 known `--newruntime` failures) and the classic
categories are unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`testament --ic` on `tests/destructor` went from 10 failures to 3; the three
left are all `--newruntime`, whose owned-ref RTTI destructor is still missing
(the object type's `=destroy` never reaches the `cg` that emits the type info).
* **global destructors are never run.** `graph.globalDestructors` is filled
while a module's top level goes through `injectDestructorCalls`, and
whole-program cgen empties the list into the main module's init proc — which
IS the program body, so the calls land at exit. Under `nim ic` every module's
`cg` is a separate process and main's only ever saw its own entries: a
module-level `var` with a `=destroy` in an imported module was simply never
destroyed. Each module now wraps its own list in a nullary exported proc and
announces the name in its `.c.nif` meta head (`CnifVersion` 4 -> 5); main's
`cg` reads the heads it already reads for init/datInit and calls them in
reverse dependency order. New test `tests/ic/tglobal_dtors.nim` pins the
order against the oracle.
* **`spawn` died with "system module needs: nimArgsPassingDone".** A module
loaded from a NIF is named by its mangled suffix, so `loadCompilerProc`'s
`module.name.s == "threadpool"` could never match. The backend loads the whole
program before codegen, so consult every loaded module's index instead; misses
are final and remembered (`getCompilerProc` doubles as a presence probe).
* **`new(x, finalizer)` died with "environment misses: x".** `semmagic`'s
finalizer-to-destructor wrapper copies the original's AST but only rewrites
the parameter, leaving `ast[namePos]` naming the ORIGINAL proc. ast2nif
re-derives a routine's serialized AST from `ast[namePos].sym.ast`, so the
wrapper serialized the original's body — whose parameter belongs to the
original — and lambda lifting saw it as a captured variable of another proc.
The copy now names itself, the invariant every other routine AST keeps.
* **a top-level `let (a, b) = f()` copied instead of moved.** A module's own
symbol is the owner of every top-level symbol and is written as a real `(sd)`,
so the loader minted a SECOND `skModule` PSym for it — and `sym.owner == owner`
is an identity test in `aliasanalysis.isAnalysableFieldAccess`, which made
every module-level location un-analysable. Hard error for a type with a
disabled `=copy`. Bind the NIF name to the one registered module symbol.
Backend only: doing it under `nim m` costs `times.toDateTimeByWeek` its
inferred `raises`.
* **a doubly linked list leaked its whole contents.** A field USE serializes as
a bare `SymUse` with nowhere to put symbol flags, so `trees.isCursor` said
"not a cursor" for every loaded field and `DoublyLinkedNode.prev` became a
COUNTED reference: every node held its predecessor alive and no refcount ever
hit zero. `{.cursor.}` now rides in the NIF name marker (`` `fc `` next to
`` `f ``), which def and use derive from the same `PSym`.
* **`--expandArc` came out shuffled.** `moduleSymbolStubs` iterated a `Table`,
i.e. hash order, so the `lower` stage transformed a module's routines in an
arbitrary order — not even stable between two compilers. Order by index
offset, which is source order.
Also: `testament`'s `generatedFile` did not include the matrix entry in the
nimcache key its caller uses, so every `ccodeCheck` test with a `matrix:`
reported `reCodeNotFound`.
`koch bootic` still reaches its fixed point; `tests/ic` and the classic
`tests/destructor` are unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every invariant `tests/ic` checked was IC-against-IC — clean == incremental, a
no-op edit changes nothing, a body edit moves no interface cookie. An IC that is
*consistently* wrong satisfies all of them, and that is exactly how two silent
miscompilations survived. `koch bootic` has the same blind spot: it proves the
compiler reproduces itself, not that it agrees with the reference backend.
Two mechanisms, at different scales.
**The oracle, in the metamorphic runner.** Every successful step is now also
compiled with `nim c` and run, and the two outputs must agree. Unlike the
hand-written `expect:` strings this needs no foresight from the test author: it
compares everything the program does, not only what someone thought to print,
which is what a silently-skipped destructor evades. `no-oracle` opts out.
The format also grew the expressiveness the recent bug hunt showed was missing —
every one of these described a state the suite could not reach:
* `#!DELETE <file>` removes a module. Deleting a still-imported file moves no
mtime, so nothing re-fires.
* `#!FLAGS <switches>` changes the compiler switches between steps. A config
change is not a file either.
* `fails: <substring>` asserts that BOTH compilers reject the program with that
text. Previously every step had to succeed, so the whole error path — and
recovery from it — was untested.
Six regression tests cover the eight bugs the last round fixed.
`testament r <file>` now dispatches metamorphic tests like `testament cat ic`.
**`testament --ic` runs the whole corpus through the incremental compiler**, so
IC inherits ~10k programs with expected output instead of 30 bespoke tests.
Two things had to change for that to mean anything:
* `nimcacheDir` now keys on the `matrix:` entry too. Two matrix variants of one
file are two different compilations; sharing a cache meant each run
invalidated what the previous left — harmless for a backend that caches only
object files, useless for an incremental one.
* About half the corpus overrides the command wholesale (`cmd: "nim c --gc:arc
$file"`), bypassing both `$target` and `$options`. Those are rewritten to `ic`
and given a private cache.
**Warm cache, hastur-style.** A generated warmup program pulling in `system` and
the most-imported stdlib modules is compiled once per distinct compile
configuration into `nimcache/ic_warmup_<hash>`, and each test's empty cache is
seeded from it with mtimes preserved (nifmake compares output-mtime >
input-mtime, so stamping the copies "now" re-fires the whole graph). Only
program-independent artifacts are copied: the frontend NIFs and cookies plus the
per-module `lower`/`cg` output. The `.c`/`.o` are left behind on purpose — the
merge decision is whole-program, so they are re-rendered for every program
anyway.
`tests/destructor` (97 runs): `nim c` 35s cold / 32s warm; `nim ic` ~3m30 cold /
**9.8s warm**.
Compiler changes this required or uncovered:
* `merge` read the live-module list from a manifest the driver writes instead of
globbing `*.c.nif` off the nimcache. Globbing absorbed artifacts belonging to
any other program sharing the directory — which is what made a prefilled cache
produce undefined symbols at link.
* The build-arg signature no longer includes `--icproject:`/`--icPreparsedConfig:`
(they name where a build lives, not what it produces, so two caches holding
identical artifacts got different signatures). The precompiled config still
counts, by content hash, minus its `(nimcache …)` line.
* `.s.deps` seeding is speculative and runs before the prune, so a sidecar entry
that has gone stale (an import that a `when` no longer takes) can be dropped
instead of lingering forever; a pruned module's scan artifacts are deleted so
an edit-accumulated cache still matches a clean one.
* A failed nifmake run no longer prints an `Error:` of its own. The children have
already reported; adding a build-system status as the LAST error hid the
compiler's real message from anything reading the final error — every
reject-style test under `nim ic` said "nifmake failed with exit code: 1".
* `--mm:hooks` fed the mm mode to an on/off switch and failed outright with
"'on' or 'off' expected, but 'hooks' found". Pre-existing and unrelated to IC;
only reachable through the explicit switch, since `--newruntime` sets
`selectedGC` directly.
Running `tests/destructor` under `--ic` currently leaves 10 failures. They are
genuine IC defects, not harness noise (all 97 pass under `nim c`) — the clearest
is `tglobaldestructor`: `graph.globalDestructors` is accumulated while injecting
destructors into a module's top level, but the main module's `cg` — which emits
the teardown — is a different process, so a module-level `var` with a `=destroy`
is never destroyed. Same shape as the init/datInit metas, and it wants the same
fix: record it in the `.c.nif` head.
Validation: `koch bootic` reaches its byte-identical fixed point; `tests/ic` is
36/36; arc, destructor, macros, template, iter, closure, ccg, codegen, types and
effects pass under `nim c`, with generics showing only its pre-existing failure.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fixes#25908
When an enum identifier is resolved as an `nkSymChoice`, one of the
candidates may come from a loop-local view and carry `tyVar` or
`tyLent`.
Enum disambiguation should compare the underlying enum type only.
Otherwise a pure-enum field can win incorrectly even though the intended
symbol is already present in the choice set.
Keep the `includePureEnum` lookup path for enum-typed expectations so
#23976 still works, but normalize `var`/`lent` only at the symchoice
selection point.
implements https://github.com/nim-lang/RFCs/issues/557
It inserts defect handing into a bare except branch
```nim
try:
raiseAssert "test"
except:
echo "nope"
```
=>
```nim
try:
raiseAssert "test"
except:
# New behaviov, now well-defined: **never** catches the assert, regardless of panic mode
raiseDefect()
echo "nope"
```
In this way, `except` still catches foreign exceptions, but panics on
`Defect`. Probably when Nim has `except {.foreign.}`, we can extend
`raiseDefect` to foreign exceptions as well. That's supposed to be a
small use case anyway.
`--legacy:noPanicOnExcept` is provided for a transition period.
follows up #24279
`discard finishTest` was wrong if the test still had a `retries` option:
it would just ignore the result of the test. This is an unlikely mistake
but we safeguard against it by splitting `finishTest` into two, one that
completely ignores the retries option and `finishTestRetryable` which
has to be checked for a retry. This also makes the code look slightly
better.
Testament now retries a test by a specified amount if it fails in any
way other than an invalid spec. This is to deal with the flaky GC tests
on Windows CI that fail in many different ways, from the linker randomly
erroring, segfaults, etc.
Unfortunately I couldn't do this cleanly in testament's current code.
The proc `addResult`, which is the "final" proc called in a test run's
lifetime, is now wrapped in a proc `finishTest` that returns a bool
`true` if the test failed and has to be retried. This result is
propagated up from `cmpMsgs` and `compilerOutputTests` until it reaches
`testSpecHelper`, which handles these results by recursing if the test
has to be retried. Since calling `testSpecHelper` means "run this test
with one given configuration", this means every single matrix
option/target etc. receive an equal amount of retries each.
The result of `finishTest` is ignored in cases where it's known that it
won't be retried due to passing, being skipped, having an invalid spec
etc. It's also ignored in `testNimblePackages` because it's not
necessary for those specific tests yet and similar retry behavior is
already implemented for part of it.
This was a last resort for the flaky GC tests but they've been a problem
for years at this point, they give us more work to do and turn off
contributors. Ideally GC tests failing should mark as "needs review" in
the CI rather than "failed" but I don't know if Github supports
something like this.
This adds several new Status packages to the CIs:
- confutils
- eth
- metrics
- nat_traversal
- toml_serialization
Other packages mentioned in https://github.com/nim-lang/Nim/issues/24266
are currently not ready to test with `devel` for various reasons.
----
This also enables `criterion`, and removes other packages that had been
in the `allowFailure` category — even without them we have plenty of
packages (145) that we test, there's no point in spending CI time on
them just to see them fail every time.
If/when the authors of those packages make them work with Nim devel, we
can re-introduce them then.
fixes#23587
As explained in the issue, `getOrDefault` has a parameter named
`default` that can be a proc after generic instantiation. But the
parameter having a proc type [overrides all other
overloads](f73e03b132/compiler/semexprs.nim (L1203))
including the magic `system.default` overload and causes a compile error
if the proc doesn't match the normal use of `default`. To fix this, the
`result = default(B)` initializer call is removed because it's not
needed, `result` is always set in `getOrDefaultImpl` when a default
value is provided.
This is still a suspicious behavior of the compiler but `tables` working
has a higher priority.
Followup to #24154, packages aren't ready for macos 14 (M1/ARM CPU) yet
and it seems to be preview on azure, so upgrade to macos 13 for now.
Macos 12 gives a warning:
```
You are using macOS 12.
We (and Apple) do not provide support for this old version.
It is expected behaviour that some formulae will fail to build in this old version.
It is expected behaviour that Homebrew will be buggy and slow.
Do not create any issues about this on Homebrew's GitHub repositories.
Do not create any issues even if you think this message is unrelated.
Any opened issues will be immediately closed without response.
Do not ask for help from Homebrew or its maintainers on social media.
You may ask for help in Homebrew's discussions but are unlikely to receive a response.
Try to figure out the problem yourself and submit a fix as a pull request.
We will review it but may or may not accept it.
```
split again from #24038, fixes
https://github.com/status-im/nimbus-eth2/pull/6554#issuecomment-2354977102
`var`/pointer types are no longer implicitly convertible to each other
if their element types either:
* require an int conversion or another conversion operation as long as
it's not to `openarray`,
* are subtypes with pointer indirection,
Previously any conversion below a subrange match would match if the
element type wasn't a pointer type, then it would error later in
`analyseIfAddressTaken`.
Different from #24038 in that the preview define that made subrange
matches also fail to match is removed for a simpler diff so that it can
be backported.
fixes#24054
`readData` is not implemented for the VM as mentioned in the issue, but
`readDataStr` is, so that is used for `readStr` instead on the VM. We
could also just use it in general since it falls back to `readData`
anyway but it's kept the same otherwise for now.
Also where and why streams in general don't work in VM is now documented
on the top level `streams` module documentation.
fixes#16376
The way the compiler handled generic proc instantiations in calls (like
`foo[int](...)`) up to this point was to instantiate `foo[int]`, create
a symbol for the instantiated proc (or a symchoice for multiple procs
excluding ones with mismatching generic param counts), then perform
overload resolution on this symbol/symchoice. The exception to this was
when the called symbol was already a symchoice node, in which case it
wasn't instantiated and overloading was called directly ([these
lines](b7b1313d21/compiler/semexprs.nim (L3366-L3371))).
This has several problems:
* Templates and macros can't create instantiated symbols, so they
couldn't participate in overloaded explicit generic instantiations,
causing the issue #16376.
* Every single proc that can be instantiated with the given generic
params is fully instantiated including the body. #9997 is about this but
isn't fixed here since the instantiation isn't in a call.
The way overload resolution handles explicit instantiations by itself is
also buggy:
* It doesn't check constraints.
* It allows only partially providing the generic parameters, which makes
sense for implicit generics, but can cause ambiguity in overloading.
Here is how this PR deals with these problems:
* Overload resolution now always handles explicit generic instantiations
in calls, in `initCandidate`, as long as the symbol resolves to a
routine symbol.
* Overload resolution now checks the generic params for constraints and
correct parameter count (ignoring implicit params). If these don't
match, the entire overload is considered as not matching and not
instantiated.
* Special error messages are added for mismatching/missing/extra generic
params. This is almost all of the diff in `semcall`.
* Procs with matching generic parameters now instantiate only the type
of the signature in overload resolution, not the proc itself, which also
works for templates and macros.
Unfortunately we can't entirely remove instantiations because overload
resolution can't handle some cases with uninstantiated types even though
it's resolved in the binding (see the last 2 blocks in
`texplicitgenerics`). There are also some instantiation issues with
default params that #24005 didn't fix but I didn't want this to become
the 3rd huge generics PR in a row so I didn't dive too deep into trying
to fix them. There is still a minor instantiation fix in `semtypinst`
though for subscripts in calls.
Additional changes:
* Overloading of `[]` wasn't documented properly, it somewhat is now
because we need to mention the limitation that it can't be done for
generic procs/types.
* Tests can now enable the new type mismatch errors with just
`-d:testsConciseTypeMismatch` in the command.
Package PRs:
- using fork for now:
[combparser](https://github.com/PMunch/combparser/pull/7) (partial
generic instantiation)
- merged: [cligen](https://github.com/c-blake/cligen/pull/233) (partial
generic instantiation but non-overloaded + template)
- merged: [neo](https://github.com/andreaferretti/neo/pull/56) (trying
to instantiate template with no generic param)