implement multi-object for loops by andrewrk · Pull Request #14671 · ziglang/zig

3 min read Original article ↗

@andrewrk added enhancement

Solving this issue will likely involve adding new logic or components to the codebase.

breaking

Implementing this issue could cause existing code to no longer compile or have different behavior.

frontend

Tokenization, parsing, AstGen, Sema, and Liveness.

labels

Feb 18, 2023

@andrewrk andrewrk marked this pull request as ready for review

February 18, 2023 23:34

Vexu and others added 12 commits

February 18, 2023 19:17
* Allow unbounded looping.
* Lower by incrementing raw pointers for each iterable rather than
  incrementing a single index variable. This elides safety checks
  without any analysis required thanks to the length assertion and
  lowers to decent machine code even in debug builds.
  - An "end" value is selected, prioritizing a counter if possible,
    falling back to a runtime calculation of ptr+len on a slice input.
* Specialize on the pattern `0..`, avoiding an unnecessary subtraction
  instruction being emitted.
* Add the `for_check_lens` ZIR instruction.
This strategy uses pointer arithmetic to iterate through the loop. This
has a problem, however, which is tuples. AstGen does not know whether a
given indexable is a tuple or can be iterated based on contiguous
memory. Tuples unlike other indexables cannot be represented as a
many-item pointer that is incremented as the loop counter.

So, after this commit, I will modify AstGen back closer to how @Vexu had
it before, using a counter and array element access.
The intent here is to revert this commit after Zig 0.10.0 is released.
This also makes another breaking change to for loops: in order to
capture a pointer of an element, one must take the address of array
values. This simplifies a lot of things, and makes more sense than how
it was before semantically.

It is still legal to use a for loop on an array value if the
corresponding element capture is byval instead of byref.

@andrewrk

@andrewrk

@andrewrk

@andrewrk

@andrewrk

@andrewrk

@andrewrk

@andrewrk

@andrewrk

One of the main points of for loops is that you can safety check the
length once, before entering the loop, and then safely assume that every
element inside the loop is in bounds.

In master branch, the safety checks are incorrectly intact even inside
for loops. This commit fixes it. It's especially nice with multi-object
loops because the number of elided checks is N * M where N is how many
iterations and M is how many objects.

@andrewrk

@andrewrk

Since for loops are statically analyzed to have an upper bound, and the
loop counter is a usize, it is impossible for it to overflow.

@andrewrk

@andrewrk

@andrewrk

andrewrk pushed a commit to ziglang/www.ziglang.org that referenced this pull request

Feb 21, 2023

@mlugg mlugg mentioned this pull request

Feb 26, 2023

@Vexu Vexu mentioned this pull request

Mar 27, 2023