method resolution problem related to Box<dyn Trait>

880dd4e
Opened by Catherine at 2024-12-21 05:10:37

To reproduce:

use std::ops::{Deref, DerefMut};
use std::borrow::BorrowMut;

pub enum Managed<'a, T: 'a + ?Sized> {
    Borrowed(&'a mut T),
    Owned(Box<BorrowMut<T>>)
}

impl<'a, T: 'a + ?Sized> Deref for Managed<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        match self {
            &Managed::Borrowed(ref value) => value,
            &Managed::Owned(ref value) => value.borrow()
        }
    }
}

impl<'a, T: 'a + ?Sized> DerefMut for Managed<'a, T> {
    fn deref_mut(&mut self) -> &mut T {
        match self {
            &mut Managed::Borrowed(ref mut value) => value,
            &mut Managed::Owned(ref mut value) => value.borrow_mut()
        }
    }
}

If you comment the impl DerefMut, everything compiles. If you uncomment it:

error[E0277]: the trait bound `Box<std::borrow::BorrowMut<T> + 'static>: std::borrow::Borrow<T>` is not satisfied
  --> <anon>:24:57
   |
24 |             &mut Managed::Owned(ref mut value) => value.borrow_mut()
   |                                                         ^^^^^^^^^^ trait `Box<std::borrow::BorrowMut<T> + 'static>: std::borrow::Borrow<T>` not satisfied
   |
   = help: the following implementations were found:
   = help:   <Box<T> as std::borrow::Borrow<T>>

which seems clearly nonsensical.

Changing value.borrow_mut() to (**value).borrow_mut() fixes it.

  1. In addition, doing use std::borrow::Borrow; breaks the earlier Deref impl, which is even weirder.

    talchas at 2016-12-17 03:50:45

  2. Simplified the test case:

    use std::ops::Deref;
    use std::borrow::Borrow;
    
    struct A(Box<Borrow<u32>>);
    
    impl Deref for A {
        type Target = u32;
    
        fn deref(&self) -> &u32 {
            self.0.borrow()
        }
    }
    
    fn main() {}
    

    Error:

    rustc 1.15.0-nightly (71c06a56a 2016-12-18)
    error[E0277]: the trait bound `Box<std::borrow::Borrow<u32>>: std::borrow::Borrow<u32>` is not satisfied
      --> <anon>:10:16
       |
    10 |         self.0.borrow()
       |                ^^^^^^ the trait `std::borrow::Borrow<u32>` is not implemented for `Box<std::borrow::Borrow<u32>>`
       |
       = help: the following implementations were found:
       = help:   <Box<T> as std::borrow::Borrow<T>>
    
    error: aborting due to previous error
    

    Mark Rousskov at 2016-12-21 18:52:31

  3. Triage: this still happens today: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=262957a6d4b0b3172ffa8580cb7cb995

    jyn at 2021-07-07 04:13:55