Description
This is the summary issue for the indirect_structural_match
future-compatibility warning and other related errors. The goal of this page is describe why this change was made and how you can fix
code that is affected by it. It also provides a place to ask questions or register a complaint if you feel the change should not be made. For more information on the policy around future-compatibility warnings, see our breaking change policy guidelines.
What is this lint about
Uses of a const
item in a pattern are currently supposed to not rely on whether the semantics of matching a pattern are based on "structural equality" (i.e. unfolding the value of the const
item into the pattern) or "semantic equality" (calling PartialEq::eq
). See RFC 1445 for more discussion on this point.
For example, we currently reject the following code, because it could be used to detect which of the two semantics are used for matching patterns (play):
// I am equal to anyone who shares my sum!
struct Plus(i32, i32);
impl PartialEq for Plus {
fn eq(&self, other: &Self) -> bool {
self.0 + self.1 == other.0 + other.1
}
}
impl Eq for Plus { }
const ONE_PLUS_TWO: Plus = Plus(1, 2);
fn main() {
if let ONE_PLUS_TWO = Plus(3, 0) {
println!("semantic!");
} else {
println!("structural!");
}
}
However, the code to enforce adherence to RFC 1445 missed some cases. The compiler incorrectly accepted the following variant of the above code (play):
const ONE_PLUS_TWO: & &Plus = & &Plus(1, 2);
fn main() {
if let ONE_PLUS_TWO = & &Plus(3, 0) {
println!("semantic!");
} else {
println!("structural!");
}
}
Since we have not yet decided how to resolve this problem for the long term, it is best to alert users that they are using a corner of the language that was not completely specified. (To be clear: The compiler will use either semantic or structural equality, and its choice will not introduce unsoundness; but it may yield very surprising behavior for the user, depending on how they have implemented PartialEq
.)
How to fix this warning/error
Here are three options:
1. Change const item itself
Change the const
item referenced in the pattern to use only types that derive PartialEq
and Eq
.
In our running example, that would correspond to changing the code to use derive
instead of explicit impl
:
// I am equal to anyone who shares my sum!
struct Plus(i32, i32);
impl PartialEq for Plus {
fn eq(&self, other: &Self) -> bool {
self.0 + self.1 == other.0 + other.1
}
}
impl Eq for Plus { }
becomes:
// I am no longer equal to all who share my sum!
#[derive(PartialEq, Eq)]
struct Plus(i32, i32);
Of course, in this particular example, this is a non-semantics preserving change for the program at large, since presumably the original designer wanted the previous semantics for PartialEq
. The main reason we point it out (and in fact, point it out first) is that in many cases, switching to #[derive(PartialEq, Eq)]
will be both correct and the simplest fix.
2. Change pattern to call ==
explicitly
If semantic equality is desired, change the pattern to bind the input to a variable and call the ==
operator (this may require switching from if let
to match
until let_chains are stabilized).
In our running example (adapted slightly to use match
):
match & &Plus(3, 0) {
ONE_PLUS_TWO => println!("semantic!"),
_ => println!("structural!"),
}
becomes:
match & &Plus(3, 0) {
sum if sum == ONE_PLUS_TWO => println!("semantic!"),
_ => println!("structural!"),
}
3. Change pattern to inline structural form
If structural equality is desired, inline the right-hand side of the const as an explicit pattern.
In our running example (adapted slightly to use match
):
match & &Plus(3, 0) {
ONE_PLUS_TWO => println!("semantic!"),
_ => println!("structural!"),
}
becomes:
match & &Plus(3, 0) {
& &Plus(1, 2) => println!("semantic!"),
_ => println!("structural!"),
}
When will this warning become a hard error?
At the beginning of each 6-week release cycle, the Rust compiler team will review the set of outstanding future compatibility warnings and nominate some of them for Final Comment Period. Toward the end of the cycle, we will review any comments and make a final determination whether to convert the warning into a hard error or remove it entirely.
Current status
- PR use visitor for #[structural_match] check #62339 implements the lint as warn by default (in a slightly broken fashion)
- PR downgrade indirect_structural_match lint to allow #62623 changes the lint to be allow by default to work around a bug
- PR Fully destructure constants into patterns #70743 returns the lint to warn by default
- PR ? makes lint deny by default
- PR ? makes lint a hard error.
Metadata
Metadata
Assignees
Type
Projects
Status