Tracking issue for rust-lang/rfcs#1445.
Implementation steps:
#[structural_match]#[derive(Eq)] add #[structural_match] attribute#[structural_match] attribute to something with impl items (e.g. a Structural trait)Why #[derive(Eq)] and not #[derive(PartialEq)]? I see this was brought up in the RFC thread but I didn't really see any reasons given.
See the PR #32199
@durka
Why #[derive(Eq)] and not #[derive(PartialEq)]? I see this was brought up in the RFC thread but I didn't really see any reasons given.
The primary reason is that types which only implement PartialEq are not really compatible with a "structural" interpretation. For example, imagine you have a match that tests against the floating point value NaN -- should this match, or not? Consider that NaN != NaN (and hence floating point types are not Eq). Currently, we sidestep this by disallowing a constant of NaN, but we won't be able to do that in the future. And there are other weird examples. Consider 0 vs -0 -- these are distinct values (different bitpatterns) and yet they compare equal. So should match foo { 0 => ... } trigger if foo is -0? Today, it does, but that is a special case for floating point values, and we don't afford user-defined types the same courtesy (that is, we use a strict structural match for user-defined types).
If we wind up adopting a "semantic" interpretation, then we could consider loosening to PartialEq.
Nominating for status update.
@nikomatsakis status update?
@brson this is basically implemented, except that I don't think I did anything clever for the exhaustiveness check. I updated the check marks. The semantics are still (in my mind) basically a kind of temporary hack.
Triage: @nikomatsakis any movement here?
Came here via #62339/#62411/#62614
use std::rc::Rc;
use std::error::Error;
const OK: Result<(), Rc<dyn Error>> = Ok(());
fn main() {
let is_ok = match OK {
OK => true,
_ => false,
};
}
On the current nightly this complains about not being able to structurally match Rc. I'm never doing that. I feel like this code should just work (as it does on stable)?
What is still left to be done for this issue?
What is still left to be done for this issue?
One original goal of RFC 1445 is to address the weakened abstraction boundary. But looks like it doesn't consider the leak through error messages.
mod state {
use std::borrow::Cow;
#[derive(PartialEq, Eq)]
pub struct State(Cow<'static, str>);
impl State {
pub fn new(s: &'static str) -> Self {
State(Cow::Borrowed(s))
}
}
pub const COLD: State = State(Cow::Borrowed("cold"));
}
fn main() {
let s = state::State::new("hot");
match s {
state::COLD => (),
_ => (),
}
}
The error message:
error: to use a constant of type
std::borrow::Cowin a pattern,std::borrow::Cowmust be annotated with#[derive(PartialEq, Eq)]
exposes the fact that std::borrow::Cow is used under the hood, which should be mere implementation detail that doesn't concern the user. Diagnostically it is also confusing.
CTFE forbids comparing pointers for equality, since two pointers being unequal may arbitrarily change to the two pointers being equal depending on various factors (e.g. different constants sharing the same memory or not depending on whether they were instantiated in the same crate).
Should we thus also exclude raw pointers from #[structural_match]?
Most helpful comment
One original goal of RFC 1445 is to address the weakened abstraction boundary. But looks like it doesn't consider the leak through error messages.
The error message:
exposes the fact that
std::borrow::Cowis used under the hood, which should be mere implementation detail that doesn't concern the user. Diagnostically it is also confusing.