Skip to content

collapsible_match suggestion incomplete #14155

Open
@nk9

Description

@nk9

Summary

I have the following code:

    pub fn find_railroad_name(lcomponents: &mut Vec<&str>) -> Option<String> {
        if let Some(last) = lcomponents.last() {
            match *last {
                "r.r." | "railroad" | "rr" => {
                    lcomponents.pop();
                    return Some(lcomponents.join(" "));
                }
                _ => (),
            }
        }

        None
    }

Clippy warns about this:

20  warning: this `match` can be collapsed into the outer `if let`
    --> rust/models/src/boundary_name.rs:283:13
     |
 283 | /             match *last {
 284 | |                 "r.r." | "railroad" | "rr" => {
 285 | |                     lcomponents.pop();
 286 | |                     return Some(lcomponents.join(" "));
 287 | |                 }
 288 | |                 _ => (),
 289 | |             }                                                                                                                                                                      ▐
     | |_____________^                                                                                                                                                                      ▐
     |                                                                                                                                                                                      ▐
 help: the outer pattern can be modified to include the inner pattern                                                                                                                       ▐
    --> rust/models/src/boundary_name.rs:282:21                                                                                                                                             ▐
     |                                                                                                                                                                                      ▐
 282 |         if let Some(last) = lcomponents.last() {                                                                                                                                     ▐
     |                     ^^^^ replace this binding                                                                                                                                        ▐
 283 |             match *last {                                                                                                                                                            ▐
 284 |                 "r.r." | "railroad" | "rr" => {                                                                                                                                      ▐
     |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ with this pattern                                                                                                                         ▐
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_match                                                                      ▐
     = note: `#[warn(clippy::collapsible_match)]` on by default                                                                                                                             ▐

I tried doing what it suggested and got three compiler errors:

    pub fn find_railroad_name(lcomponents: &mut Vec<&str>) -> Option<String> {
        if let Some("r.r." | "railroad" | "rr") = lcomponents.last() {
            lcomponents.pop();
            return Some(lcomponents.join(" "));
        }

        None
    }
 1  error[E0308]: mismatched types                                                                                                                                                          ▐
    --> rust/models/src/boundary_name.rs:282:21                                                                                                                                             ▐
     |                                                                                                                                                                                      ▐
 282 |         if let Some("r.r." | "railroad" | "rr") = lcomponents.last() {                                                                                                               ▐
     |                     ^^^^^^                        ------------------ this expression has type `std::option::Option<&&str>`                                                           ▐
     |                     |                                                                                                                                                                ▐
     |                     expected `&&str`, found `&str`                                                                                                                                   ▐
     |                                                                                                                                                                                      ▐
     = note: expected reference `&&_`                                                                                                                                                       ▐
                found reference `&'static _`                                                                                                                                                ▐

What I ended up needing to do was:

    pub fn find_railroad_name(lcomponents: &mut Vec<&str>) -> Option<String> {
        if let Some(&"r.r." | &"railroad" | &"rr") = lcomponents.last() {
            lcomponents.pop();
            return Some(lcomponents.join(" "));
        }

        None
    }

It feels a little weird to be putting referenced, static strings inside a Some() pattern match like that. Anyway, I wanted to alert to the fact that the Clippy suggestion isn't sufficient in this case. Should this be special-cased, or does this actually count as a False-Positive?

Reproducer

I tried this code:

fn main() {
    let lcomponents: Vec<&str> = "B&O R.R.".to_lowercase().split_whitespace().collect();
    if let Some(rr_name) = find_railroad_name(&mut lcomponents) {
        println!("Found: {rr_name}");
    }
}

    pub fn find_railroad_name(lcomponents: &mut Vec<&str>) -> Option<String> {
        if let Some(last) = lcomponents.last() {
            match *last {
                "r.r." | "railroad" | "rr" => {
                    lcomponents.pop();
                    return Some(lcomponents.join(" "));
                }
                _ => (),
            }
        }

        None
    }

I expected to see this happen: No warning, I think? Not sure.

Instead, this happened: Warning

Version:

rustc 1.84.0 (9fc6b4312 2025-01-07)
binary: rustc
commit-hash: 9fc6b43126469e3858e2fe86cafb4f0fd5068869
commit-date: 2025-01-07
host: aarch64-apple-darwin
release: 1.84.0
LLVM version: 19.1.5

Version


Additional Labels

No response

Metadata

Metadata

Labels

C-bugCategory: Clippy is not doing the correct thingI-suggestion-causes-errorIssue: The suggestions provided by this Lint cause an ICE/error when applied

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions