fixes#25821
This pull request includes a minor bug fix in the lexer and adds new
test cases for string formatting with binary operators in interpolated
expressions.
Lexer bug fix:
* Fixed an off-by-one error in the unary minus detection logic in the
`rawGetTok` procedure in `lexer.nim`, ensuring that the start-of-buffer
condition is correctly checked.
Testing improvements:
* Added tests to `tstrformat.nim` to verify that binary operators (such
as subtraction) work correctly inside interpolated string expressions
using both `&` and `fmt`.
(cherry picked from commit f9647276d8)
Preserves implicit imports instead of always storing the resolved
absolute filename. That lets the later StdPrefix warning check see the
original std/objectdollar spelling.
This is for situations where in cfg or cli warnings are enabled for the
prefix. Essentially a niche combination of compiler switches don't get
along e.g.
`-d:nimPreviewSlimSystem --warning:StdPrefix:on
--warningAsError:StdPrefix:on --import:std/objectdollar`
will cause:
`Error: objectdollar needs the 'std' prefix [StdPrefix]`
(cherry picked from commit 4c8052a45b)
ref https://github.com/nim-lang/Nim/pull/25783
This pull request addresses an issue with addressability of tuple
elements of type `lent` or `var` in Nim, ensuring that expressions
involving these types are handled correctly during type changes. The
main changes introduce a check to prevent attempting to change the type
of tuple elements that are views (`var` or `lent`), and a new test is
added to verify the correct error is raised when trying to take the
address of such elements.
Type system and semantic analysis improvements:
* Added the `isViewTarget` template in `semexprs.nim` to check if a type
is a view (`var` or `lent`), and updated `changeType` to skip type
changes for tuple elements that are views. This prevents invalid
addressability operations on these types.
[[1]](diffhunk://#diff-539da3a63df08fa987f1b0c67d26cdc690753843d110b6bf0805a685eeaffd40R655-R657)
[[2]](diffhunk://#diff-539da3a63df08fa987f1b0c67d26cdc690753843d110b6bf0805a685eeaffd40R686-R693)
Testing:
* Added a new test `tlent_tuple_address.nim` to verify that attempting
to take the address of tuple elements of type `lent` correctly produces
an "expression has no address" error.
(cherry picked from commit f2e4ae0016)
fix#25789
This pull request addresses an issue with the `distinctBase` trait in
the Nim compiler, ensuring it correctly handles types with generic
parameters and static parameters. Additionally, it adds a new test to
cover this scenario. The most important changes are:
### Compiler logic improvements
* Updated the `evalTypeTrait` implementation for the `distinctBase`
trait in `compiler/semmagic.nim` to properly skip all relevant type
wrappers, including those with generic and static parameters, when
unwrapping distinct types. This fixes incorrect handling of types like
`distinct L[int, 100]`.
### Test coverage
* Added a new test block for bug #25789 in
`tests/metatype/ttypetraits.nim` that defines a distinct type over a
generic type with a static parameter, verifies conversions, and checks
that the `distinctBase` trait returns the correct type.
(cherry picked from commit b73908a361)
When an `except T as e:` handler in the cpp backend raises a new
exception, the enclosing `finally` block is silently dropped under
`--mm:arc` and `--mm:orc`:
```nim
proc main() =
try:
try:
raise newException(CatchableError, "orig")
except CatchableError as e:
echo "inner: ", e.msg
raise newException(CatchableError, "re:" & e.msg)
finally:
echo "finally"
except CatchableError as outer:
echo "outer: ", outer.msg
main()
```
Expected output:
```
inner: orig
finally
outer: re:orig
```
Actual output on `nim cpp --mm:arc` (and `--mm:orc`):
```
inner: orig
outer: re:orig
```
The `finally` line is missing. The bug is specific to memory managers
that use destructor injection (arc/orc); under `--mm:refc` the original
code path works correctly because no destructor wrapper is injected.
When the body of `except T as e:` is processed under ARC/ORC, the
destructor injection pass injects a compiler-generated `nkHiddenTryStmt`
wrapper around the handler body to call `=destroy` on `e` when it goes
out of scope. That wrapper sits at the top of `p.nestedTryStmts` with
`inExcept = false`.
`finallyActions` (which inlines the user-finally body before a raise
propagates) only inspected the topmost entry of `nestedTryStmts`.
Because the wrapper has `inExcept = false`, the check short-circuited
and the user's finally was never inlined.
After the raise, C++'s rule that sibling catch clauses do not catch each
other's throws means the surrounding `catch(...)/finally` emitted by
`genTryCpp` never runs either, so the user's finally is silently
dropped.
- Add an `isHidden` flag to `nestedTryStmts` entries, set to `t.kind ==
nkHiddenTryStmt` so compiler-injected try wrappers can be distinguished
from user-written ones.
- In `finallyActions`, walk past `isHidden` wrappers but stop at the
first user try. If that user try is in its except branch with a finally,
inline the finally body before the raise; otherwise leave the raise
untouched (the raise will be caught by that user try's own except
branches and the inner finally will run via normal unwinding, which is
what already happens correctly under refc).
Walking past wrappers fixes the `as e` case under arc/orc. Stopping at
user trys preserves the existing correct behaviour for nested
try/except/finally constructs (e.g. `tests/exception/tfinally.nim`'s
`nested_finally`), which would otherwise see the outer finally inlined
too eagerly when an inner raise is processed.
Adds `tests/exception/tcpp_handler_raise_finally.nim` covering:
- `except T as e:` re-raise + outer finally
- typeless `except:` re-raise + outer finally
- try/finally without except (exception propagation through finally)
The test runs on `--mm:arc`, `--mm:orc`, and `--mm:refc`.
Locally verified on both `devel` and `version-2-2`:
- `tests/exception/` — 42 PASS, 0 FAIL, 3 SKIP
- `tests/destructor/` — all PASS
- `tests/cpp/` — all PASS (single unrelated failure: `tasync_cpp.nim`
needs the `jester` package)
- `megatest` — PASS for both `--mm:arc` and `--mm:refc`, including the
previously regressing `tfinally.nim`'s `nested_finally`
Tagged `[backport]` in the commit message for inclusion in
`version-2-2`.
---------
Co-authored-by: puffball1567 <17452514+puffball1567@users.noreply.github.com>
(cherry picked from commit cbe02aa9de)
fixes#25751
This pull request improves the JavaScript backend code generation and
expands test coverage, particularly around temporary and loop variables,
as well as object destruction behavior. The main changes include
updating the code generator to handle more symbol kinds and adding tests
to ensure proper destruction and option handling.
**JavaScript code generation improvements:**
* Updated `genSymAddr` in `compiler/jsgen.nim` to support additional
symbol kinds, specifically `skTemp` and `skForVar`, ensuring correct
address generation for temporaries and loop variables.
**Test suite enhancements:**
* Added tests in `tests/js/test2.nim` to verify correct behavior of
option types, object destruction (`=destroy`), and to check for
backend-specific crashes. This includes printing results of
option-returning functions and confirming destruction messages.
* Updated expected output in `tests/js/test2.nim` to include results
from new tests and destruction messages, ensuring the test suite
reflects the latest code behavior.
(cherry picked from commit 98131a9fa1)
fixes#25469
This pull request introduces an important fix to argument handling in
the compiler's transformation logic and adds a new test to verify
correct behavior with distinct types and ARC memory management.
### Compiler transformation improvements
* Updated `putArgInto` in `compiler/transf.nim` to handle
`nkHiddenStdConv`, `nkHiddenSubConv`, and `nkConv` nodes more
accurately. Now, if the types match (ignoring distinctness and shallow
range differences), the argument is recursively processed; otherwise, it
falls back to a fast assignment. This prevents incorrect assignments
when dealing with type conversions and distinct types.
### Testing for distinct types and ARC
* Added a new test `tdistinct_for_nodup.nim` to ensure correct iteration
and memory management for distinct sequences of large arrays under ARC.
The test checks that the sequence length remains unchanged during
iteration, helping catch regressions related to ARC and distinct types.
(cherry picked from commit 2b2872928b)
Inline C++ comment emitted by `compiler/ccgstmts.nim:1168` into
generated code read `C++ exception occured, not under Nim's control`.
Doc-only change in the emitted source.
Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
Co-authored-by: SAY-5 <SAY-5@users.noreply.github.com>
(cherry picked from commit 3eb4a60b6b)
fixes#25724
This pull request introduces a small but important fix in the compiler
and adds a new test case related to iterators. The main change in the
compiler ensures that lambda-like constructs are handled consistently
with other procedure definitions, while the new test in the suite covers
a previously untested scenario.
**Compiler improvements:**
* Updated `introduceNewLocalVars` in `compiler/transf.nim` to handle all
`nkLambdaKinds` in addition to `nkProcDef`, `nkFuncDef`, `nkMethodDef`,
and `nkConverterDef`, ensuring consistent transformation of all
lambda-like constructs.
**Testing:**
* Added a block to `tests/iter/titer_issues.nim` to test iterator
behavior in both compile-time and run-time contexts, addressing bug
#25724.
(cherry picked from commit 6353c4e5b0)
fixes#25697
This pull request improves the handling of borrowed routines in the
compiler transformation phase, making the code more robust and
maintainable. The main change is the introduction of a helper function
to properly resolve borrowed routine symbols, which is then used in
multiple places to ensure correct symbol resolution. Additionally, a new
test case is added to cover a previously reported bug related to
borrowed iterators on distinct types.
**Compiler improvements:**
* Added `resolveBorrowedRoutineSym` helper function to follow borrow
aliases and retrieve the underlying implementation symbol for borrowed
routines. This centralizes and clarifies the logic for resolving
borrowed symbols.
* Updated `transformSymAux` and `transformFor` to use the new helper
function, replacing duplicated logic and improving correctness when
handling borrowed routines.
[[1]](diffhunk://#diff-c7b80f51fb685eb22c5b56ee2f320d6c708706f3ae7293478ecd104a2b5b8096L139-R154)
[[2]](diffhunk://#diff-c7b80f51fb685eb22c5b56ee2f320d6c708706f3ae7293478ecd104a2b5b8096L788-R795)
**Testing:**
* Added a test case for bug #25697 to `tests/distinct/tborrow.nim`,
ensuring that iteration over a distinct type with a borrowed iterator
works as expected.
(cherry picked from commit 9a2b0dd045)
Unfortunately I do not have a test case for this (although I can link
[this package
test](60f1be9037/tests/test_simple_combined.nim)
which broke), but this is a regression caused by #24841 (which was
backported to 2.2.4) that causes the following compiler crash:
```
assertions.nim(34) raiseAssert
Error: unhandled exception: ccgtypes.nim(230, 13) `false` mapType: tyGenericInvocation [AssertionDefect]
```
Codegen is traversing the type of the symbol of an explicit destructor
call, but the symbol is the uninstantiated generic hook. This happens
because #24841 changed the code which gives explicit destructor calls
the proper attached destructor to use `replaceHookMagic`, which now
skips `abstractVar` from the type to get the destructor whereas
previously it was just `{tyAlias, tyVar}`. This skips `tyGenericInst`
and also `tyDistinct`. I cannot explain why the skipped `tyGenericInst`
does not have the right destructor but it's not really unexpected, and
skipping `tyDistinct` is just wrong.
To fix this, just `{tyAlias, tyVar, tySink}` are skipped.
(cherry picked from commit 0dc577a4dc)
```nim
type
K = enum
k1,k2
Variant = object
case kind: K
of k1:
discard
of k2:
discard
proc a(x: var K) = discard
proc b(x: ptr K) = discard
var x = Variant(kind: k1)
{.cast(uncheckedAssign).}:
# must be within uncheckedAssign to work
a(x.kind)
b(addr x.kind)
```
(cherry picked from commit 184d423779)
Fixes#25704
This makes sure that `iter` still has `tyGenericInst` skipped like
before, without skipping it for `iterType` which requires it
(cherry picked from commit f9524861f3)
Nested transformBody/liftLambdas passes used a fresh DetectionPass, so
getEnvTypeForOwner could allocate a duplicate PType for the same owner
while :envP already referenced the inner pass type. When addClosureParam
saw cp.typ != t, it errored.
If both types are env objects for the same routine owner, reuse cp.typ
and sync ownerToType.
Adds regression test tests/iter/t21242_nested_closure_in_iter.nim.
(cherry picked from commit 0028ea563c)
fixes#25687
This pull request introduces an optimization for sequence (`seq`)
assignments and copies in the Nim compiler, enabling bulk memory copying
for sequences whose element types are trivially copyable (i.e., no GC
references or destructors). This can significantly improve performance
for such types by avoiding per-element loops.
Key changes:
* Added the `elemSupportsCopyMem` function in
`compiler/liftdestructors.nim` to detect if a sequence's element type is
trivially copyable (no GC refs, no destructors).
* Updated the `fillSeqOp` procedure to use a new `genBulkCopySeq` code
path for eligible element types, generating a call to
`nimCopySeqPayload` for efficient bulk copying. Fallback to the
element-wise loop remains for non-trivial types.
[[1]](diffhunk://#diff-456118dde9a4e21f1b351fd72504d62fc16e9c30354dbb9a3efcb95a29067863R665-R670)
[[2]](diffhunk://#diff-456118dde9a4e21f1b351fd72504d62fc16e9c30354dbb9a3efcb95a29067863R623-R655)
* Introduced the `nimCopySeqPayload` procedure in
`lib/system/seqs_v2.nim`, which performs the actual bulk memory copy of
sequence data using `copyMem`. This is only used for types that are safe
for such an operation.
These changes collectively improve the efficiency of sequence operations
for simple types, while maintaining correctness for complex types.
refc: 3.52s user 0.02s system 99% cpu 3.538 total
orc (after change): 3.46s user 0.01s system 99% cpu 3.476 total
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
(cherry picked from commit 854c1f15ba)
This fixes type resolution for `iterable[T]`.
I want to proceed with RFC
[#562](https://github.com/nim-lang/RFCs/issues/562) and this is the main
blocker for composability.
Fixes#22098 and, arguably, #19206
```nim
import std/strutils
template collect[T](it: iterable[T]): seq[T] =
block:
var res: seq[T] = @[]
for x in it:
res.add x
res
const text = "a b c d"
let words = text.split.collect()
doAssert words == @[ "a", "b", "c", "d" ]
```
In cases like `strutils.split`, where both proc and iterator overload
exists, the compiler resolves to the `func` overload causing a type
mismatch.
The old mode resolved `text.split` to `seq[string]` before the
surrounding `iterable[T]` requirement was applied, so the argument no
longer matched this template.
It should be noted that, compared to older sequtils templates,
composable chains based on `iterable[T]` require an iterator-producing
expression, e.g. `"foo".items.iterableTmpl()` rather than just
`"foo".iterableTmpl()`. This is actually desirable: it keeps the
iteration boundary explicit and makes iterable-driven templates
intentionally not directly interchangeable with older
untyped/loosely-typed templates like those in `sequtils`, whose internal
iterator setup we have zero control over (e.g. hard-coding adapters like
`items`).
Also, I noticed in `semstmts` that anonymous iterators are always
`closure`, which is not that surprising if you think about it, but still
I added a paragraph to the manual.
Regarding implementation:
From what I gathered, the root cause is that `semOpAux` eagerly
pre-types all arguments with plain flags before overload resolution
begins, so by the time `prepareOperand` processes `split` against the
`iterable[T]`, the wrong overload has already won.
The fix touches a few places:
- `prepareOperand` in `sigmatch.nim`:
When `formal.kind == tyIterable` and the argument was already typed as
something else, it's re-semchecked with the
`efPreferIteratorForIterable` flag. The recheck is limited to direct
calls (`a[0].kind in {nkIdent, nkAccQuoted, nkSym, nkOpenSym}`) to avoid
recursing through `semIndirectOp`/`semOpAux` again.
- `iteratorPreference` field `TCandidate`, checked before
`genericMatches` in `cmpCandidates`, gives the iterator overload a win
without touching the existing iterator heuristic used by `for` loops.
**Limitations:**
The implementation is still flag-driven rather than purely
formal-driven, so the behaviour is a bit too broad `efWantIterable` can
cause iterator results to be wrapped as `tyIterable` in
iterable-admitting contexts, not only when `iterable[T]` match is being
processed.
`iterable[T]` still does not accept closure iterator values such
as`iterator(): T {.closure.}`. It only matches the compiler's internal
`tyIterable`, not arbitrary iterator-typed values.
The existing iterator-preference heuristic is still in place, because
when I tried to remove it, some loosely-related regressions happened. In
particular, ordinary iterator-admitting contexts and iterator chains
still rely on early iterator preference during semchecking, before the
compiler has enough surrounding context to distinguish between
value/iterator producing overloads. Full heuristic removal would require
a broader refactor of dot-chain/intermediate-expression semchecking,
which is just too much for me ATM. This PR narrows only the
tyIterable-specific cases.
**Future work:**
Rework overload resolution to preserve additional information of
matching iterator overloads for calls up to the point where the
iterator-requiring context is established, to avoid re-sem in
`prepareOperand`.
Currently there's no good channel to store that information. Nodes can
get rewritten, TCandidate doesn't live long enough, storing in Context
or some side-table raises the question how to properly key that info.
(cherry picked from commit be29bcd402)
fixes#25682
This pull request introduces a fix to the Nim compiler's assignment code
generation logic to better handle statement list expressions, and adds
regression tests to ensure correct behavior when assigning to object
fields via templates. The changes address a specific bug (#25682)
related to assignments using templates with side effects in static
contexts.
**Compiler code generation improvements:**
* Updated the `genAsgn` procedure in `compiler/vmgen.nim` to properly
handle assignments where the left-hand side is a `nkStmtListExpr`
(statement list expression), ensuring all statements except the last are
executed before the assignment occurs.
**Regression tests for assignment semantics:**
* Added new test blocks in `tests/vm/tvmmisc.nim` to verify that
template-based assignments to object fields work as expected in static
contexts, specifically testing for bug #25682.
(cherry picked from commit 9c07bb94c1)
fixes#25632fixes#25631fixes#25630
This pull request introduces a compatibility check between the
`{.error.}` and `{.exportc.}` pragmas in procedure declarations.
Specifically, it prevents a procedure from being marked with both
pragmas at the same time, as this combination is now considered invalid.
Pragma compatibility enforcement:
* Added a check in `semProcAux` (in `compiler/semstmts.nim`) to emit a
local error if a procedure is declared with both `{.error.}` and
`{.exportc.}` pragmas, preventing their incompatible usage.
(cherry picked from commit fb31e86537)
fixes#25677;
fixes#25678
This pull request introduces both a bug fix to the type checking logic
in the compiler and new test cases for lent types involving procedures
and tables. The most significant change is a refinement in how type
flags are handled for procedure and function types in the compiler,
which improves correctness in type allowance checks. Additionally, the
test suite is expanded to cover more complex scenarios with lent types
and table lookups.
**Compiler improvements:**
* Refined the handling of type flags in `typeAllowedAux` for procedure
and function types by introducing `innerFlags`, which removes certain
flags (`taObjField`, `taTupField`, `taIsOpenArray`) before recursing
into parameter and return types. This ensures more accurate type
checking and prevents inappropriate flag propagation.
**Testing enhancements:**
* Added new test blocks in `tests/lent/tlents.nim` to cover lent
procedure types stored in objects and used as table values, including a
function that retrieves such procedures from a table by key.
* Introduced a test case for an object containing a lent procedure
field, ensuring correct behavior when accessing and using these fields.
(cherry picked from commit 7a82c5920c)
Fixes bug #25670.
The second argument to `max` in `cmpDecimalsIgnoreCase` used `limitB -
iA` instead of `limitB - iB`, which could mis-order numeric segments
when sorting doc index entries.
(cherry picked from commit 5c86c1eda9)
Fixes bug #25671.
The previous condition `not value > 0` was parsed as `(not value) > 0`,
not `not (value > 0)`, so the check did not reliably enforce a positive
`--maxLoopIterationsvm` limit. Align with `--maxcalldepthvm` by using
`value <= 0`.
(cherry picked from commit 7f6b76b34c)
It seems in dispute whether changes to code induced to avoid this new
warning firing are worthwhile.
Until either the analyzer is better or a palatable way to adjust stdlib
code not warn is found, verbosity=1 should not include the warning.
Possibly higher levels, too, but this PR is conservative and only takes
it out at the 2->1 transition.
(cherry picked from commit 4bf44ca47f)
Follows up #25269, refs #25265.
I hit the same bug as #25265 for my own project but #25269 does not fix
it, I think because the type in my case is a `tyGenericInst` which does
not trigger the generation here. First I thought of skipping abstract
type kinds instead of checking for a raw `tyObject`, which fixes my
problem. But in general this could maybe also be encountered for
`tyTuple` and `tySequence` etc. So I figured it might just be safest to
not filter on specific type kinds, ~~which is done now~~ (edit: broke
CI). Maybe this has a slight cost on codegen performance though.
Edit: Allowing all types failed CI for some reason as commented below,
trying skipped type version again.
(cherry picked from commit 1a1586a5fb)
This fixes autogenerated references within the same-module for types,
variables and constants for custom output file names. Previously, the
module name was baked-in, now intra-module links omit the page name in
href.
In short, fixes symbol anchors for `-o:index.html`
Expected test results updated.
(cherry picked from commit 2db13e05ac)
`getTypeImpl` and friends were always putting `nkEmpty` in the default
value field which meant the default values couldn't be introspected.
This copies the default AST so it can be seen in the returned object
(cherry picked from commit edbb32e4c4)
On simple code like:
```nim
type Foo = object
case x: range[0..7]
of 0..2:
a: string
else:
b: string
var foo = Foo()
{.cast(uncheckedAssign).}:
foo.x = 5
```
The compiler tries to generate a destructor for the variant fields by
checking if the discrim is equal to the old one, but the type is not
skipped when looking for an `==` operator in system, so any
discriminator with type `range`/`distinct`/etc crashes with:
```
(10, 9) Error: can't find magic equals operator for type kind tyRange
```
This is fixed by just skipping abstract types.
(cherry picked from commit 7a87e7d199)
fixes#25262
```nim
if constraint != nil and constraint.kind == tyTypeDesc:
n[i].typ = e.typ
else:
n[i].typ = e.typ.skipTypes({tyTypeDesc})
```
at least when `constraint` is a typedesc, it should not skip
`tyTypeDesc`
```nim
if arg.kind != tyTypeDesc:
arg = makeTypeDesc(m.c, arg)
```
Wrappers literals into typedesc, which can cause problems. Though, it
doesn't seem to be necessary
(cherry picked from commit bd709f9b4c)
fixes#25005
In `semTypeIdent`, when resolving a typedesc parameter inside a generic
instantiation, the code took a shortcut: it returned the symbol of the
element type (`bound = result.typ.elementType.sym`). However, for
generic types like `RpcResponse[T] = ref object`, the instantiated
object type (e.g., `RpcResponse:ObjectType[string]`) is a copy with a
new type ID but still points to the same symbol as the uninstantiated
generic body type. That symbol's .typ refers to the original
uninstantiated type, which still contains unresolved generic params `T`
(cherry picked from commit e58acc2e1e)
fixes#25475
```nim
var x: array[0..1, int] = [0, 1]
var y: array[4'u..5'u, int] = [0, 3]
echo x == y
```
sigmatch treats array compatibility by element type + length, not by the
index (range) type. Perhaps backend should do the same check
(cherry picked from commit 97fed258ed)
This fixes two issues with impotc'ed types.
1. Passing an importc'ed inherited object to where superclass is
expected emitted `v.Sup` previously. Now it emits `v`, similar to cpp
codegen.
2. Casting between different nim types that resolve to the same C type
previously was done like `*(T*)&v`, now it is just `v`.
(cherry picked from commit 937e647f4f)