Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check for exhaustion in RangeInclusive::contains and slicing #78109

Merged
merged 3 commits into from
Oct 24, 2020

Conversation

cuviper
Copy link
Member

@cuviper cuviper commented Oct 19, 2020

When a range has finished iteration, is_empty returns true, so it
should also be the case that contains returns false.

Fixes #77941.

When a range has finished iteration, `is_empty` returns true, so it
should also be the case that `contains` returns false.
@rust-highfive
Copy link
Collaborator

r? @shepmaster

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 19, 2020
@cuviper
Copy link
Member Author

cuviper commented Oct 19, 2020

This might want @rust-lang/libs FCP per #77941 (comment).

@cuviper
Copy link
Member Author

cuviper commented Oct 19, 2020

I've moved the exhausted check to RangeBounds::end_bound, per @SkiFire13's observation in #77941 (comment).

@jyn514
Copy link
Member

jyn514 commented Oct 19, 2020

I don't know why the end should be treated specially. If you think this is useful, shouldn't it apply to all parts of iteration equally, and let mut iter = 0..5; iter.next(); iter.contains(0) return false?

@jyn514 jyn514 added A-iterators Area: Iterators T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Oct 19, 2020
@cuviper
Copy link
Member Author

cuviper commented Oct 19, 2020

This is about RangeInclusive, so your example should be 0..=5, but otherwise yes! Once you advance the iterator, contains(&0) will be false, and this is already the case. Well, except if you advance in reverse to exhaustion, then it would be "empty" but still "contain" start==end==0, until this PR.

The inclusive end is special by nature, that's the whole point. Once the iterator reaches start == end, we have two possible states: !exhausted where the next value is that start/end value, then exhausted where we are empty. But contains didn't consider the latter state, which is what I'm addressing now.

@jyn514
Copy link
Member

jyn514 commented Oct 19, 2020

Got it, thanks, I didn't realize this was fixing an omission. Looks good to me then :)

Also, wow, Range being an Iterator is very confusing.

@SkiFire13
Copy link
Contributor

It would also be nice to have some tests that check this behaviour

@dtolnay
Copy link
Member

dtolnay commented Oct 20, 2020

@rust-lang/libs: this PR changes the implementation of RangeBounds for RangeInclusive in such a way that the following assertions succeed. Previously range.contains(end) continued returning true even after range.is_empty() was true.

fn main() {
    let mut range = 0..=0;
    assert!(!range.is_empty());
    assert!(range.contains(&0));

    range.next();
    assert!(range.is_empty());
    assert!(!range.contains(&0));
}

Another example of the behavior change:

fn main() {
    let array = ['w', 'x', 'y', 'z'];
    let mut range = 0..=3;
    while let Some(i) = range.next() {
        println!(
            "after i={}, the remaining elements are {:?}",
            i, &array[range.clone()],
        );
    }
}

Old behavior:

after i=0, the remaining elements are ['x', 'y', 'z']
after i=1, the remaining elements are ['y', 'z']
after i=2, the remaining elements are ['z']
after i=3, the remaining elements are ['z']

New behavior:

after i=0, the remaining elements are ['x', 'y', 'z']
after i=1, the remaining elements are ['y', 'z']
after i=2, the remaining elements are ['z']
after i=3, the remaining elements are []

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Oct 20, 2020

Team member @dtolnay has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Oct 20, 2020
@dtolnay dtolnay assigned dtolnay and unassigned shepmaster Oct 20, 2020
@cuviper
Copy link
Member Author

cuviper commented Oct 20, 2020

@SkiFire13 I figured the doc-test was sufficient -- I don't see any other existing tests of ranged contains.

@dtolnay this doesn't actually affect slicing (yet) because SliceIndex is a separate thing. I was going to followup separately, but I can add that change to this PR if you'd prefer to do it all at once.

@dtolnay
Copy link
Member

dtolnay commented Oct 20, 2020

Let's consider both as part of this FCP. I imagine we'd not want to do one without the other. But the code change for SliceIndex can go in either this PR or separate PR if easier.

