-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Fix code suggestion for local enum patterns in non-exhaustive matches #137783
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
//! Pattern analysis sometimes wants to print patterns as part of a user-visible | ||
//! diagnostic. | ||
//! | ||
//! Historically it did so by creating a synthetic [`thir::Pat`](rustc_middle::thir::Pat) | ||
//! Historically it did so by creating a synthetic [`thir::Pat`] | ||
//! and printing that, but doing so was making it hard to modify the THIR pattern | ||
//! representation for other purposes. | ||
//! | ||
|
@@ -12,8 +12,8 @@ | |
use std::fmt; | ||
|
||
use rustc_abi::{FieldIdx, VariantIdx}; | ||
use rustc_middle::bug; | ||
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; | ||
use rustc_middle::{bug, thir}; | ||
use rustc_span::sym; | ||
|
||
#[derive(Clone, Debug)] | ||
|
@@ -44,12 +44,33 @@ pub(crate) enum EnumInfo<'tcx> { | |
NotEnum, | ||
} | ||
|
||
fn erase_path_if_local<'tcx>( | ||
tcx: TyCtxt<'_>, | ||
adt_def: AdtDef<'tcx>, | ||
scrut: &thir::Expr<'tcx>, | ||
) -> bool { | ||
let enum_parent_def_id = tcx.parent(adt_def.did()); | ||
let scrut_parent_def_id = if let thir::ExprKind::Scope { region_scope: _, lint_level, value: _ } = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not super familiar with how lint scopes work in THIR, but this feels very un-robust: there seem to be many reasons for this expression not to be a scope. Can you not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function wants a scope expression surrounding the scrutinee, like: match v {}
^ -- scope surrounding this Then we can get the def id of the scrutinee's owner. Sorry that I can't find an approach to get the def id by not using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pretty sure a match and its scrutinee always have the same owner def_id; you should be able to use |
||
scrut.kind | ||
&& let thir::LintLevel::Explicit(hir_id) = lint_level | ||
{ | ||
Some(hir_id.owner.to_def_id()) | ||
} else { | ||
None | ||
}; | ||
if scrut_parent_def_id == Some(enum_parent_def_id) { | ||
return true; | ||
} | ||
false | ||
makai410 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
pub(crate) fn write_struct_like<'tcx>( | ||
f: &mut impl fmt::Write, | ||
tcx: TyCtxt<'_>, | ||
ty: Ty<'tcx>, | ||
enum_info: &EnumInfo<'tcx>, | ||
subpatterns: &[FieldPat], | ||
scrut: Option<&thir::Expr<'tcx>>, | ||
) -> fmt::Result { | ||
let variant_and_name = match *enum_info { | ||
EnumInfo::Enum { adt_def, variant_index } => { | ||
|
@@ -60,7 +81,18 @@ pub(crate) fn write_struct_like<'tcx>( | |
{ | ||
variant.name.to_string() | ||
} else { | ||
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) | ||
let enum_and_variant = if let Some(scrut) = scrut | ||
&& erase_path_if_local(tcx, adt_def, scrut) | ||
{ | ||
ty::print::with_forced_trimmed_paths!(format!( | ||
"{}::{}", | ||
tcx.def_path_str(adt_def.did()), | ||
variant.name | ||
)) | ||
Comment on lines
+87
to
+91
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels quite ad-hoc: the underlying issue is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea here is that if the scrutinee and the enum both have the same owner (which means they are at the same function or method), then trimming the path is ok because we just want the enum name here(I guess). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh perhaps I got what you were worrying about, cc #137845. So here the problem is that the path is totally wrong because it is a function name which should not appear. Idk if I got to the right way but I appreciate it if you're willing to point my problems out. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My worry is that this is a very special-cased fix, where the general underlying issue is "how to emit correct paths in suggestions". Maybe @estebank you would know about this? What's the correct way to get a path that can be used in a suggestion? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see... No clues at hand right now. But would be happy to be mentored to solve this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could open a thread in the T-compiler/diagnostics stream asking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the suggestion! I just opened a thread to talk about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh yeah, sorry for leaving you without a clear path forward |
||
} else { | ||
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name) | ||
}; | ||
enum_and_variant | ||
}; | ||
Some((variant, name)) | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
struct Shadowed {} | ||
|
||
fn main() { | ||
let v = Shadowed::Foo; | ||
|
||
match v { | ||
//~^ non-exhaustive patterns: `main::Shadowed::Foo` not covered [E0004] | ||
} | ||
|
||
enum Shadowed { | ||
Foo, | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
error[E0004]: non-exhaustive patterns: `main::Shadowed::Foo` not covered | ||
--> $DIR/shadowed-non-exhaustive.rs:6:11 | ||
| | ||
LL | match v { | ||
| ^ pattern `main::Shadowed::Foo` not covered | ||
| | ||
note: `main::Shadowed` defined here | ||
--> $DIR/shadowed-non-exhaustive.rs:10:10 | ||
| | ||
LL | enum Shadowed { | ||
| ^^^^^^^^ | ||
LL | Foo, | ||
| --- not covered | ||
= note: the matched value is of type `main::Shadowed` | ||
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | ||
| | ||
LL ~ match v { | ||
LL + Shadowed::Foo => todo!(), | ||
LL + } | ||
| | ||
|
||
error: aborting due to 1 previous error | ||
|
||
For more information about this error, try `rustc --explain E0004`. |
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.
Can you document what this function is meant to do?
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.
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.
Doc looks good, I would name it something like
should_trim_enum_paths
.