Skip to content

Commit 1523291

Browse files
committed
erase local enum paths in non-exhaustive match suggestions
1 parent 00f2459 commit 1523291

File tree

5 files changed

+86
-8
lines changed

5 files changed

+86
-8
lines changed

compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
538538
self.error = Err(report_non_exhaustive_match(
539539
&cx,
540540
self.thir,
541-
scrut.ty,
542-
scrut.span,
541+
scrut,
543542
witnesses,
544543
arms,
545544
braces_span,
@@ -1205,12 +1204,13 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
12051204
fn report_non_exhaustive_match<'p, 'tcx>(
12061205
cx: &PatCtxt<'p, 'tcx>,
12071206
thir: &Thir<'tcx>,
1208-
scrut_ty: Ty<'tcx>,
1209-
sp: Span,
1207+
scrut: &Expr<'tcx>,
12101208
witnesses: Vec<WitnessPat<'p, 'tcx>>,
12111209
arms: &[ArmId],
12121210
braces_span: Option<Span>,
12131211
) -> ErrorGuaranteed {
1212+
let scrut_ty = scrut.ty;
1213+
let sp = scrut.span;
12141214
let is_empty_match = arms.is_empty();
12151215
let non_empty_enum = match scrut_ty.kind() {
12161216
ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
@@ -1323,7 +1323,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
13231323
let suggested_arm = if suggest_the_witnesses {
13241324
let pattern = witnesses
13251325
.iter()
1326-
.map(|witness| cx.print_witness_pat(witness))
1326+
.map(|witness| cx.print_witness_pat_with_scrut(witness, Some(scrut)))
13271327
.collect::<Vec<String>>()
13281328
.join(" | ");
13291329
if witnesses.iter().all(|p| p.is_never_pattern()) && cx.tcx.features().never_patterns() {

compiler/rustc_pattern_analysis/src/rustc.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -805,10 +805,18 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
805805
}
806806
}
807807

808+
pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
809+
self.print_witness_pat_with_scrut(pat, None)
810+
}
811+
808812
/// Prints a [`WitnessPat`] to an owned string, for diagnostic purposes.
809813
///
810814
/// This panics for patterns that don't appear in diagnostics, like float ranges.
811-
pub fn print_witness_pat(&self, pat: &WitnessPat<'p, 'tcx>) -> String {
815+
pub fn print_witness_pat_with_scrut(
816+
&self,
817+
pat: &WitnessPat<'p, 'tcx>,
818+
scrut: Option<&thir::Expr<'tcx>>,
819+
) -> String {
812820
let cx = self;
813821
let print = |p| cx.print_witness_pat(p);
814822
match pat.ctor() {
@@ -847,6 +855,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
847855
pat.ty().inner(),
848856
&enum_info,
849857
&subpatterns,
858+
scrut,
850859
)
851860
.unwrap();
852861
s

compiler/rustc_pattern_analysis/src/rustc/print.rs

+34-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
use std::fmt;
1313

1414
use rustc_abi::{FieldIdx, VariantIdx};
15-
use rustc_middle::bug;
1615
use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
16+
use rustc_middle::{bug, thir};
1717
use rustc_span::sym;
1818

1919
#[derive(Clone, Debug)]
@@ -44,12 +44,33 @@ pub(crate) enum EnumInfo<'tcx> {
4444
NotEnum,
4545
}
4646

47+
fn erase_path_if_local<'tcx>(
48+
tcx: TyCtxt<'_>,
49+
adt_def: AdtDef<'tcx>,
50+
scrut: &thir::Expr<'tcx>,
51+
) -> bool {
52+
let enum_parent_def_id = tcx.parent(adt_def.did());
53+
let scrut_parent_def_id = if let thir::ExprKind::Scope { region_scope: _, lint_level, value: _ } =
54+
scrut.kind
55+
&& let thir::LintLevel::Explicit(hir_id) = lint_level
56+
{
57+
Some(hir_id.owner.to_def_id())
58+
} else {
59+
None
60+
};
61+
if scrut_parent_def_id == Some(enum_parent_def_id) {
62+
return true;
63+
}
64+
false
65+
}
66+
4767
pub(crate) fn write_struct_like<'tcx>(
4868
f: &mut impl fmt::Write,
4969
tcx: TyCtxt<'_>,
5070
ty: Ty<'tcx>,
5171
enum_info: &EnumInfo<'tcx>,
5272
subpatterns: &[FieldPat],
73+
scrut: Option<&thir::Expr<'tcx>>,
5374
) -> fmt::Result {
5475
let variant_and_name = match *enum_info {
5576
EnumInfo::Enum { adt_def, variant_index } => {
@@ -60,7 +81,18 @@ pub(crate) fn write_struct_like<'tcx>(
6081
{
6182
variant.name.to_string()
6283
} else {
63-
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
84+
let enum_and_variant = if let Some(scrut) = scrut
85+
&& erase_path_if_local(tcx, adt_def, scrut)
86+
{
87+
ty::print::with_forced_trimmed_paths!(format!(
88+
"{}::{}",
89+
tcx.def_path_str(adt_def.did()),
90+
variant.name
91+
))
92+
} else {
93+
format!("{}::{}", tcx.def_path_str(adt_def.did()), variant.name)
94+
};
95+
enum_and_variant
6496
};
6597
Some((variant, name))
6698
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
struct Shadowed {}
2+
3+
fn main() {
4+
let v = Shadowed::Foo;
5+
6+
match v {
7+
//~^ non-exhaustive patterns: `main::Shadowed::Foo` not covered [E0004]
8+
}
9+
10+
enum Shadowed {
11+
Foo,
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0004]: non-exhaustive patterns: `main::Shadowed::Foo` not covered
2+
--> $DIR/shadowed-non-exhaustive.rs:6:11
3+
|
4+
LL | match v {
5+
| ^ pattern `main::Shadowed::Foo` not covered
6+
|
7+
note: `main::Shadowed` defined here
8+
--> $DIR/shadowed-non-exhaustive.rs:10:10
9+
|
10+
LL | enum Shadowed {
11+
| ^^^^^^^^
12+
LL | Foo,
13+
| --- not covered
14+
= note: the matched value is of type `main::Shadowed`
15+
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
16+
|
17+
LL ~ match v {
18+
LL + Shadowed::Foo => todo!(),
19+
LL + }
20+
|
21+
22+
error: aborting due to 1 previous error
23+
24+
For more information about this error, try `rustc --explain E0004`.

0 commit comments

Comments
 (0)