Is it possible to write your own error messages?

Hi there, this is a bit of a weird question, but please bear with me.
I have a function, get, which is defined a bit wonkily, so I’ll try to clean it up abit with some pseudocode:

fn get<T>(&self) -> Option<Cont<T>> where Cont<T>: SomeConstraint;
Actual code
#[inline]
pub fn get<'a, T: 'static + Send>(&'a self) -> DynamicResult<<Borrowed<'a, U> as Map<(dyn Any + Send), T>>::Output>
    where
        Borrowed<'a, U>: Map<(dyn Any + Send), T, Func=for<'b> fn(&'b (dyn Any + Send)) -> &'b T>,
{
    Ok(self.unit_get::<T>()?.one()?.map(|x| {
        x.downcast_ref().unwrap()
    }))
}

This function is only available for some variants of Self, depending on the type parameter’s associated types. Could I write a special error message for the case where Cont<T>: !SomeConstraint, because the current error message conveys the technical reason why it doesn’t work, but not why it won’t work:

error[E0271]: type mismatch resolving `<lock_api::mutex::MappedMutexGuard<'_, parking_lot::raw_mutex::RawMutex, (dyn std::any::Any + std::marker::Send + 'static)> as restor::black_box::Map<(dyn std::any::Any + std::marker::Send + 'static), usize>>::Func == for<'b> fn(&'b (dyn std::any::Any + std::marker::Send + 'static)) -> &'b usize`
  --> tests\mutex.rs:47:15
   |
47 |     let y = x.get::<usize>();
   |               ^^^ types differ in mutability
   |
   = note: expected type `for<'b> fn(&'b mut (dyn std::any::Any + std::marker::Send + 'static)) -> &'b mut usize`
              found type `for<'b> fn(&'b (dyn std::any::Any + std::marker::Send + 'static)) -> &'b usize`

While I would like it to say something like the following:

error: `get<T>` and `ind<T>` functions are not defined for the `Mutex` variant of `BlackBox`
   note: You can use `.get_mut` and `.ind_mut` instead.

Essentially, I have a RefCell, Mutex, and RwLock variant for my container, and I need to map the references in the guards. I have two guards for RwLocks and RefCells, but Mutexes only provide one lock/guard, and it’s mutable, so I can’t really apply a fn(&T) -> &U function to them, therefore these functions (get and ind) are not defined, and instead force the user to use get_mut(&self) or ind_mut(&self).

Why not provide those functions, it doesn’t seem like it wouldn’t cost that much, and it would allow more flexibility when using your crate generically. Is there a limitation in parking_lot that prohibits it?

Yes, there is, MappedMutexGuard::map's function parameter is defined like so:

where F: FnOnce(&mut T) -> &mut U

Which I can use with my Map trait (Not to be confused with my MapMut trait):

impl<'a, I: 'static + Send + ?Sized, O: 'static + Send + ?Sized> Map<I, O>
for MappedMutexGuard<'a, I>
{
    type Output = MappedMutexGuard<'a, O>;
    type Func = for<'b> fn(&'b mut I) -> &'b mut O;
    fn map(self, f: Self::Func) -> MappedMutexGuard<'a, O> {
        MappedMutexGuard::map(self, f)
    }
}

But I can’t cover the case of Func's references being &T and &mut T at the same time, and I can’t redeclare the function with the same name, just changing the constraints.

Ok, I don’t think that there is a way to introduce custom errors or warnings, except if you are using macros or conditional compilation, but that probably won’t work here.

1 Like

Relatedly, when calling pin.foo(), I would personally like to see “you cannot call derefmut on this Pin instance because it dereferences to a !Unpin type” instead of “cannot call foo on a immutable receiver”.

I think we need static_assert and compile-time trait introspection for this to happen.

2 Likes