Repository: astral-sh/ruff
File: crates/ruff_linter/src/rules/pylint/rules/repeated_equality_comparison.rs (Rust)

Code before:
    {
        // If there's only one comparison, there's nothing to merge.
        if comparators.len() == 1 {
            continue;
        }

        // Break into sequences of consecutive comparisons.
        let mut sequences: Vec<(Vec<usize>, Vec<&Expr>)> = Vec::new();
        let mut last = None;
        for (index, comparator) in indices.iter().zip(comparators) {
            if last.is_some_and(|last| last + 1 == *index) {
                let (indices, comparators) = sequences.last_mut().unwrap();
                indices.push(*index);
                comparators.push(comparator);
            } else {
                sequences.push((vec![*index], vec![comparator]));
            }
            last = Some(*index);
        }

        for (indices, comparators) in sequences {
            if indices.len() == 1 {
                continue;
            }

            let first_comparable = ComparableExpr::from(comparators[0]);
            if comparators
                .iter()
                .skip(1)
                .all(|&c| ComparableExpr::from(c) == first_comparable)
            {
                // Do not flag if all members are identical
                continue;
            }
            // if we can determine that all the values are hashable, we can use a set
            // TODO: improve with type inference
            let all_hashable = comparators
                .iter()
                .all(|comparator| comparator.is_literal_expr());

            let mut diagnostic = checker.report_diagnostic(
                RepeatedEqualityComparison {
                    expression: SourceCodeSnippet::new(merged_membership_test(
                        expr,
                        bool_op.op,
                        &comparators,
                        checker.locator(),
                        all_hashable,
                    )),
                    all_hashable,
                },

Review comment (suggestion):
I don't _think_ we can get here if `comparators` is empty, but it always makes me nervous to index like this, just in case, since it will panic when empty. What do you think about wrapping this check in:

```rust
if let Some(comparator) = comparators.first() {
   // ...
}
```

Code after:
    {
        // If there's only one comparison, there's nothing to merge.
        if comparators.len() == 1 {
            continue;
        }

        // Break into sequences of consecutive comparisons.
        let mut sequences: Vec<(Vec<usize>, Vec<&Expr>)> = Vec::new();
        let mut last = None;
        for (index, comparator) in indices.iter().zip(comparators) {
            if last.is_some_and(|last| last + 1 == *index) {
                let (indices, comparators) = sequences.last_mut().unwrap();
                indices.push(*index);
                comparators.push(comparator);
            } else {
                sequences.push((vec![*index], vec![comparator]));
            }
            last = Some(*index);
        }

        for (indices, comparators) in sequences {
            if indices.len() == 1 {
                continue;
            }

            if let Some((&first, rest)) = comparators.split_first() {
                let first_comparable = ComparableExpr::from(first);

                if rest
                    .iter()
                    .all(|&c| ComparableExpr::from(c) == first_comparable)
                {
                    // Do not flag if all members are identical
                    continue;
                }
            }

            // if we can determine that all the values are hashable, we can use a set
            // TODO: improve with type inference
            let all_hashable = comparators
                .iter()
                .all(|comparator| comparator.is_literal_expr());

            let mut diagnostic = checker.report_diagnostic(
                RepeatedEqualityComparison {
                    expression: SourceCodeSnippet::new(merged_membership_test(
                        expr,
                        bool_op.op,
                        &comparators,
                        checker.locator(),
                        all_hashable,