Is it by design that assert_eq! does not deref like a function call would?

Hi friends,

I'm a bit of a Rust noob here, and I'm taking a dive into automatic dereferencing rules. While that was happening, I noticed that the assert_eq! macro doesn't do what I'd expect.

Here, I have a function that takes two references and compares them for equality:

let a = [1, 2];
let b = [1, 2];

fn assert(c: &[i32; 2], d: &[i32; 2]) {
  assert_eq!(c, d);
}

assert(&&&&a, &&b);

This works how I would expect it to based on the rules I am reading. However, this fails:

assert_eq!(&&&&a, &&b);

So, I took a look at the macro and I think I understand why, but I'm curious if it's by design. The relevant section (https://doc.rust-lang.org/src/core/macros/mod.rs.html#42-75):

macro_rules! assert_eq {
    ($left:expr, $right:expr) => ({
        match (&$left, &$right) {
            (left_val, right_val) => {
                if !(*left_val == *right_val) {
                    // The reborrows below are intentional. Without them, the stack slot for the
                    // borrow is initialized even before the values are compared, leading to a
                    // noticeable slow down.
                    panic!(r#"assertion failed: `(left == right)`
  left: `{:?}`,
 right: `{:?}`"#, &*left_val, &*right_val)
                }
            }
        }
    });
}

Would it be desirable to have assert_eq! deref, and is something like this just plain wrong?

// Same functionality but derefs bc of the function call
macro_rules! my_assert_eq {
    ($left:expr, $right:expr) => ({
          fn test<T: std::cmp::PartialEq + std::fmt::Debug>(left_val: &T, right_val: &T) {
            if !(*left_val == *right_val) {
              panic!(r#"assertion failed: `(left == right)` left: `{:?}`, right: `{:?}`"#, &*left_val, &*right_val)
            }
          }
          test($left, $right);
    });
}

With this example macro, I'm able to produce the desired functionality:

let a = [1, 2];
let b = [1, 2];

fn assert(c: &[i32; 2], d: &[i32; 2]) {
  assert_eq!(c, d);
}

my_assert_eq!(&&&&a, &&b);

Your assert function is no fair comparison because it specifies the precise types it expects while assert_eq must work generically. In particular, equality testing in Rust can even work in some cases where the left side and the right side of the == comparison are entirely different types, as long as there is a matching implementation L: PartialEq<R>. Your proposed alternative my_assert_eq macro, too, imposes the restriction of both sides needing too have the same type.

Note that is should be the case that assert_eq!(expr1, expr2) works exactly in the same cases as expr1 == expr2 does, as long as the types involved also implement Debug. Since == is way more important than assert_eq, you probably want to focus on the fact that &&&&a == &&b doesn't work and discuss ways to, perhaps, improve the Rust language in that regard, if you have any ideas how to solve these "problems".