rust-clippy icon indicating copy to clipboard operation
rust-clippy copied to clipboard

`coerce_container_to_any` should not trigger in method chains

Open flip1995 opened this issue 4 months ago • 1 comments

Summary

This just triggered in the Rust repo and I think that's a false positive.

As I think this is significant, I moved this lint to nursery in the Clippy->Rust sync.

Added in #14812 cc @Ralith @llogiq

Lint Name

coerce_container_to_any

Reproducer

I tried this code:

let stepcache: &mut HashMap<S, <S as Step>::Output> = cache // RefMut<'_, HashMap<TypeId, …>>
    .entry(key: type_id) // Entry<'_, TypeId, Box<dyn Any + 'static>>
    .or_insert_with(default: || Box::<HashMap<S, S::Output>>::default()) // &mut Box<dyn Any + 'static>
    .downcast_mut::<HashMap<S, S::Output>>() // Option<&mut HashMap<S, <S as Step>::Output>>
    .expect(msg: "invalid type mapped");

I saw this happen:

warning: coercing `&mut std::boxed::Box<dyn std::any::Any>` to `&dyn Any`
   --> src/bootstrap/src/utils/cache.rs:231:25
    |
231 |           let stepcache = cache
    |  _________________________^
232 | |             .entry(type_id)
233 | |             .or_insert_with(|| Box::<HashMap<S, S::Output>>::default())
    | |_______________________________________________________________________^
    |
    = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#coerce_container_to_any
    = note: `-D clippy::coerce-container-to-any` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::coerce_container_to_any)]`
help: consider dereferencing
    |
231 |         let stepcache = &**cache
    |                         +++

I expected to see this happen: no lint. In a method chain the actual type is &mut Box<dyn Any>. Calling downcast_mut on that type will go through the Deref implementations and then call downcast_mut on the actual dyn Any. The Box is not converted into a &dyn Any reference.

Also the suggestion is wrong, as adding the derefs like shown in the suggestion, it would apply to the whole method chain, not to the offending code only. This is the correct "fix":

let stepcache: &mut HashMap<S, <S as Step>::Output> =
    (**cache.entry(key: type_id).or_insert_with(default: || Box::<HashMap<S, S::Output>>::default())) // dyn Any + 'static
        .downcast_mut::<HashMap<S, S::Output>>() // Option<&mut HashMap<S, <S as Step>::Output>>
        .expect(msg: "invalid type mapped");

Version

Current master: 4ef75291b5dd6739212f1f61666d19d4e086690d

Additional Labels

No response

flip1995 avatar Jun 13 '25 10:06 flip1995