Support if-let-guard in matches! and assert_matches!#152832
Support if-let-guard in matches! and assert_matches!#152832SpriteOvO wants to merge 1 commit intorust-lang:mainfrom
matches! and assert_matches!#152832Conversation
This comment was marked as off-topic.
This comment was marked as off-topic.
|
cc @rust-lang/libs-api |
|
r? libs |
| assert!( | ||
| matches!(Some(Some(2_i32)), Some(inner) if let Some(value) = inner && value.pow(2) == 4) | ||
| ); | ||
| assert_matches!(Some(Some(2_i32)), Some(inner) if let Some(value) = inner && value.pow(2) == 4); |
There was a problem hiding this comment.
Needs another test for assert_matches!() with a panic message.
There was a problem hiding this comment.
Oh, so looks like we can't simply use $(tt)+ to catch if-let guards because it also catches the comma and panic message.
Does this mean we have to start implementing it as a compiler built-in macro? Especially since we already have 4 arms here.
|
Nominating for discussion. It seems like this might be hard to implement (no longer just macro_rules?), so we should offer guidance on whether we want it before any further implementation delta. It seems also possible that we should add (unstable?) |
Closes #152313, and if-let-guard is stabilized in #141295 just now.
Motivations
Simplify code where
matchandlet-elseare used for assertions. For examples, see files:struct TestStruct { first: u8, second: u16, reference: &'static u16, } - const { - let Type { kind: Struct(ty), size, .. } = Type::of::<TestStruct>() else { panic!() }; - assert!(size == Some(size_of::<TestStruct>())); - assert!(!ty.non_exhaustive); - assert!(ty.fields.len() == 3); - assert!(ty.fields[0].name == "first"); - assert!(ty.fields[0].ty == TypeId::of::<u8>()); - assert!(ty.fields[0].offset == offset_of!(TestStruct, first)); - assert!(ty.fields[1].name == "second"); - assert!(ty.fields[1].ty == TypeId::of::<u16>()); - assert!(ty.fields[1].offset == offset_of!(TestStruct, second)); - assert!(ty.fields[2].name == "reference"); - assert!(ty.fields[2].ty == TypeId::of::<&'static u16>()); - assert!(ty.fields[2].offset == offset_of!(TestStruct, reference)); - } + assert_matches!( + const {Type::of::<TestStruct>() }, Type { kind: Struct(ty), size, .. } + if size == Some(size_of::<TestStruct>()) + && !ty.non_exhaustive + && ty.fields.len() == 3 + && ty.fields[0].name == "first" + && ty.fields[0].ty == TypeId::of::<u8>() + && ty.fields[0].offset == offset_of!(TestStruct, first) + && ty.fields[1].name == "second" + && ty.fields[1].ty == TypeId::of::<u16>() + && ty.fields[1].offset == offset_of!(TestStruct, second) + && ty.fields[2].name == "reference" + && ty.fields[2].ty == TypeId::of::<&'static u16>() + && ty.fields[2].offset == offset_of!(TestStruct, reference) + );Notes
At the moment, it seems we cannot fully port const-eval only operations (e.g. file https://github.com/rust-lang/rust/blob/e0cb264b814526acb82def4b5810e394a2ed294f/library/coretests/tests/mem/type_info.rs) to use
assert_matches!with if-let-guards, because of:triggers a runtime panic
rust/library/core/src/intrinsics/mod.rs
Lines 2872 to 2874 in e0cb264
triggers
error[E0015]: cannot call non-const function 'core::panicking::assert_matches_failed::<_>' in constants. (blocked by const functions can assert! but cannot assert_eq! #119826)Todo
r? theemathas
cc @rustbot ping libs-api