Skip to content

Add Step::forward/backward_overflowing to enable RangeInclusive loop optimizations#155114

Open
pitaj wants to merge 6 commits intorust-lang:mainfrom
pitaj:rangeinclusiveiter-optimize
Open

Add Step::forward/backward_overflowing to enable RangeInclusive loop optimizations#155114
pitaj wants to merge 6 commits intorust-lang:mainfrom
pitaj:rangeinclusiveiter-optimize

Conversation

@pitaj
Copy link
Copy Markdown
Contributor

@pitaj pitaj commented Apr 10, 2026

View all comments

ACP: rust-lang/libs-team#767

This adds new required methods to the Step trait:

trait Step: ... {
    // ... existing functions

    // New required functions
    fn forward_overflowing(start: Self, count: usize) -> (Self, bool);
    fn backward_overflowing(start: Self, count: usize) -> (Self, bool);
}

It was found that using these to implement RangeInclusive's Iterator impl enabled optimizations previously only applicable to the exclusive-ended Range.

This required changing how "exhaustion" works for RangeInclusive. I've nominated this for libs-api discussion because of one insta-stable change:

The new implementations now only set exhausted when overflow occurs, and start is now advanced past end otherwise. I doubt anyone depends on the prior behavior, but it's probably worth a crater run.

The exhaustion changes also affect Debug but my understanding is that debug formatting is never guaranteed stable.

I have now changed the nth impls to use the new functions as well.

r? libs

but RangeInclusive loops do not
@pitaj pitaj added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Apr 10, 2026
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 10, 2026
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

and optimize the RangeInclusive iterator implementation with them

This changes the `exhausted` field to represent an overflow flag
for the bounds, essentially acting as an extra bit for `Idx`.
This was found to enable optimizations previously only applicable
to the exclusive-ended Range type.
@pitaj pitaj force-pushed the rangeinclusiveiter-optimize branch from d0c1f8d to 39e74a3 Compare April 10, 2026 18:01
@Amanieu Amanieu removed the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Apr 14, 2026
@Amanieu
Copy link
Copy Markdown
Member

Amanieu commented Apr 14, 2026

We discussed this in the @rust-lang/libs-api meeting.

The PartialEq implementation as proposed violates the reflexivity requirement of the Eq trait which states that a == a must always be true. Instead, could equality be computed by ignoring the start field if the range is exhausted? This would treat the combination of start and exhausted as an Option<Idx> for the purposes of comparison.

If the PartialEq implementation can be fixed, we are happy to accept this after a crater run.

@pitaj
Copy link
Copy Markdown
Contributor Author

pitaj commented Apr 14, 2026

Right, I forgot this implements Eq even though I implemented it manually 🤦‍♂️. exhausted.then_some(self.start) could work though it's less meaningful if the range was exhausted by reverse iteration.

@Amanieu I'm not sure it gains much over just going back to the derive, would that be acceptable?

@Amanieu
Copy link
Copy Markdown
Member

Amanieu commented Apr 14, 2026

RangeInclusive doesn't support reverse iteration.

The derive is also acceptable. We explicitly document that start has an unspecified value after exhaustion, so it makes sense for equality to also be unspecified.

@pitaj
Copy link
Copy Markdown
Contributor Author

pitaj commented Apr 14, 2026

RangeInclusive doesn't support reverse iteration.

It implements DoubleEndedIterator but regardless yeah I'll change it back to the derive

@pitaj
Copy link
Copy Markdown
Contributor Author

pitaj commented Apr 16, 2026

@rustbot ready

@theemathas
Copy link
Copy Markdown
Contributor

I found a bug with this PR.

fn main() {
    let mut range = 255_u8..=255_u8;
    let _ = range.next();
    println!("{range:?}");
    println!("{}", range.contains(&100_u8));
}

Output of above code on nightly:

255..=255 (exhausted)
false

Output of above code with this PR:

0..=255 (exhausted)
true

(The desired behavior of the RangeBounds methods also need to be figured out.)

@theemathas theemathas added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 16, 2026
@theemathas
Copy link
Copy Markdown
Contributor

And here's some strange behavior that's possibly a bug:

fn main() {
    let mut range = 0_usize..=0_usize;
    let _ = range.next_back();
    println!("{range:?}");
    let data = [0; 1000];
    println!("{:?}", &data[range]);
}

