-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Fix replace-if-let-with-match generates non-exhausive match #18797
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be more happy with some approach based on the analysis on the usefulness of the pattern (didn't check if something like that is possible), but this is good enough for now.
crates/ide-assists/src/utils.rs
Outdated
.pat() | ||
.map_or(true, |pat| check_pat_variant_nested_or_literal_with_depth(&pat, depth)), | ||
ast::Pat::TuplePat(pat) => { | ||
pat.fields().any(|pat| check_pat_variant_nested_or_literal_with_depth(&pat, depth)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pat.fields().any(|pat| check_pat_variant_nested_or_literal_with_depth(&pat, depth)) | |
pat.fields().any(|pat| check_pat_variant_nested_or_literal_with_depth(&pat, depth + 1)) |
Should be depth + 1
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think nesting tuple pattern is fine if it does not contain literal patterns or tuple struct patterns or else.
let bar: Result<(i32, i32, Option<i32>), ()> = Ok((1, 2, Some(3)));
if let Ok((first, second, third)) = bar {} // fine
if let Ok((1, second, third)) = bar {} // bad
if let Ok((first, second, Some(third))) = bar {} // bad
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then why the others (e.g. OrPat
) have a depth limit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point, I must have missed it. Just fixed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also in TupleStructPat
, and if you're going to not use depth
, why not just remove it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt about TupleStructPat
, it should not be nested.
let bar: Result<Option<i32>, ()> = Ok(Some(1));
if let Ok(Some(a)) = bar {} // bad
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah so this is the reason - then RecordPat
should also be depth + 1
(Enum::Variant {}
) - and perhaps also rename depth
to something more informative, e.g. depth_after_refutable
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair. You remind me that I forgot to consider record in enum Enum::Variant {}
at all. My current test cases only covered structs MyStruct { a, b }
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I also covered cases like MyStruct(i32, i32)
crates/ide-assists/src/utils.rs
Outdated
ast::Pat::RecordPat(pat) => pat.record_pat_field_list().map_or(true, |pat| { | ||
pat.fields().any(|pat| { | ||
pat.pat() | ||
.map_or(true, |pat| check_pat_variant_nested_or_literal_with_depth(&pat, depth)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here too depth + 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar reason to TuplePat
@@ -728,6 +728,363 @@ fn foo(x: Result<i32, ()>) { | |||
); | |||
} | |||
|
|||
#[test] | |||
fn test_if_let_with_match_variant_nested_or_literal() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test can benefit from a split to several tests, but I'll leave that to you.
Updated. Thanks for your time reviewing this and happy new year! |
@rustbot review |
Do we talk about minicore in our dev guide? Probably not in which case we absolutely should |
I think thats something @Nadrieril specifically tried to enable with the librarification of the exhaustiveness checking code in rustc (that we now use). Please correct me if I am wrong :) |
Indeed using the exhaustiveness checker should be possible here. For this case, I'd expect we do something like: let |
Seems |
I'm not an expert in rust analyzer but after some attempts I feel there might be a lot of work to be done before the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I think this is enough for now.
Why
Closes: #8690 and #10583
Continuation of #10491. r? @Veykril if you don't mind?
The reason why the original author were unable to reproduce the first case in #8690 might be because of misuses of
minicore
, which creates an error in the types and make it fallback to the wildcard. Maybe we should give more information aboutminicore
in the docs?I extended the patterns marked as
FIXME
in #10491, while also covering the cases involving literals.What
replace_if_let_with_match
make_else_arm