Fix iterable resolution, prefer iterator overloads#25679
Open
ZoomRmc wants to merge 7 commits intonim-lang:develfrom
Open
Fix iterable resolution, prefer iterator overloads#25679ZoomRmc wants to merge 7 commits intonim-lang:develfrom
iterable resolution, prefer iterator overloads#25679ZoomRmc wants to merge 7 commits intonim-lang:develfrom
Conversation
Recheck direct-call operands for tyIterable, propagate iterable preference through template re-semchecking, and rank iterator candidates with a dedicated iteratorPreference bucket. This fixes cases like text.split.collect() where split previously resolved to the seq-returning overload before the surrounding iterable[T] requirement was applied.
`iterBase` is now wrong here when the loop source was wrapped as tyIterable, because the loop variable should not get the wrapper `iterAfterVarLent` would be too stripped, because it removes tyGenericInst `iterType` is the middle ground: - removes outer tyIterable / alias-like wrappers - preserves tyGenericInst
Araq
reviewed
Mar 28, 2026
metagn
reviewed
Mar 28, 2026
`prepareOperand` no longer retries every already-typed direct call for iterable[T], only calls where overload resolution has seen a plausible iterator candidate fixes the new call check against nkCallKinds, not just nkCall sem.nim: remove `iprefersIteratorForIterable`
Member
|
@metagn review it one more time please. |
metagn
reviewed
Mar 31, 2026
Collaborator
|
No other objections to the implementation, and the design is unlikely to cause regressions from what I understand, should be good except the 1 comment above. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This fixes type resolution for
iterable[T].I want to proceed with RFC #562 and this is the main blocker for composability.
Fixes #22098 and, arguably, #19206
In cases like
strutils.split, where both proc and iterator overload exists, the compiler resolves to thefuncoverload causing a type mismatch.The old mode resolved
text.splittoseq[string]before the surroundingiterable[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 insequtils, whose internal iterator setup we have zero control over (e.g. hard-coding adapters likeitems).Also, I noticed in
semstmtsthat anonymous iterators are alwaysclosure, 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
semOpAuxeagerly pre-types all arguments with plain flags before overload resolution begins, so by the timeprepareOperandprocessessplitagainst theiterable[T], the wrong overload has already won.The fix touches a few places:
prepareOperandinsigmatch.nim:When
formal.kind == tyIterableand the argument was already typed as something else, it's re-semchecked with theefPreferIteratorForIterableflag. The recheck is limited to direct calls (a[0].kind in {nkIdent, nkAccQuoted, nkSym, nkOpenSym}) to avoid recursing throughsemIndirectOp/semOpAuxagain.iteratorPreferencefieldTCandidate, checked beforegenericMatchesincmpCandidates, gives the iterator overload a win without touching the existing iterator heuristic used byforloops.Limitations:
The implementation is still flag-driven rather than purely formal-driven, so the behaviour is a bit too broad
efWantIterablecan cause iterator results to be wrapped astyIterablein iterable-admitting contexts, not only wheniterable[T]match is being processed.iterable[T]still does not accept closure iterator values such asiterator(): T {.closure.}. It only matches the compiler's internaltyIterable, 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.