Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve custom message format in assert_eq macro #94016

Closed
wants to merge 10 commits into from
16 changes: 12 additions & 4 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ macro_rules! assert_eq {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = $crate::panicking::AssertKind::Eq;
let left_name = stringify!($left);
let right_name = stringify!($right);
// 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.
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, $crate::option::Option::None);
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, left_name, right_name, $crate::option::Option::None);
}
}
}
Expand All @@ -52,10 +54,12 @@ macro_rules! assert_eq {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = $crate::panicking::AssertKind::Eq;
let left_name = stringify!($left);
let right_name = stringify!($right);
// 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.
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, $crate::option::Option::Some($crate::format_args!($($arg)+)));
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, left_name, right_name, $crate::option::Option::Some($crate::format_args!($($arg)+)));
}
}
}
Expand Down Expand Up @@ -89,10 +93,12 @@ macro_rules! assert_ne {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = $crate::panicking::AssertKind::Ne;
let left_name = stringify!($left);
let right_name = stringify!($right);
// 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.
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, $crate::option::Option::None);
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, left_name, right_name, $crate::option::Option::None);
}
}
}
Expand All @@ -102,10 +108,12 @@ macro_rules! assert_ne {
(left_val, right_val) => {
if *left_val == *right_val {
let kind = $crate::panicking::AssertKind::Ne;
let left_name = stringify!($left);
let right_name = stringify!($right);
// 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.
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, $crate::option::Option::Some($crate::format_args!($($arg)+)));
$crate::panicking::assert_failed(kind, &*left_val, &*right_val, left_name, right_name, $crate::option::Option::Some($crate::format_args!($($arg)+)));
}
}
}
Expand Down
34 changes: 23 additions & 11 deletions library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,15 +171,17 @@ pub enum AssertKind {
#[doc(hidden)]
pub fn assert_failed<T, U>(
kind: AssertKind,
left: &T,
right: &U,
left_val: &T,
right_val: &U,
left_name: &'static str,
right_name: &'static str,
args: Option<fmt::Arguments<'_>>,
) -> !
where
T: fmt::Debug + ?Sized,
U: fmt::Debug + ?Sized,
{
assert_failed_inner(kind, &left, &right, args)
assert_failed_inner(kind, &left_val, &right_val, &left_name, &right_name, args)
}

/// Internal function for `assert_match!`
Expand All @@ -198,15 +200,24 @@ pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
fmt::Display::fmt(self.0, f)
}
}
assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
assert_failed_inner(
AssertKind::Match,
&left,
&Pattern(right),
stringify!(&left),
stringify!(&right),
args,
);
}

/// Non-generic version of the above functions, to avoid code bloat.
#[track_caller]
fn assert_failed_inner(
kind: AssertKind,
left: &dyn fmt::Debug,
right: &dyn fmt::Debug,
left_val: &dyn fmt::Debug,
right_val: &dyn fmt::Debug,
left_name: &'static str,
right_name: &'static str,
args: Option<fmt::Arguments<'_>>,
) -> ! {
let op = match kind {
Expand All @@ -217,16 +228,17 @@ fn assert_failed_inner(

match args {
Some(args) => panic!(
r#"assertion failed: `(left {} right)`
r#"assertion failed: `({left_name} {} {right_name})`
left: `{:?}`,
Comment on lines +231 to 232
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The at: here shouldn't be followed by a formatting specifier that we print, this is meant to be where the location goes, which is printed by the caller of assert_failed_inner, so we should just finish the output here. The args that you're printing here is the error message and should come before left.

Suggested change
r#"assertion failed: `({left_name} {} {right_name})`
left: `{:?}`,
r#"assertion failed: `({left_name} {op} {right_name})`
Error: {args},
left: `{left_val:?}`,

right: `{:?}`: {}"#,
op, left, right, args
right: `{:?}`:
at: {}"#,
op, left_val, right_val, args
),
Comment on lines +233 to 236
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
right: `{:?}`:
at: {}"#,
op, left_val, right_val, args
),
right: `{right_val:?}`,
at: "#),

None => panic!(
r#"assertion failed: `(left {} right)`
r#"assertion failed: `({left_name} {} {right_name})`
left: `{:?}`,
right: `{:?}`"#,
Comment on lines +238 to 240
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
r#"assertion failed: `({left_name} {} {right_name})`
left: `{:?}`,
right: `{:?}`"#,
r#"assertion failed: `({left_name} {op} {right_name})`
left: `{left_val:?}`,
right: `{right_val:?}`,
at: "#),

op, left, right,
op, left_val, right_val,
),
}
}