-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Add assert_matches macro. #82770
Add assert_matches macro. #82770
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
I don't understand this point -- the user's pattern might not consume anything, and I think the failure case could use assert_matches!(borrowed.field, Some(_)); |
@cuviper Yeah the issue is a bit more subtle: let a = Some("asdf".to_string());
assert_matches!(a, Some(_));
dbg!(a); // OK, `a` still exists. let a = Some("asdf".to_string());
assert_matches!(a, Some(_x));
dbg!(a); // Error, `a` was consumed by the pattern. let a = Some("asdf".to_string());
assert_matches!(a, Some(ref _x));
dbg!(a); // OK, `a` still exists. It could be a little surprising, but I think it makes sense. |
This comment has been minimized.
This comment has been minimized.
If the user's pattern consumes, that's at least something they can fix. I was thinking of cases more like this: #![feature(assert_matches)]
fn main() {
let pair = (42, Some("asdf".to_string()));
assert_matches!(pair.1, Some(_));
dbg!(&pair); // OK, `pair` is still complete.
let ref_pair = &pair;
assert_matches!(ref_pair.1, Some(_));
// error[E0507]: cannot move out of `ref_pair.1` which is behind a shared reference
// --> src/main.rs:9:21
// |
// 9 | assert_matches!(ref_pair.1, Some(_));
// | ----------------^^^^^^^^^^-----------
// | |
// | data moved here
// | move occurs because `left_val` has type `Option<String>`, which does not implement the `Copy` trait
// |
} In the first case, the failure path would consume the option, but that's fine since it diverges. In the second case, it's not possible to consume it at all. But it will work if the failed pattern is |
@cuviper Ah, right. Thanks. Updated. |
When you file a tracking issue, I think it should take this TODO item from #62633:
|
@bors r+ |
📌 Commit f223aff has been approved by |
Forgot the tracking issue. @bors r=joshtriplett |
📌 Commit 80fcdef has been approved by |
Add assert_matches macro. This adds `assert_matches!(expression, pattern)`. Unlike the other asserts, this one ~~consumes the expression~~ may consume the expression, to be able to match the pattern. (It could add a `&` implicitly, but that's noticable in the pattern, and will make a consuming guard impossible.) See rust-lang#62633 (comment) This re-uses the same `left: .. right: ..` output as the `assert_eq` and `assert_ne` macros, but with the pattern as the right part: assert_eq: ``` assertion failed: `(left == right)` left: `Some("asdf")`, right: `None` ``` assert_matches: ``` assertion failed: `(left matches right)` left: `Ok("asdf")`, right: `Err(_)` ``` cc `@cuviper`
Add assert_matches macro. This adds `assert_matches!(expression, pattern)`. Unlike the other asserts, this one ~~consumes the expression~~ may consume the expression, to be able to match the pattern. (It could add a `&` implicitly, but that's noticable in the pattern, and will make a consuming guard impossible.) See rust-lang#62633 (comment) This re-uses the same `left: .. right: ..` output as the `assert_eq` and `assert_ne` macros, but with the pattern as the right part: assert_eq: ``` assertion failed: `(left == right)` left: `Some("asdf")`, right: `None` ``` assert_matches: ``` assertion failed: `(left matches right)` left: `Ok("asdf")`, right: `Err(_)` ``` cc ``@cuviper``
Rollup of 10 pull requests Successful merges: - rust-lang#80723 (Implement NOOP_METHOD_CALL lint) - rust-lang#80763 (resolve: Reduce scope of `pub_use_of_private_extern_crate` deprecation lint) - rust-lang#81136 (Improved IO Bytes Size Hint) - rust-lang#81939 (Add suggestion `.collect()` for iterators in iterators) - rust-lang#82289 (Fix underflow in specialized ZipImpl::size_hint) - rust-lang#82728 (Avoid unnecessary Vec construction in BufReader) - rust-lang#82764 (Add {BTreeMap,HashMap}::try_insert) - rust-lang#82770 (Add assert_matches macro.) - rust-lang#82773 (Add diagnostic item to `Default` trait) - rust-lang#82787 (Remove unused code from main.js) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
FYI, this broke a few places in Fuchsia where we were using
Adding the explicit import fixes the error, but causes an unused import lint (which definitely seems like a bug, albeit pre-existing). |
@tmandry Interesting. Do you also get such errors for The Re-exporting |
I don't recall seeing any of these, but the explanation could be that |
It’s unfortunate that the compiler does not resolve this ambiguity automatically (favoring the explicit |
If we are adding new assert methods, worth questioning if we want {:#?} for printing out the assertion failure so that it's nicely formatted? |
If it's all on one line it's hard to post-process it back to multiline, but the other way is pretty easy. Then if we have assertions with many lines we could in the cli output hide identical lines (but a little context is always nice). All possible if we include the '#'. |
This adds
assert_matches!(expression, pattern)
.Unlike the other asserts, this one
consumes the expressionmay consume the expression, to be able to match the pattern. (It could add a&
implicitly, but that's noticable in the pattern, and will make a consuming guard impossible.)See #62633 (comment)
This re-uses the same
left: .. right: ..
output as theassert_eq
andassert_ne
macros, but with the pattern as the right part:assert_eq:
assert_matches:
cc @cuviper