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#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 #25674.
`replace` read `s[i+1]` for a CRLF pair without ensuring `i+1 <
s.len()`, so a value ending in a lone `\\c` (quoted in `writeConfig`)
raised `IndexDefect`.
- Fix: only treat `\\c\\l` when the following character exists.
- Test: `tests/stdlib/tparsecfg.nim` block bug #25674 — fails before
fix, passes after.
(cherry picked from commit 78282b241f)
Even on nimscript, the `else` branch of the `when nimvm` below compiles
and gives an "undeclared identifier: copyMem" error. Regression since
#25064.
(cherry picked from commit 6f85d348f4)
`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)
1. A trailing `$` at the end of a replacement string could read out of
bounds via `how[i + 1]`; this now raises `ValueError` instead.
2. Numeric capture parsing used `id += (id * 10) + digit` instead of `id
= (id * 10) + digit`, so multi-digit refs were parsed incorrectly (e.g.
`$12` resolved as capture 13 instead of 12).
4. Unterminated named replacement syntax (e.g. `${foo)` is now rejected
with ValueError instead of being accepted and parsed inconsistently.
Found and fixed by GPT 5.3 Codex.
(cherry picked from commit 9b2b286baf)
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)
Adds configurable parser modes to std/parseopt module. **Take two.**
Initially solved the issue of not being able to pass arguments to short
options as you do with most everyday CLI programs, but reading the tests
made me add more features so that some of the behaviour could be changed
and here we are.
**`std/parseopt` now supports three parser modes** via an optional
`mode` parameter in `initOptParser` and `getopt`.
Three modes are provided:
- `NimMode` (default, fully backward compatible),
- `LaxMode` (POSIX-inspired with relaxed short option handling),
- `GnuMode` (stricter GNU-style conventions).
The new modes are marked as experimental in the documentation.
The parser behaviour is controlled by a new `ParserRules` enum, which
provides granular feature flags that modes are built from. This makes it
possible for users with specific requirements to define custom rule sets
by importing private symbols, this is mentioned but clearly marked as
unsupported.
**Backward compatibility:**
The default mode preserves existing behaviour completely, with a single
exception: `allowWhitespaceAfterColon` is deprecated.
Now, `allowWhitespaceAfterColon` doesn't make much sense as a single
tuning knob. The `ParserRule.prSepAllowDelimAfter` controls this now.
As `allowWhitespaceAfterColon` had a default, most calls never mention
it so they will silently migrate to the new `initOptParser` overload. To
cover cases when the proc param was used at call-site, I added an
overload, which modifies the default parser mode to reflect the required
`allowWhitespaceAfterColon` value. Should be all smooth for most users,
except the deprecation warning.
The only thing I think can be classified as the breaking change is a
surprising **bug** of the old parser:
```nim
let p = initOptParser("-n 10 -m20 -k= 30 -40", shortNoVal = {'v'})
# ^-disappears
```
This is with the aforementioned `allowWhitespaceAfterColon` being true
by default, of course. In this case the `30` token is skipped
completely. I don't think that's right, so it's fixed.
Things I still don't like about how the old parser and the new default
mode behave:
1. **Parser behaviour is controlled by an emptiness of two containers**.
This is an interesting approach. It's also made more interesting because
the `shortNoVal`/`longNoVal` control both the namesakes, but *and also
how their opposites (value-taking opts) work*.
---
**Edit:**
2. `shortNoVal` is not mandatory:
```nim
let p = initOptParser(@["-a=foo"], shortNoVal = {'a'})
# Nim, Lax parses as: (cmdShortOption, "a", "foo")
# GnuMode parses as: (cmdShortOption, "a", "=foo")
```
In this case, even though the user specified `a` as no no-val, parser
ignores it, relying only on the syntax to decide the kind of the
argument. This is especially problematic with the modes that don't use
the rule `prShortAllowSep` (GnuMode), in this case the provided input is
twice invalid, regardless of the `shortNoVal`.
With the current parser architecture, parsing it this way **is
inevitable**, though. We don't have any way to signal the error state
detected with the input, so the user is expected to validate the input
for mistakes.
Bundling positional arguments is nonsensical and short option can't use
the separator character, so `[cmd "a", arg "=foo"]` and `[cmd "a", cmd
"=", cmd "f"...]` are both out of the question **and** would complicate
validating, requiring keeping track of a previous argument. Hope I'm
clear enough on the issue.
**Future work:**
1. Looks like the new modes are already usable, but from the discussions
elsewhere it looks like we might want to support special-casing
multi-digit short options (`-XX..`) to allow numerical options greater
than 9. This complicates bundling, though, so requires a bit of thinking
through.
2. Signaling error state?
---------
Co-authored-by: Andreas Rumpf <araq4k@proton.me>
(cherry picked from commit 7c873ca615)
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)
fixes https://github.com/nim-lang/Nim/issues/25457
Small chunks allocate memory in fixed-size cells. Each cell is
positioned at exact multiples of the cell size from the chunk's data
start, which makes it much harder to support alignment
```nim
sysAssert c.size == size, "rawAlloc 6"
if c.freeList == nil:
sysAssert(c.acc.int + smallChunkOverhead() + size <= SmallChunkSize,
"rawAlloc 7")
result = cast[pointer](cast[int](addr(c.data)) +% c.acc.int)
inc(c.acc, size)
```
See also https://github.com/nim-lang/Nim/pull/12926
While using big trunk, each allocation gets its own chunk
(cherry picked from commit 94008531c1)
`hashType` proc returned the same hash value from different instanced
generics types like `D[int64]` and `D[F]`.
That caused the struct type with wrong field types.
object/tuple type size check code is generated when it is compiled with
`-d:checkAbi` option.
(cherry picked from commit 88e7adfcb7)
Implements #21928
Adds a `--raw` (since thats what the original issue used, suggestions
welcome) switch which stops the jsondoc gen from rendering rst/markdown.
Implemented by making `genComment` check if it needs to return the raw
string or not. This required switching the related procs to using
`Option` to handle how `nil` values were returned before. The `nil`
returns were eventually ignored so just ignoring `none(T)` has the same
effect.
Doesn't support `runnableExamples` since jsondocs doesn't support them
either
(cherry picked from commit c1e381ae8d)
Issue #16726 reported an internal compiler error (`semcall.nim(229, 18)
nArg != nil`) when calling `toJs` with invalid arguments. The bug has
been fixed in the current codebase but lacked a regression test.
```nim
import std/jsffi
let a = toJs(3)
let b = a.toJs(int) # Now produces: Error: type mismatch
# Previously: internal error
```
**Changes:**
- Added `tests/js/t16726.nim` to verify proper type mismatch error is
reported instead of internal compiler error
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
>
> ----
>
> *This section details on the original issue you should resolve*
>
> <issue_title>internal error: semcall.nim(229, 18) nArg !=
nil</issue_title>
> <issue_description>### Example
> the code below should give a clean CT error, not an internal error
> ```nim
> import std/jsffi
> let a = toJs(3)
> let b = a.toJs(int)
> ```
>
> ### Current Output
> nim r -b:js main
> compiler/semcall.nim(229, 18) `nArg != nil`
>
> ### Expected Output
> proper CT error
>
> ### Additional Information
> 1.5.1 41965880ce
> </issue_description>
>
> <agent_instructions>adds a test case for it and verify it by `./koch
temp js -r test.nim` before committing</agent_instructions>
>
> ## Comments on the Issue (you are @copilot in this section)
>
> <comments>
> <comment_new><author>@ringabout</author><body>
> related:
https://github.com/nim-lang/Nim/issues/15607</body></comment_new>
> </comments>
>
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
- Fixesnim-lang/Nim#16726
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>
(cherry picked from commit 83d7d8c634)
This code was failing to compile with `Error: unhandled exception:
semmagic.nim(247, 5) operand.kind == tyTuple tyAlias [AssertionDefect]`
```nim
import std/typetraits
type
Bar[T] = T
Foo = Bar[tuple[a: int]]
echo Foo.tupleLen
```
Fix was just making `tupleLen` skip alias types also
(cherry picked from commit 91d51923b9)
This is a problem on big-endian CPUs because you end up with nimvm
computing something different than Nim proper, so e.g. a const table
won't work.
I also took the liberty to replace a redundant implementation of load4
in murmurHash.
(Thanks to barracuda156 for helping debug this.)
(cherry picked from commit a061f026a8)