fix(parser): infer for loop items from iterable unions#18551
Merged
Conversation
## Description
`parse_for` inferred the loop variable from the type of the iterable expression.
That works for direct list, table, and range types, but it fails for iterable
unions returned by commands such as `skip`.
For `oneof<table, binary, list<any>>`, the loop variable was typed as the whole
iterable union instead of the yielded row or item type. With
`enforce-runtime-annotations` enabled, assigning the yielded value to that loop
variable raised a runtime type mismatch.
The parser now maps iterable types to their yielded types when inferring the
loop variable type, including alternatives inside `oneof`.
## User-facing changes (Release notes)
Fixed an issue where `for` loops over command outputs with union iterable types
could fail runtime type checking.
##### example: filter output union
<table>
<tr>
<td>Code</td>
<td width="1000">
```nushell
let pending = ([a] | each {} | collect | skip 0)
for item in $pending { print $item }
```
</td>
</tr>
<tr>
<td>Before</td>
<td>
```ansi
Error: nu::shell::type_mismatch
× Type mismatch.
╭─[source:1:17]
1 │ let pending = ([a] | each {} | collect | skip 0); for item in $pending { print $item }
· ┬ ──┬─
· │ ╰── expected oneof<table, binary, list<any>>, got string
· ╰── the value is a string
╰────
```
</td>
</tr>
<tr>
<td>After</td>
<td>
```ansi
a
```
</td>
</tr>
</table>
## Additional notes
Added regression coverage for `for` over filter outputs and over commands
returning unions of iterable types.
Contributor
|
Thanks! |
nidara-duo
pushed a commit
to nidara-duo/nushell
that referenced
this pull request
Jul 11, 2026
## Description
`parse_for` inferred the loop variable from the type of the iterable
expression. That works for direct list, table, and range types, but
fails for iterable unions returned by commands like `skip`.
For `oneof<table, binary, list<any>>`, the loop variable was typed as
the whole iterable union instead of the yielded row or item type. With
`enforce-runtime-annotations` enabled, assigning the yielded value to
that loop variable raised a runtime type mismatch.
The parser now maps iterable types to their yielded types when inferring
the loop variable type, including alternatives inside `oneof`.
### example: filter output union
<table>
<tr>
<td>Code</td>
<td width="1000">
```nushell
let pending = ([a] | each {} | collect | skip 0)
for item in $pending { print $item }
```
</td>
</tr>
<tr>
<td>Before</td>
<td>
```ansi
Error: nu::shell::type_mismatch
× Type mismatch.
╭─[source:1:17]
1 │ let pending = ([a] | each {} | collect | skip 0); for item in $pending { print $item }
· ┬ ──┬─
· │ ╰── expected oneof<table, binary, list<any>>, got string
· ╰── the value is a string
╰────
```
</td>
</tr>
<tr>
<td>After</td>
<td>
```ansi
a
```
</td>
</tr>
</table>
## User-facing changes (Release notes)
- Fixed an issue in `for` loops where type of the looping variable was
inferred incorrectly when iterating over a value/stream with a union
type (`oneof<list, table, binary>`). This could manifest as a runtime
type checking error with `enforce-runtime-annotations` enabled.
---------
Co-authored-by: Bahex <17417311+Bahex@users.noreply.github.com>
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.
Description
parse_forinferred the loop variable from the type of the iterable expression. That works for direct list, table, and range types, but fails for iterable unions returned by commands likeskip.For
oneof<table, binary, list<any>>, the loop variable was typed as the whole iterable union instead of the yielded row or item type. Withenforce-runtime-annotationsenabled, assigning the yielded value to that loop variable raised a runtime type mismatch.The parser now maps iterable types to their yielded types when inferring the loop variable type, including alternatives inside
oneof.example: filter output union
User-facing changes (Release notes)
forloops where type of the looping variable was inferred incorrectly when iterating over a value/stream with a union type (oneof<list, table, binary>). This could manifest as a runtime type checking error withenforce-runtime-annotationsenabled.