Impl of `Debug` is not general enough ERROR

Hello world,

I've got the following error trying implementing debug:

'Debugwould have to be implemented for the typefor<'r> fn(&'r T)but is actually implemented for the typefn(&'0 T)

part of Code where the compiler trips

#[derive(Debug)]   ..<-- Here
#[derive(clone)]
//use std::fmt::Debug;
pub struct Delegate<T> (fn(Data: &T)) ; //for<'r> fn(&'r T)  ????

impl <T> Default for Delegate<T>
{
    fn default() -> Self { Self{ 0:| Tea| {}}}
}

impl<T> Delegate< T> 
{
    pub fn Invoke (&self,myself:&T)
        { 
            (self.0)(myself)  // for sending &self or $sender or other &data
        }
    
    pub fn Set (&mut self,del:fn(Data:&T)) 
        {   
            self.0=del
        }
}

Got something to do with (hidden) lifetimes?
Someone knows a solution for this

Regards,

Remco

The type fn(Data: &T) is a shorthand for a type involving a higher-ranked lifetime, namely for<'a> fn(&'a T). This type is not a type of the form fn(A) for some fixed type A, and hence it doesn’t match the Debug implementation for single-argument function pointers in the standard library.

Unfortunately there is an infinite number of such types to consider and no generic way to create trait implementations for all of them at once, currently, so the standard library just doesn’t implement Debug (or other traits implemented by fn pointers like Eq, Ord, Hash) for any of these higher-ranked function pointer types.

In order to implement Debug yourself for your type (which is a good idea anyways in this case because even if derive(Debug) would work, it would only generate an implementation impl<T> Debug for Delegate<T> where T: Debug, whereas for debug-printing a function pointer, you don’t need any additional constraints like T: Debug on the argument types), let me get help from my IDE (rust-analyzer) which offers an Option to generate the code that derive(Debug) would’ve created in order for me to be able to change it:

use std::fmt;

impl<T: fmt::Debug> fmt::Debug for Delegate<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("Delegate").field(&self.0).finish()
    }
}
error: implementation of `Debug` is not general enough
  --> src/main.rs:13:41
   |
13 |         f.debug_tuple("Delegate").field(&self.0).finish()
   |                                         ^^^^^^^ implementation of `Debug` is not general enough
   |
   = note: `Debug` would have to be implemented for the type `for<'r> fn(&'r T)`
   = note: ...but `Debug` is actually implemented for the type `fn(&'0 T)`, for some specific lifetime `'0`

Now we can change it to not have a T: Debug bound and add some conversion of fn(&T) to fn(&'a T) for some concrete lifetime 'a. I cannot use 'static here (because T might not support &'static T references), so let me use the lifetime of the &self argument instead.

impl<T> fmt::Debug for Delegate<T> {
    fn fmt<'a>(&'a self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("Delegate").field(&self.0 as &fn(&'a T)).finish()
    }
}

This compiles now :tada:


Edit: Seems like I’ve run into a compiler bug with this Debug implementation:

5 Likes

Tnx for the fast reply,

it compiles now (if i dont use dbg! or {:?})

mm, weird :thinking:

Remco

Using &(self.0 as fn(&'a T)) seems to get rid of the error, i.e.:

impl<T> fmt::Debug for Delegate<T> {
    fn fmt<'a>(&'a self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("Delegate").field(&(self.0 as fn(&'a T))).finish()
    }
}

Oke thats great steff. going to try it right now.
:+1:t4:

Remco

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.