@@ -8,7 +8,7 @@ use rustc_index::{Idx, IndexVec};
88use rustc_middle:: middle:: stability:: EvalResult ;
99use rustc_middle:: mir:: interpret:: Scalar ;
1010use rustc_middle:: mir:: { self , Const } ;
11- use rustc_middle:: thir:: { FieldPat , Pat , PatKind , PatRange , PatRangeBoundary } ;
11+ use rustc_middle:: thir:: { self , FieldPat , Pat , PatKind , PatRange , PatRangeBoundary } ;
1212use rustc_middle:: ty:: layout:: IntegerExt ;
1313use rustc_middle:: ty:: { self , FieldDef , OpaqueTypeKey , Ty , TyCtxt , TypeVisitableExt , VariantDef } ;
1414use rustc_session:: lint;
@@ -900,6 +900,70 @@ impl<'p, 'tcx: 'p> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
900900 let span = self . whole_match_span . unwrap_or ( self . scrut_span ) ;
901901 Err ( self . tcx . dcx ( ) . span_err ( span, "reached pattern complexity limit" ) )
902902 }
903+
904+ fn lint_non_contiguous_range_endpoints (
905+ & self ,
906+ pat : & crate :: pat:: DeconstructedPat < Self > ,
907+ gap : IntRange ,
908+ gapped_with : & [ & crate :: pat:: DeconstructedPat < Self > ] ,
909+ ) {
910+ let Some ( & thir_pat) = pat. data ( ) else { return } ;
911+ let thir:: PatKind :: Range ( range) = & thir_pat. kind else { return } ;
912+ // Only lint when the left range is an exclusive range.
913+ if range. end != rustc_hir:: RangeEnd :: Excluded {
914+ return ;
915+ }
916+ // `pat` is an exclusive range like `lo..gap`. `gapped_with` contains ranges that start with
917+ // `gap+1`.
918+ let suggested_range: thir:: Pat < ' _ > = {
919+ // Suggest `lo..=gap` instead.
920+ let mut suggested_range = thir_pat. clone ( ) ;
921+ let thir:: PatKind :: Range ( range) = & mut suggested_range. kind else { unreachable ! ( ) } ;
922+ range. end = rustc_hir:: RangeEnd :: Included ;
923+ suggested_range
924+ } ;
925+ let gap_as_pat = self . hoist_pat_range ( & gap, * pat. ty ( ) ) ;
926+ if gapped_with. is_empty ( ) {
927+ // If `gapped_with` is empty, `gap == T::MAX`.
928+ self . tcx . emit_node_span_lint (
929+ lint:: builtin:: NON_CONTIGUOUS_RANGE_ENDPOINTS ,
930+ self . match_lint_level ,
931+ thir_pat. span ,
932+ errors:: ExclusiveRangeMissingMax {
933+ // Point at this range.
934+ first_range : thir_pat. span ,
935+ // That's the gap that isn't covered.
936+ max : gap_as_pat. clone ( ) ,
937+ // Suggest `lo..=max` instead.
938+ suggestion : suggested_range. to_string ( ) ,
939+ } ,
940+ ) ;
941+ } else {
942+ self . tcx . emit_node_span_lint (
943+ lint:: builtin:: NON_CONTIGUOUS_RANGE_ENDPOINTS ,
944+ self . match_lint_level ,
945+ thir_pat. span ,
946+ errors:: ExclusiveRangeMissingGap {
947+ // Point at this range.
948+ first_range : thir_pat. span ,
949+ // That's the gap that isn't covered.
950+ gap : gap_as_pat. clone ( ) ,
951+ // Suggest `lo..=gap` instead.
952+ suggestion : suggested_range. to_string ( ) ,
953+ // All these ranges skipped over `gap` which we think is probably a
954+ // mistake.
955+ gap_with : gapped_with
956+ . iter ( )
957+ . map ( |pat| errors:: GappedRange {
958+ span : pat. data ( ) . unwrap ( ) . span ,
959+ gap : gap_as_pat. clone ( ) ,
960+ first_range : thir_pat. clone ( ) ,
961+ } )
962+ . collect ( ) ,
963+ } ,
964+ ) ;
965+ }
966+ }
903967}
904968
905969/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
0 commit comments