-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Tracking issue for indirect_structural_match
compatibility lint
#62411
Comments
non_structural_match
compatibility lintindirect_structural_match
compatibility lint
I've noticed this warning suddenly being triggered on this code using the let m = http::Method::GET;
match m {
http::Method::GET => (),
_ => ()
} There is a |
@seanmonstar is everything that is recursively teachable from that structure also a (I have been wondering if there may be subtle cases where this warning arises that are instances of there not being “turtles all the way down”) |
I noticed the warning says So while I guess technically in correct, in this case a structural match would be fine since you can't make a constant of that variant anyway. |
Hmm yes. This may be an unfortunate artifact of how this implementation is trying to detect instances of ADT's missing structural match: It traverses the structure of the type itself, which means it visits every variant of an enum type, including variants that are unused by the const item in question. I suspect we can fix this. I don't think I'm going to be able to do so before I go on leave, but I'll file a bug about it in any case. |
@seanmonstar filed as #62614 |
... and filed PR #62623 as a way to address the problem in the short-term. |
…h, r=pnkfelix Const qualification for `StructuralEq` Furthers rust-lang#62411. Resolves rust-lang#62614. The goal of this PR is to implement the logic in rust-lang#67088 on the MIR instead of the HIR. It uses the `Qualif` trait to track `StructuralPartialEq`/`StructuralEq` in the final value of a `const`. Then, if we encounter a constant during HAIR lowering whose value may not be structurally matchable, we emit the `indirect_structural_match` lint. This PR contains all the tests present in rust-lang#67088 and emits the proper warnings for the corner cases. This PR does not handle rust-lang#65466, which would require that we be [more aggressive](https://github.com/rust-lang/rust/blob/42abbd8878d3b67238f3611b0587c704ba94f39c/src/librustc_mir_build/hair/pattern/const_to_pat.rs#L126-L130) when checking matched types for `PartialEq`. I think that should be done separately. Because this works on MIR and uses dataflow, this PR should accept more cases than rust-lang#67088. Notably, the qualifs in the final value of a const are encoded cross-crate, so matching on a constant whose value is defined in another crate to be `Option::<TyWithCustomEqImpl>::None` should work. Additionally, if a `const` has branching/looping, we will only emit the warning if any possible control flow path could result in a type with a custom `PartialEq` impl ending up as the final value of a `const`. I'm not sure how rust-lang#67088 handled this. AFAIK, it's not settled that these are the semantics we actually want: it's just how the `Qualif` framework happens to work. If the cross-crate part is undesirable, it would be quite easy to change the result of `mir_const_qualif().custom_eq` to `true` before encoding it in the crate metadata. This way, other crates would have to assume that all publicly exported constants may not be safe for matching. r? @pnkfelix cc @eddyb
=== stdout === === stderr === warning: to use a constant of type `Eek` in a pattern, `Eek` must be annotated with `#[derive(PartialEq, Eq)]` --> /home/runner/work/glacier/glacier/ices/82909.rs:15:11 | 15 | &&EEK_ONE => {} | ^^^^^^^ | = note: `#[warn(indirect_structural_match)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #62411 <rust-lang/rust#62411> error[E0004]: non-exhaustive patterns: `&&&_` not covered --> /home/runner/work/glacier/glacier/ices/82909.rs:14:11 | 14 | match &&&[][..] { | ^^^^^^^^^ pattern `&&&_` not covered | = note: the matched value is of type `&&&[Eek]` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | 15 ~ &&EEK_ONE => {} 16 + &&&_ => todo!() | warning: unused variable: `other` --> /home/runner/work/glacier/glacier/ices/82909.rs:3:18 | 3 | fn eq(&self, other: &Self) -> bool { | ^^^^^ help: if this is intentional, prefix it with an underscore: `_other` | = note: `#[warn(unused_variables)]` on by default error: aborting due to previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0004`. ==============
What is the current status here? This has been a future-incompat lint for a long time now, can we move towards making it a hard error? Should we at least take a step towards that by having it show up in cargo's future-incompat reports? I am not sure if our vision for structural-match restrictions is still the same as 4 years ago though. #74446 is still unresolved. My immediate goal would be to move pattern matching away from a "fallback" logic: currently it works by "trying a valtree" and then "falling back to an opaque const with PartialEq"; such fallbacks are typically fragile and hard to reason about. What would it take to decide between "construct transparent pattern via valtree" vs "opaque pattern" up-front (and ICEing if building a valtree fails after we decided that that is the strategy we want to use)? Is it something like @oli-obk or anyone else who knows the current status here, would be great to get a summary. :) |
In fact I think I'm uncertain about what the endgame here really is. Is it the fallback plan above? But which code would that even break? With fn ptrs now having Or is the point that in case we detect custom equality, we're not just falling back to What are examples of code that we still plan to break? Maybe the breaking has nothing at all to do with valtrees or other internals. |
I laid down some of my thoughts on where we might want to go with all this over here. |
This is pretty much superseded by #120362. |
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 fixcode 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 theconst
item into the pattern) or "semantic equality" (callingPartialEq::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):
However, the code to enforce adherence to RFC 1445 missed some cases. The compiler incorrectly accepted the following variant of the above code (play):
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 derivePartialEq
andEq
.In our running example, that would correspond to changing the code to use
derive
instead of explicitimpl
:becomes:
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
==
explicitlyIf semantic equality is desired, change the pattern to bind the input to a variable and call the
==
operator (this may require switching fromif let
tomatch
until let_chains are stabilized).In our running example (adapted slightly to use
match
):becomes:
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
):becomes:
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
The text was updated successfully, but these errors were encountered: