rust-lang / rust-lang/rust-clippy

`assert_is_empty` could catch every other collection in `std::collections`

Open
#17,660 3 comments 0 reactions 1 assignee View on GitHub

@saberoueslati is already working on this.

Since Sep 17, 2026.

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

Description

Summary

Of all the collections in std::collections, assert_is_empty only fires on Vec. Here is how it can fire on every other collection in std::collections.

To make it more obvious which traits are the bare minimum required on a given type, I introduce this trait to allow me to fill collections generically:

    trait ElementExists {
        const ELEMENT: Self;
    }

...and also leave comments explaining which traits are required.

All cases provided will intentionally fail the assertion, since that's the whole point of the lint. The first case in each set will be the case that the lint should fire on, to show the difference in trait bounds (as some collections have innate bounds).

Lint Name

assert_is_empty

Reproducer

In each of these, Clippy should suggest replacing the assert shown in *_normal with the assert shown in *_eq or *_matches if the type(s) in the collection meet the new trait bounds.

BTreeMap

    // T: Ord is implied by the requirements of BTreeMap
    fn btreemap_normal<T: ElementExists + Ord, U: ElementExists>() {
        let mut btreemap = BTreeMap::new();
        drop(btreemap.insert(T::ELEMENT, U::ELEMENT));
        assert!(btreemap.is_empty());
    }

    fn btreemap_eq<
        T: ElementExists + Ord + Debug, // T now needs Debug
        U: ElementExists + PartialEq + Debug, // U now needs PartialEq and Debug
    >() {
        let mut btreemap = BTreeMap::new();
        drop(btreemap.insert(T::ELEMENT, U::ELEMENT));
        assert_eq!(btreemap, BTreeMap::new());
    }

BTreeSet

    // T: Ord is implied by the requirements of BTreeSet
    fn btreeset_normal<T: ElementExists + Ord>() {
        let mut btreeset = BTreeSet::new();
        let _: bool = btreeset.insert(T::ELEMENT);
        assert!(btreeset.is_empty());
    }

    // T now needs Debug
    fn btreeset_eq<T: ElementExists + Ord + Debug>() {
        let mut btreeset = BTreeSet::new();
        let _: bool = btreeset.insert(T::ELEMENT);
        assert_eq!(btreeset, BTreeSet::new());
    }

BinaryHeap

    // T: Ord is implied by the requirements of BinaryHeap
    fn binaryheap_normal<T: ElementExists + Ord>() {
        let mut binaryheap = BinaryHeap::new();
        binaryheap.push(T::ELEMENT);
        assert!(binaryheap.is_empty());
    }

    // T now needs Debug
    fn binaryheap_eq<T: ElementExists + Ord + Debug>() {
        let mut binaryheap = BinaryHeap::new();
        binaryheap.push(T::ELEMENT);
        assert_eq!(binaryheap.as_slice(), []);
    }

HashMap

    // T: Eq + Hash is implied by the requirements of HashMap
    fn hashmap_normal<T: ElementExists + Eq + Hash, U: ElementExists>() {
        let mut hashmap = HashMap::new();
        drop(hashmap.insert(T::ELEMENT, U::ELEMENT));
        assert!(hashmap.is_empty());
    }

    fn hashmap_eq<
        T: ElementExists + Eq + Hash + Debug, // T now needs Debug
        U: ElementExists + Debug + PartialEq, // U now needs PartialEq and Debug
    >() {
        let mut hashmap = HashMap::new();
        drop(hashmap.insert(T::ELEMENT, U::ELEMENT));
        assert_eq!(hashmap, HashMap::new());
    }

HashSet

    // T: Eq + Hash is implied by the requirements of HashSet
    fn hashset_normal<T: ElementExists + Eq + Hash>() {
        let mut hashset = HashSet::new();
        let _: bool = hashset.insert(T::ELEMENT);
        assert!(hashset.is_empty());
    }

    // T now needs Debug
    fn hashset_eq<T: ElementExists + Eq + Hash + Debug>() {
        let mut hashset = HashSet::new();
        let _: bool = hashset.insert(T::ELEMENT);
        assert_eq!(hashset, HashSet::new());
    }

LinkedList

    fn linkedlist_normal<T: ElementExists>() {
        let mut linkedlist = LinkedList::new();
        linkedlist.push_front(T::ELEMENT);
        assert!(linkedlist.is_empty());
    }

    // T now needs PartialEq and Debug
    fn linkedlist_eq<T: ElementExists + PartialEq + Debug>() {
        let mut linkedlist = LinkedList::new();
        linkedlist.push_front(T::ELEMENT);
        assert_eq!(linkedlist, LinkedList::new());
    }

VecDeque

This is the only collection where we can get a more general fix by using assert_matches!, but in case that's undesirable for some reason, the stricter assert_eq! solution is also included.

    fn vecdeque_normal<T: ElementExists>() {
        let mut vecdeque = VecDeque::new();
        vecdeque.push_front(T::ELEMENT);
        assert!(vecdeque.is_empty());
    }

    // T now needs PartialEq and Debug
    fn vecdeque_eq<T: ElementExists + Debug + PartialEq>() {
        let mut vecdeque = VecDeque::new();
        vecdeque.push_front(T::ELEMENT);
        assert_eq!(vecdeque, VecDeque::new());
    }

    // T now needs Debug
    fn vecdeque_matches<T: ElementExists + Debug>() {
        let mut vecdeque = VecDeque::new();
        vecdeque.push_front(T::ELEMENT);
        assert_matches!(vecdeque.as_slices(), ([], []));
    }
Version
rustc 1.100.0-nightly (fb6531d55 2026-08-23)
binary: rustc
commit-hash: fb6531d550e0075b9eb9a51464f404805eec87d9
commit-date: 2026-08-23
host: x86_64-unknown-linux-gnu
release: 1.100.0-nightly
LLVM version: 23.1.0

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.