Files
Nim/tests
Zoom 5df28ab02a Fix iterable resolution, prefer iterator overloads (#25679)
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)
2026-04-02 08:34:34 +02:00
..
2024-06-06 00:52:01 +02:00
2021-08-21 08:22:00 +02:00
2026-02-16 09:13:45 +01:00
2025-11-15 12:26:15 +01:00
2025-03-03 14:01:41 +01:00
2023-07-22 21:11:08 +02:00
2025-12-18 20:53:04 +01:00
2025-03-31 14:00:39 +02:00
2022-12-22 08:32:12 +01:00
2013-03-16 23:53:07 +01:00
2020-12-28 14:13:21 +01:00

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.