@Mark-Simulacrum Mark-Simulacrum added the relnotes Marks issues that should be documented in the release notes of the next release. label Oct 20, 2020
@cuviper
Copy link
Member Author

cuviper commented Oct 21, 2020

Preserving bounds checking for exhausted SliceIndex was tricky to think about, but I think I've got it working now.

@cuviper cuviper changed the title Check for exhaustion in RangeInclusive::contains Check for exhaustion in RangeInclusive::contains and slicing Oct 21, 2020
Copy link
Member

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

Implementation looks good to me. Thank you @cuviper.

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Oct 23, 2020
@rfcbot
Copy link

rfcbot commented Oct 23, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@dtolnay
Copy link
Member

dtolnay commented Oct 23, 2020

@bors r+

@bors
Copy link
Contributor

bors commented Oct 23, 2020

📌 Commit 9202fbd has been approved by dtolnay

@bors
Copy link
Contributor

bors commented Oct 23, 2020

🌲 The tree is currently closed for pull requests below priority 1000, this pull request will be tested once the tree is reopened

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 23, 2020
bors added a commit to rust-lang-ci/rust that referenced this pull request Oct 24, 2020
…as-schievink

Rollup of 15 pull requests

Successful merges:

 - rust-lang#76649 (Add a spin loop hint for Arc::downgrade)
 - rust-lang#77392 (add `insert` to `Option`)
 - rust-lang#77716 (Revert "Allow dynamic linking for iOS/tvOS targets.")
 - rust-lang#78109 (Check for exhaustion in RangeInclusive::contains and slicing)
 - rust-lang#78198 (Simplify assert terminator only if condition evaluates to expected value)
 - rust-lang#78243 (--test-args flag description)
 - rust-lang#78249 (improve const infer error)
 - rust-lang#78250 (Document inline-const)
 - rust-lang#78264 (Add regression test for issue-77475)
 - rust-lang#78274 (Update description of Empty Enum for accuracy)
 - rust-lang#78278 (move `visit_predicate` into `TypeVisitor`)
 - rust-lang#78292 (Loop instead of recursion)
 - rust-lang#78293 (Always store Rustdoc theme when it's changed)
 - rust-lang#78300 (Make codegen coverage_context optional, and check)
 - rust-lang#78307 (Revert "Set .llvmbc and .llvmcmd sections as allocatable")

Failed merges:

r? `@ghost`
@bors bors merged commit d9acd7d into rust-lang:master Oct 24, 2020
@rustbot rustbot added this to the 1.49.0 milestone Oct 24, 2020
@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. to-announce Announce this issue on triage meeting and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Nov 2, 2020
@spastorino spastorino removed the to-announce Announce this issue on triage meeting label Nov 5, 2020
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Feb 14, 2021
Pkgsrc changes:
 * Adjust patches, convert tabs to spaces so that tests pass.
 * Remove patches which are no longer needed (upstream changed)
 * Minor adjustments for SunOS, e.g. disable stack probes.
 * Adjust cargo checksum patching accordingly.
 * Remove commented-out use of PATCHELF on NetBSD, which doesn't work anyway...

Upstream changes:

Version 1.49.0 (2020-12-31)
============================

Language
-----------------------

- [Unions can now implement `Drop`, and you can now have a field in a union
  with `ManuallyDrop<T>`.][77547]
- [You can now cast uninhabited enums to integers.][76199]
- [You can now bind by reference and by move in patterns.][76119] This
  allows you to selectively borrow individual components of a type. E.g.
  ```rust
  #[derive(Debug)]
  struct Person {
      name: String,
      age: u8,
  }

  let person = Person {
      name: String::from("Alice"),
      age: 20,
  };

  // `name` is moved out of person, but `age` is referenced.
  let Person { name, ref age } = person;
  println!("{} {}", name, age);
  ```

Compiler
-----------------------

