@@ -5,7 +5,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
55use rustc_errors:: codes:: * ;
66use rustc_errors:: { Applicability , ErrorGuaranteed , MultiSpan , struct_span_code_err} ;
77use rustc_hir:: def:: * ;
8- use rustc_hir:: def_id:: LocalDefId ;
8+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
99use rustc_hir:: { self as hir, BindingMode , ByRef , HirId , MatchSource } ;
1010use rustc_infer:: infer:: TyCtxtInferExt ;
1111use rustc_lint:: Level ;
@@ -687,12 +687,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
687687 unpeeled_pat = subpattern;
688688 }
689689
690- if let PatKind :: ExpandedConstant { def_id, .. } = unpeeled_pat. kind
691- && let DefKind :: Const = self . tcx . def_kind ( def_id)
692- && let Ok ( snippet) = self . tcx . sess . source_map ( ) . span_to_snippet ( pat. span )
693- // We filter out paths with multiple path::segments.
694- && snippet. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c == '_' )
695- {
690+ if let Some ( def_id) = is_const_pat_that_looks_like_binding ( self . tcx , unpeeled_pat) {
696691 let span = self . tcx . def_span ( def_id) ;
697692 let variable = self . tcx . item_name ( def_id) . to_string ( ) ;
698693 // When we encounter a constant as the binding name, point at the `const` definition.
@@ -1209,6 +1204,26 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
12091204 }
12101205}
12111206
1207+ /// If the given pattern is a named constant that looks like it could have been
1208+ /// intended to be a binding, returns the `DefId` of the named constant.
1209+ ///
1210+ /// Diagnostics use this to give more detailed suggestions for non-exhaustive
1211+ /// matches.
1212+ fn is_const_pat_that_looks_like_binding < ' tcx > ( tcx : TyCtxt < ' tcx > , pat : & Pat < ' tcx > ) -> Option < DefId > {
1213+ // The pattern must be a named constant, and the name that appears in
1214+ // the pattern's source text must resemble a plain identifier without any
1215+ // `::` namespace separators or other non-identifier characters.
1216+ if let PatKind :: ExpandedConstant { def_id, .. } = pat. kind
1217+ && matches ! ( tcx. def_kind( def_id) , DefKind :: Const )
1218+ && let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( pat. span )
1219+ && snippet. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c == '_' )
1220+ {
1221+ Some ( def_id)
1222+ } else {
1223+ None
1224+ }
1225+ }
1226+
12121227/// Report that a match is not exhaustive.
12131228fn report_non_exhaustive_match < ' p , ' tcx > (
12141229 cx : & PatCtxt < ' p , ' tcx > ,
@@ -1303,12 +1318,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
13031318
13041319 for & arm in arms {
13051320 let arm = & thir. arms [ arm] ;
1306- if let PatKind :: ExpandedConstant { def_id, .. } = arm. pattern . kind
1307- && !matches ! ( cx. tcx. def_kind( def_id) , DefKind :: InlineConst )
1308- && let Ok ( snippet) = cx. tcx . sess . source_map ( ) . span_to_snippet ( arm. pattern . span )
1309- // We filter out paths with multiple path::segments.
1310- && snippet. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c == '_' )
1311- {
1321+ if let Some ( def_id) = is_const_pat_that_looks_like_binding ( cx. tcx , & arm. pattern ) {
13121322 let const_name = cx. tcx . item_name ( def_id) ;
13131323 err. span_label (
13141324 arm. pattern . span ,
0 commit comments