Skip to content

fix(parser): infer for loop items from iterable unions#18551

Merged
Bahex merged 3 commits into
nushell:mainfrom
Alb-O:iter-union-infer
Jul 9, 2026
Merged

fix(parser): infer for loop items from iterable unions#18551
Bahex merged 3 commits into
nushell:mainfrom
Alb-O:iter-union-infer

Conversation

@Alb-O

@Alb-O Alb-O commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

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

Code
let pending = ([a] | each {} | collect | skip 0)
for item in $pending { print $item }
Before
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
   ╰────
After
a

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.

@github-actions github-actions Bot added the A:parser Issues related to parsing label Jul 8, 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 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.
@Alb-O Alb-O force-pushed the iter-union-infer branch from 9b543c3 to 9fd2c10 Compare July 8, 2026 21:14
@Bahex Bahex added the A:type-system Problems or features related to nushell's type system label Jul 9, 2026
@Bahex Bahex force-pushed the iter-union-infer branch from 6571199 to 9bed383 Compare July 9, 2026 10:26
@Bahex Bahex merged commit 63ca014 into nushell:main Jul 9, 2026
17 checks passed
@github-actions github-actions Bot added this to the v0.115.0 milestone Jul 9, 2026
@fdncred

fdncred commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Thanks!

@Alb-O Alb-O deleted the iter-union-infer branch July 10, 2026 23:36
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>
@cptpiepmatz cptpiepmatz added notes:fixes Noted in "Bug fixes" section notes:ready Indicates Ready for Release notes labels Jul 11, 2026
@cptpiepmatz cptpiepmatz modified the milestones: v0.115.0, v0.114.1 Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A:parser Issues related to parsing A:type-system Problems or features related to nushell's type system notes:fixes Noted in "Bug fixes" section notes:ready Indicates Ready for Release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants