diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a6cf0ebeb82..f4dd7d2dcd6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -19,7 +19,7 @@ use rustc_middle::mir::Field; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::lint; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; use rustc_target::abi::{Integer, Size, VariantIdx}; use smallvec::{smallvec, SmallVec}; @@ -184,51 +184,42 @@ impl IntRange { } /// Split this range, as described at the top of the file. - fn split<'p, 'tcx>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - hir_id: Option, - ) -> SmallVec<[Constructor<'tcx>; 1]> { - // We collect the span and range of all the intersecting ranges to lint on likely incorrect - // range patterns. (#63987) - let mut overlaps = vec![]; + fn split<'p, 'tcx>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { let mut split_range = SplitIntRange::new(self.clone()); - let row_len = pcx.matrix.column_count().unwrap_or(0); - let intranges = pcx - .matrix - .head_ctors_and_spans(pcx.cx) - .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))); - let intranges = intranges.inspect(|(range, span)| { - if let Some(intersection) = self.intersection(&range) { - if row_len == 1 && self.suspicious_intersection(&range) { - // FIXME: for now, only check for overlapping ranges on simple range - // patterns. Otherwise with the current logic the following is detected - // as overlapping: - // ``` - // match (0u8, true) { - // (0 ..= 125, false) => {} - // (125 ..= 255, true) => {} - // _ => {} - // } - // ``` - overlaps.push((intersection.clone(), *span)); - } - } - }); - split_range.split(intranges.map(|(range, _)| range).cloned()); - - self.lint_overlapping_range_endpoints(pcx, hir_id, overlaps); - + let intranges = pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range()); + split_range.split(intranges.cloned()); split_range.iter().map(IntRange).collect() } - fn lint_overlapping_range_endpoints( - &self, - pcx: PatCtxt<'_, '_, '_>, - hir_id: Option, - overlaps: Vec<(IntRange, Span)>, - ) { - if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { + /// Lint on likely incorrect range patterns (#63987) + pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>, hir_id: HirId) { + if self.is_singleton() { + return; + } + + if pcx.matrix.column_count().unwrap_or(0) != 1 { + // FIXME: for now, only check for overlapping ranges on simple range + // patterns. Otherwise with the current logic the following is detected + // as overlapping: + // ``` + // match (0u8, true) { + // (0 ..= 125, false) => {} + // (125 ..= 255, true) => {} + // _ => {} + // } + // ``` + return; + } + + let overlaps: Vec<_> = pcx + .matrix + .head_ctors_and_spans(pcx.cx) + .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span))) + .filter(|(range, _)| self.suspicious_intersection(range)) + .map(|(range, span)| (self.intersection(&range).unwrap(), span)) + .collect(); + + if !overlaps.is_empty() { pcx.cx.tcx.struct_span_lint_hir( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, hir_id, @@ -673,21 +664,14 @@ impl<'tcx> Constructor<'tcx> { /// This function may discard some irrelevant constructors if this preserves behavior and /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the /// matrix, unless all of them are. - /// - /// `hir_id` is `None` when we're evaluating the wildcard pattern. In that case we do not want - /// to lint for overlapping ranges. - pub(super) fn split<'p>( - &self, - pcx: PatCtxt<'_, 'p, 'tcx>, - hir_id: Option, - ) -> SmallVec<[Self; 1]> { + pub(super) fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> { debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); match self { Wildcard => Constructor::split_wildcard(pcx), // Fast-track if the range is trivial. In particular, we don't do the overlapping // ranges check. - IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx, hir_id), + IntRange(ctor_range) if !ctor_range.is_singleton() => ctor_range.split(pcx), Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx), // Any other constructor can be used unchanged. _ => smallvec![self.clone()], @@ -937,7 +921,7 @@ impl<'tcx> MissingConstructors<'tcx> { pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); // Since `all_ctors` never contains wildcards, this won't recurse further. let all_ctors = - all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx, None)).collect(); + all_constructors(pcx).into_iter().flat_map(|ctor| ctor.split(pcx)).collect(); MissingConstructors { all_ctors, used_ctors } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 0ecc034ac0b..877d48a85b7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -991,11 +991,16 @@ fn is_useful<'p, 'tcx>( }); Usefulness::merge(usefulnesses) } else { + let v_ctor = v.head_ctor(cx); + if let Constructor::IntRange(ctor_range) = &v_ctor { + // Lint on likely incorrect range patterns (#63987) + ctor_range.lint_overlapping_range_endpoints(pcx, hir_id) + } // We split the head constructor of `v`. - let ctors = v.head_ctor(cx).split(pcx, Some(hir_id)); + let split_ctors = v_ctor.split(pcx); // For each constructor, we compute whether there's a value that starts with it that would // witness the usefulness of `v`. - let usefulnesses = ctors.into_iter().map(|ctor| { + let usefulnesses = split_ctors.into_iter().map(|ctor| { // We cache the result of `Fields::wildcards` because it is used a lot. let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);