- [Added tier 1\* support for `aarch64-unknown-linux-gnu`.][78228]
- [Added tier 2 support for `aarch64-apple-darwin`.][75991]
- [Added tier 2 support for `aarch64-pc-windows-msvc`.][75914]
- [Added tier 3 support for `mipsel-unknown-none`.][78676]
- [Raised the minimum supported LLVM version to LLVM 9.][78848]
- [Output from threads spawned in tests is now captured.][78227]
- [Change os and vendor values to "none" and "unknown" for some targets][78951]

\* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.

Libraries
-----------------------

- [`RangeInclusive` now checks for exhaustion when calling `contains`
  and indexing.][78109]
- [`ToString::to_string` now no longer shrinks the internal buffer
  in the default implementation.][77997]
- [`ops::{Index, IndexMut}` are now implemented for fixed sized
  arrays of any length.][74989]

Stabilized APIs
---------------

- [`slice::select_nth_unstable`]
- [`slice::select_nth_unstable_by`]
- [`slice::select_nth_unstable_by_key`]

The following previously stable methods are now `const`.

- [`Poll::is_ready`]
- [`Poll::is_pending`]

Cargo
-----------------------
- [Building a crate with `cargo-package` should now be independently
  reproducible.][cargo/8864]
- [`cargo-tree` now marks proc-macro crates.][cargo/8765]
- [Added `CARGO_PRIMARY_PACKAGE` build-time environment
  variable.]  [cargo/8758] This variable will be set if the crate
  being built is one the user selected to build, either with `-p`
  or through defaults.
- [You can now use glob patterns when specifying packages &
  targets.][cargo/8752]


Compatibility Notes
-------------------
- [Demoted `i686-unknown-freebsd` from host tier 2 to target tier
  2 support.][78746]
- [Macros that end with a semi-colon are now treated as statements
  even if they expand to nothing.][78376]
- [Rustc will now check for the validity of some built-in attributes
  on enum variants.][77015] Previously such invalid or unused
  attributes could be ignored.
- Leading whitespace is stripped more uniformly in documentation
  comments, which may change behavior. You read [this post about
  the changes][rustdoc-ws-post] for more details.
- [Trait bounds are no longer inferred for associated types.][79904]

Internal Only
-------------
These changes provide no direct user facing benefits, but represent
significant improvements to the internals and overall performance
of rustc and related tools.

- [rustc's internal crates are now compiled using the `initial-exec` Thread
  Local Storage model.][78201]
- [Calculate visibilities once in resolve.][78077]
- [Added `system` to the `llvm-libunwind` bootstrap config option.][77703]
- [Added `--color` for configuring terminal color support to bootstrap.][79004]


[75991]: rust-lang/rust#75991
[78951]: rust-lang/rust#78951
[78848]: rust-lang/rust#78848
[78746]: rust-lang/rust#78746
[78376]: rust-lang/rust#78376
[78228]: rust-lang/rust#78228
[78227]: rust-lang/rust#78227
[78201]: rust-lang/rust#78201
[78109]: rust-lang/rust#78109
[78077]: rust-lang/rust#78077
[77997]: rust-lang/rust#77997
[77703]: rust-lang/rust#77703
[77547]: rust-lang/rust#77547
[77015]: rust-lang/rust#77015
[76199]: rust-lang/rust#76199
[76119]: rust-lang/rust#76119
[75914]: rust-lang/rust#75914
[74989]: rust-lang/rust#74989
[79004]: rust-lang/rust#79004
[78676]: rust-lang/rust#78676
[79904]: rust-lang/rust#79904
[cargo/8864]: rust-lang/cargo#8864
[cargo/8765]: rust-lang/cargo#8765
[cargo/8758]: rust-lang/cargo#8758
[cargo/8752]: rust-lang/cargo#8752
[`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable
[`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by
[`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key
[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html
[`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready
[`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending
[rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc
@cuviper cuviper deleted the exhausted-rangeinc branch September 21, 2021 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-iterators Area: Iterators disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

RangeInclusive::contains doesn't consider exhaustion