From e4781115f2a5e50d60673d5c64d49182fc190247 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Wed, 28 Feb 2024 11:51:27 +0100 Subject: [PATCH 1/4] Improve assert_matches! documentation This new documentation tries to avoid to limit the impact of the conceptual pitfall, that the if guard relaxes the constraint, when really it tightens it. This is achieved by changing the text and examples. The previous documentation also chose a rather weird and non-representative example for the if guard, that made it needlessly complicated to understand. --- library/core/src/macros/mod.rs | 79 +++++++++++++++++++++------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d818889f36402..949b07dfb77d2 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -112,16 +112,19 @@ macro_rules! assert_ne { }; } -/// Asserts that an expression matches any of the given patterns. +/// Asserts that an expression matches the provided pattern. /// -/// Like in a `match` expression, the pattern can be optionally followed by `if` -/// and a guard expression that has access to names bound by the pattern. +/// This macro is generally preferable to `assert!(matches!(value, pattern))`, because it can print +/// the debug representation, of the actual value shape that did not meet expectation. In contrast +/// using [`assert!`] will only print that the expectation was not met, but not why. /// -/// On panic, this macro will print the value of the expression with its -/// debug representation. +/// The pattern syntax is exactly the same as found in a match arm and the [`matches!`] macro. The +/// optional if guard can be used to add additional checks that must be true for the matched value, +/// otherwise this macro will panic. /// -/// Like [`assert!`], this macro has a second form, where a custom -/// panic message can be provided. +/// On panic, this macro will print the value of the expression with its debug representation. +/// +/// Like [`assert!`], this macro has a second form, where a custom panic message can be provided. /// /// # Examples /// @@ -130,13 +133,20 @@ macro_rules! assert_ne { /// /// use std::assert_matches::assert_matches; /// -/// let a = 1u32.checked_add(2); -/// let b = 1u32.checked_sub(2); +/// let a = Some(345); +/// let b = Some(56); /// assert_matches!(a, Some(_)); -/// assert_matches!(b, None); +/// assert_matches!(b, Some(_)); +/// +/// assert_matches!(a, Some(345)); +/// assert_matches!(a, Some(345) | None); +/// +/// // assert_matches!(a, None); // panics +/// // assert_matches!(b, Some(345)); // panics +/// // assert_matches!(b, Some(345) | None); // panics /// -/// let c = Ok("abc".to_string()); -/// assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); +/// assert_matches!(a, Some(x) if x > 100); +/// // assert_matches!(a, Some(x) if x < 100); // panics /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(panic_internals)] @@ -369,21 +379,25 @@ macro_rules! debug_assert_ne { }; } -/// Asserts that an expression matches any of the given patterns. +/// Asserts that an expression matches the provided pattern. /// -/// Like in a `match` expression, the pattern can be optionally followed by `if` -/// and a guard expression that has access to names bound by the pattern. +/// This macro is generally preferable to `debug_assert!(matches!(value, pattern))`, because it can +/// print the debug representation, of the actual value shape that did not meet expectation. In +/// contrast using [`debug_assert!`] will only print that the expectation was not met, but not why. +/// +/// The pattern syntax is exactly the same as found in a match arm and the [`matches!`] macro. The +/// optional if guard can be used to add additional checks that must be true for the matched value, +/// otherwise this macro will panic. /// -/// On panic, this macro will print the value of the expression with its -/// debug representation. +/// On panic, this macro will print the value of the expression with its debug representation. /// -/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only -/// enabled in non optimized builds by default. An optimized build will not -/// execute `debug_assert_matches!` statements unless `-C debug-assertions` is -/// passed to the compiler. This makes `debug_assert_matches!` useful for -/// checks that are too expensive to be present in a release build but may be -/// helpful during development. The result of expanding `debug_assert_matches!` -/// is always type checked. +/// Like [`assert!`], this macro has a second form, where a custom panic message can be provided. +/// +/// Unlike [`assert_matches!`], `debug_assert_matches!` statements are only enabled in non optimized +/// builds by default. An optimized build will not execute `debug_assert_matches!` statements unless +/// `-C debug-assertions` is passed to the compiler. This makes `debug_assert_matches!` useful for +/// checks that are too expensive to be present in a release build but may be helpful during +/// development. The result of expanding `debug_assert_matches!` is always type checked. /// /// # Examples /// @@ -392,13 +406,20 @@ macro_rules! debug_assert_ne { /// /// use std::assert_matches::debug_assert_matches; /// -/// let a = 1u32.checked_add(2); -/// let b = 1u32.checked_sub(2); +/// let a = Some(345); +/// let b = Some(56); /// debug_assert_matches!(a, Some(_)); -/// debug_assert_matches!(b, None); +/// debug_assert_matches!(b, Some(_)); +/// +/// debug_assert_matches!(a, Some(345)); +/// debug_assert_matches!(a, Some(345) | None); +/// +/// // debug_assert_matches!(a, None); // panics +/// // debug_assert_matches!(b, Some(345)); // panics +/// // debug_assert_matches!(b, Some(345) | None); // panics /// -/// let c = Ok("abc".to_string()); -/// debug_assert_matches!(c, Ok(x) | Err(x) if x.len() < 100); +/// debug_assert_matches!(a, Some(x) if x > 100); +/// // debug_assert_matches!(a, Some(x) if x < 100); // panics /// ``` #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(assert_matches)] From d2495facb14b6e79b70d98847fd8dfd6f0023e70 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Thu, 29 Feb 2024 09:52:02 +0100 Subject: [PATCH 2/4] Drop link to matches macro and link matches macro to assert_matches. --- library/core/src/macros/mod.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 949b07dfb77d2..62ff3181ef801 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -118,7 +118,7 @@ macro_rules! assert_ne { /// the debug representation, of the actual value shape that did not meet expectation. In contrast /// using [`assert!`] will only print that the expectation was not met, but not why. /// -/// The pattern syntax is exactly the same as found in a match arm and the [`matches!`] macro. The +/// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The /// optional if guard can be used to add additional checks that must be true for the matched value, /// otherwise this macro will panic. /// @@ -385,7 +385,7 @@ macro_rules! debug_assert_ne { /// print the debug representation, of the actual value shape that did not meet expectation. In /// contrast using [`debug_assert!`] will only print that the expectation was not met, but not why. /// -/// The pattern syntax is exactly the same as found in a match arm and the [`matches!`] macro. The +/// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The /// optional if guard can be used to add additional checks that must be true for the matched value, /// otherwise this macro will panic. /// @@ -430,10 +430,15 @@ pub macro debug_assert_matches($($arg:tt)*) { } } -/// Returns whether the given expression matches any of the given patterns. +/// Returns whether the given expression matches the provided pattern. /// -/// Like in a `match` expression, the pattern can be optionally followed by `if` -/// and a guard expression that has access to names bound by the pattern. +/// The pattern syntax is exactly the same as found in a match arm. The optional if guard can be +/// used to add additional checks that must be true for the matched value, otherwise this macro will +/// return `false`. +/// +/// When testing that a value matches a pattern, it's generally preferable to use +/// [`assert_matches!`] as it will print the debug representation of the value if the assertion +/// fails. /// /// # Examples /// From d6438f526681703641610549910e9db5d1d5a392 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Sat, 2 Mar 2024 14:07:25 +0100 Subject: [PATCH 3/4] Apply review comments --- library/core/src/macros/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 62ff3181ef801..3e25418f14fe5 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -115,7 +115,7 @@ macro_rules! assert_ne { /// Asserts that an expression matches the provided pattern. /// /// This macro is generally preferable to `assert!(matches!(value, pattern))`, because it can print -/// the debug representation, of the actual value shape that did not meet expectation. In contrast +/// the debug representation, of the actual value shape that did not meet expectation. In contrast, /// using [`assert!`] will only print that the expectation was not met, but not why. /// /// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The @@ -383,7 +383,7 @@ macro_rules! debug_assert_ne { /// /// This macro is generally preferable to `debug_assert!(matches!(value, pattern))`, because it can /// print the debug representation, of the actual value shape that did not meet expectation. In -/// contrast using [`debug_assert!`] will only print that the expectation was not met, but not why. +/// contrast, using [`debug_assert!`] will only print that the expectation was not met, but not why. /// /// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The /// optional if guard can be used to add additional checks that must be true for the matched value, From c45f0a977abc021ad3454930e2728d815def4938 Mon Sep 17 00:00:00 2001 From: Lukas Bergdoll Date: Sun, 3 Mar 2024 15:30:46 +0100 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Josh Stone --- library/core/src/macros/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 3e25418f14fe5..643968c35e849 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -115,8 +115,8 @@ macro_rules! assert_ne { /// Asserts that an expression matches the provided pattern. /// /// This macro is generally preferable to `assert!(matches!(value, pattern))`, because it can print -/// the debug representation, of the actual value shape that did not meet expectation. In contrast, -/// using [`assert!`] will only print that the expectation was not met, but not why. +/// the debug representation of the actual value shape that did not meet expectations. In contrast, +/// using [`assert!`] will only print that expectations were not met, but not why. /// /// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The /// optional if guard can be used to add additional checks that must be true for the matched value, @@ -382,8 +382,8 @@ macro_rules! debug_assert_ne { /// Asserts that an expression matches the provided pattern. /// /// This macro is generally preferable to `debug_assert!(matches!(value, pattern))`, because it can -/// print the debug representation, of the actual value shape that did not meet expectation. In -/// contrast, using [`debug_assert!`] will only print that the expectation was not met, but not why. +/// print the debug representation of the actual value shape that did not meet expectations. In +/// contrast, using [`debug_assert!`] will only print that expectations were not met, but not why. /// /// The pattern syntax is exactly the same as found in a match arm and the `matches!` macro. The /// optional if guard can be used to add additional checks that must be true for the matched value,