rust-lang / rust-lang/rust-clippy

False pattern_type_mismatch positive: suggests reference when not allowed (appears when unpacking)

Open
#9,378 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug I-false-positive
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Summary

When unpacking tuples that cannot be moved, pattern_type_mismatch is raised and comes with a suggestion that is not valid.

The example in the section below shows the full setup, but basically the following causes this error:

.take_while(|(a_item, b_item)| *a_item == *b_item)

and clippy suggests adding a reference to get |&(a_item, b_item)|. However, this is not allowed if the tuple cannot be moved and a reference cannot be taken. This issue only seems to arise when the closure argument is a tuple to be unpacked.

It is possible there exists a pattern that allows unpacking and correct pattern type matching that I just don't know. In this case, only the suggested fix needs to be updated.

See the code below for examples of what works and doesn't

Lint Name

pattern_type_mismatch

Reproducer

Playground link: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=94ea17582991bad50169a2a5e1e3fd5e

I tried this code:

#![warn(clippy::pattern_type_mismatch)]

fn test<T,I>(a: I, b: I) 
where
    I: IntoIterator<Item=T>,
    T: PartialEq,
{

    // Simple use of closures on unmovable tuples
    let res = a
        .into_iter()
        .zip(b.into_iter())
        // These two work but error in clippy
        .take_while(|(a_item, b_item)| a_item == b_item)
        .take_while(|(a_item, b_item)| *a_item == *b_item)
        // This works and passes clippy, but is less clean
        .take_while(|items| items.0 == items.1)
        // This does not compile because of moved data
        // .take_while(|&(a_item, b_item)| a_item == b_item)
        .count();

    println!("Total: {res}");
}

fn main() {
    let a = [1u32, 2, 3, 4];
    let b = [1u32, 2, 0, 4];

    test(&a,&b);
}

I saw this happen:

warning: type of pattern does not match the expression type
  --> src/main.rs:14:22
   |
14 |         .take_while(|(a_item, b_item)| a_item == b_item)
   |                      ^^^^^^^^^^^^^^^^
   |
note: the lint level is defined here
  --> src/main.rs:1:9
   |
1  | #![warn(clippy::pattern_type_mismatch)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch

warning: type of pattern does not match the expression type
  --> src/main.rs:15:22
   |
15 |         .take_while(|(a_item, b_item)| *a_item == *b_item)
   |                      ^^^^^^^^^^^^^^^^
   |
   = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch

warning: `playground` (bin "playground") generated 2 warnings

I expected to see this happen:

No errors

Version
rustc 1.63.0 (4b91a6ea7 2022-08-08)
binary: rustc
commit-hash: 4b91a6ea7258a947e59c6522cd5898e7c0a6a88f
commit-date: 2022-08-08
host: x86_64-apple-darwin
release: 1.63.0
LLVM version: 14.0.5

Also seen on 1.65 nightly
Additional Labels

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the pattern_type_mismatch lint implementation and reproduce the issue using the supplied Playground code, focusing on the tuple-unpacking closure examples. Trace how the reference suggestion is generated; done means the invalid suggestion is no longer emitted and the reproducer is covered by a regression test.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.