Output of above code on nightly:

0..=0 (exhausted)
[]

Output of above code with this PR:

0..=18446744073709551615 (exhausted)

thread 'main' (188575) panicked at src/main.rs:6:27:
range end index 18446744073709551615 out of range for slice of length 1000
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Comment thread library/core/src/iter/range.rs Outdated

let (n, o) = Step::forward_overflowing(self.start.clone(), 1);

self.exhausted |= o;
Copy link
Copy Markdown
Contributor

@theemathas theemathas Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.exhausted |= o;
self.exhausted = o;

self.exhausted is always false before this line.

View changes since the review

Comment thread library/core/src/iter/range.rs Outdated
}
}
self.start = plus_1;
self.exhausted |= on | o1;
Copy link
Copy Markdown
Contributor

@theemathas theemathas Apr 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.exhausted |= on | o1;
self.exhausted = on | o1;

Same thing here

View changes since the review

@theemathas theemathas added the needs-crater This change needs a crater run to check for possible breakage in the ecosystem. label Apr 16, 2026
pitaj added 3 commits April 16, 2026 10:32
change end_bound to return Excluded(start) when exhausted
add contains to tests
matches From<legacy::RangeInclusive<T>> for RangeInclusive<T>

and expand explanation for into_slice_range
@pitaj
Copy link
Copy Markdown
Contributor Author

pitaj commented Apr 16, 2026

@theemathas

I found a bug with this PR.

Good find on contains, that should be fixed now. Added some tests as well.

And here's some strange behavior that's possibly a bug

This is expected behavior from the new overflowing behavior. Given that the values of start and end have always been unspecified when exhausted, the indexing behavior is also unspecified - so I don't think this is an issue.

(The desired behavior of the RangeBounds methods also need to be figured out.)

I think the end_bound change I just made should resolve this. Now end_bound will return Excluded(start) when exhausted, which ensures (start_bound, end_bound) is always empty. This is fine since the values are unspecified anyways. Excluded(end) no longer works since end is no longer held equal to start on exhaustion.

I also changed into_bounds to panic when converting if exhausted. This matches the behavior of the conversion to the new RangeInclusive type, and is the only viable way of implementing IntoBounds unrestricted with the change. IntoBounds is unstable, so this can still be changed.

Nominating for libs-api approval of those changes

@pitaj pitaj added I-libs-api-nominated Nominated for discussion during a libs-api team meeting. S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 16, 2026
@nia-e nia-e added I-libs-api-nominated Nominated for discussion during a libs-api team meeting. and removed I-libs-api-nominated Nominated for discussion during a libs-api team meeting. labels Apr 21, 2026
@Amanieu
Copy link
Copy Markdown
Member

Amanieu commented Apr 21, 2026

This was discussed the @rust-lang/libs-api meeting. We're happy with the end_bound change. Let's get a crater run started.

@bors try

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Apr 21, 2026
Add `Step::forward/backward_overflowing` to enable RangeInclusive loop optimizations
@Amanieu Amanieu removed the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Apr 21, 2026
@rust-bors rust-bors Bot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 21, 2026
@rust-bors

This comment has been minimized.

@pitaj

This comment has been minimized.

@rust-bors

This comment has been minimized.

@Zalathar
Copy link
Copy Markdown
Member

@bors try

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Apr 22, 2026
Add `Step::forward/backward_overflowing` to enable RangeInclusive loop optimizations
@theemathas theemathas added the relnotes Marks issues that should be documented in the release notes of the next release. label Apr 22, 2026
@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented Apr 22, 2026

☀️ Try build successful (CI)
Build commit: b8e88e5 (b8e88e5ddf5521a9f43ee3f62a702388c713e4bb, parent: f9988fefd3add01f414f52b414308e7872622fee)

@tgross35
Copy link
Copy Markdown
Contributor

@craterbot run mode=build-and-test

(per #t-libs > crater run for #155114)

@craterbot
Copy link
Copy Markdown
Collaborator

👌 Experiment pr-155114 created and queued.
🤖 Automatically detected try build b8e88e5
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 22, 2026
@craterbot
Copy link
Copy Markdown
Collaborator

🚧 Experiment pr-155114 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-crater This change needs a crater run to check for possible breakage in the ecosystem. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-crater Status: Waiting on a crater run to be completed. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants