[Chapel Merge] Avoid infinite loops in (serial) unbounded range i

Branch: refs/heads/main
Revision: e38d9e4
Author: bradcray
Link: Unavailable
Log Message:

Merge pull request #19991 from bradcray/unbounded-range-iters-not-infinite

Avoid infinite loops in (serial) unbounded range iterators

[reviewed by @stonea]

This changes the serial iterators for unbounded integral ranges such
that as they are about to run off the top or bottom of the range, they print
an error and halt rather than wrapping around to the extreme integer
on the other side as we have traditionally done. The approach taken is to
compute the near-maximum bound, exit the loop once it is reached to
avoid wrapping around within the loop itself, and then print an error if that
maximal value was reached. This conditional turns out to be important
because, without it, when we zipper unbounded ranges serially in the
"follower" position, we hit the halt.

It is tempting to add an additional yield after the loop exits corresponding
to the most extreme index value (e.g., 127 for 1:uint(8)..), but doing
so breaks our serial zippered loop optimization when an unbounded range
is used as a follower, as in zip(whatever, 1..). It seemed preferable to
keep the performance and complain about falling off the end of the loop
after yielding 126 than to get this most extreme value.

Both of the cases above in which the unbounded range is used as a follower
could arguably by seen as (additional) motivation for supporting distinct
iterators for serial standalone vs. follower iterators (the main traditional one
being to give users the tools to write their own unbounded follower iterators).

For unbounded ranges over enums and bools, the process is similar, but
slightly different since the problem of wraparound doesn't exist (well...
for most reasonably sized enums anyway). We just iterate through all the
values and then return without an error.

Added some tests of various upward and downward iterations over unbounded
ranges of ints, enums, bools x strided vs. non-.

Modified Files:
A test/types/range/unbounded/unboundedBoolEnum.chpl

A test/types/range/unbounded/unboundedBoolEnum.good
A test/types/range/unbounded/unboundedEnumIntVals.chpl
A test/types/range/unbounded/unboundedEnumIntVals.good
A test/types/range/unbounded/unboundedIter-2.good
A test/types/range/unbounded/unboundedIter-3.good
A test/types/range/unbounded/unboundedIter-4.good
A test/types/range/unbounded/unboundedIter-5.good
A test/types/range/unbounded/unboundedIter-6.good
A test/types/range/unbounded/unboundedIter.chpl
A test/types/range/unbounded/unboundedIter.execopts
A test/types/range/unbounded/unboundedIter.good
M modules/internal/ChapelRange.chpl

Compare: https://github.com/chapel-lang/chapel/compare/bbeb73eddaea...e38d9e4021ee