Skip to content

RangeInclusive::contains doesn't consider exhaustion #77941

Closed
@cuviper

Description

@cuviper

I tried this code:

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));
}

I expected to see this happen: all assertions pass.

Instead, this happened: the last assertion fails.

Meta

Playground link

The behavior is the same across stable 1.47.0, 1.48.0-beta.2, and 1.49.0-nightly (2020-10-13 adef9da30f1ecbfeb813).

Analysis

The implementation of is_empty includes a check for the exhausted flag:

    pub fn is_empty(&self) -> bool {
        self.exhausted || !(self.start <= self.end)
    }

But contains only looks at the raw bounds:

    pub fn contains<U>(&self, item: &U) -> bool
    where
        Idx: PartialOrd<U>,
        U: ?Sized + PartialOrd<Idx>,
    {
        <Self as RangeBounds<Idx>>::contains(self, item)
    }

It would be easy to insert !self.exhausted && ... in there, as long as we're OK with the behavior change, which I consider a bug fix. I think the exhausted state of start/end is unspecified, so nobody should be depending on contains being true then.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.T-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions