1
Fork 0

Run the annoying lint separately

This commit is contained in:
Nadrieril 2020-12-19 00:37:36 +00:00
parent 5a24b2c2c7
commit 7948f91910
2 changed files with 43 additions and 54 deletions

View file

@ -19,7 +19,7 @@ use rustc_middle::mir::Field;
use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_session::lint; use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::DUMMY_SP;
use rustc_target::abi::{Integer, Size, VariantIdx}; use rustc_target::abi::{Integer, Size, VariantIdx};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -184,23 +184,20 @@ impl IntRange {
} }
/// Split this range, as described at the top of the file. /// Split this range, as described at the top of the file.
fn split<'p, 'tcx>( fn split<'p, 'tcx>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> {
&self,
pcx: PatCtxt<'_, 'p, 'tcx>,
hir_id: Option<HirId>,
) -> 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![];
let mut split_range = SplitIntRange::new(self.clone()); let mut split_range = SplitIntRange::new(self.clone());
let row_len = pcx.matrix.column_count().unwrap_or(0); let intranges = pcx.matrix.head_ctors(pcx.cx).filter_map(|ctor| ctor.as_int_range());
let intranges = pcx split_range.split(intranges.cloned());
.matrix split_range.iter().map(IntRange).collect()
.head_ctors_and_spans(pcx.cx) }
.filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)));
let intranges = intranges.inspect(|(range, span)| { /// Lint on likely incorrect range patterns (#63987)
if let Some(intersection) = self.intersection(&range) { pub(super) fn lint_overlapping_range_endpoints(&self, pcx: PatCtxt<'_, '_, '_>, hir_id: HirId) {
if row_len == 1 && self.suspicious_intersection(&range) { 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 // FIXME: for now, only check for overlapping ranges on simple range
// patterns. Otherwise with the current logic the following is detected // patterns. Otherwise with the current logic the following is detected
// as overlapping: // as overlapping:
@ -211,24 +208,18 @@ impl IntRange {
// _ => {} // _ => {}
// } // }
// ``` // ```
overlaps.push((intersection.clone(), *span)); return;
}
}
});
split_range.split(intranges.map(|(range, _)| range).cloned());
self.lint_overlapping_range_endpoints(pcx, hir_id, overlaps);
split_range.iter().map(IntRange).collect()
} }
fn lint_overlapping_range_endpoints( let overlaps: Vec<_> = pcx
&self, .matrix
pcx: PatCtxt<'_, '_, '_>, .head_ctors_and_spans(pcx.cx)
hir_id: Option<HirId>, .filter_map(|(ctor, span)| Some((ctor.as_int_range()?, span)))
overlaps: Vec<(IntRange, Span)>, .filter(|(range, _)| self.suspicious_intersection(range))
) { .map(|(range, span)| (self.intersection(&range).unwrap(), span))
if let (true, Some(hir_id)) = (!overlaps.is_empty(), hir_id) { .collect();
if !overlaps.is_empty() {
pcx.cx.tcx.struct_span_lint_hir( pcx.cx.tcx.struct_span_lint_hir(
lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
hir_id, hir_id,
@ -673,21 +664,14 @@ impl<'tcx> Constructor<'tcx> {
/// This function may discard some irrelevant constructors if this preserves behavior and /// 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 /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the
/// matrix, unless all of them are. /// matrix, unless all of them are.
/// pub(super) fn split<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>) -> SmallVec<[Self; 1]> {
/// `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<HirId>,
) -> SmallVec<[Self; 1]> {
debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix); debug!("Constructor::split({:#?}, {:#?})", self, pcx.matrix);
match self { match self {
Wildcard => Constructor::split_wildcard(pcx), Wildcard => Constructor::split_wildcard(pcx),
// Fast-track if the range is trivial. In particular, we don't do the overlapping // Fast-track if the range is trivial. In particular, we don't do the overlapping
// ranges check. // 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), Slice(slice @ Slice { kind: VarLen(..), .. }) => slice.split(pcx),
// Any other constructor can be used unchanged. // Any other constructor can be used unchanged.
_ => smallvec![self.clone()], _ => smallvec![self.clone()],
@ -937,7 +921,7 @@ impl<'tcx> MissingConstructors<'tcx> {
pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect(); pcx.matrix.head_ctors(pcx.cx).cloned().filter(|c| !c.is_wildcard()).collect();
// Since `all_ctors` never contains wildcards, this won't recurse further. // Since `all_ctors` never contains wildcards, this won't recurse further.
let all_ctors = 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 } MissingConstructors { all_ctors, used_ctors }
} }

View file

@ -991,11 +991,16 @@ fn is_useful<'p, 'tcx>(
}); });
Usefulness::merge(usefulnesses) Usefulness::merge(usefulnesses)
} else { } 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`. // 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 // For each constructor, we compute whether there's a value that starts with it that would
// witness the usefulness of `v`. // 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. // We cache the result of `Fields::wildcards` because it is used a lot.
let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor); let ctor_wild_subpatterns = Fields::wildcards(pcx, &ctor);
let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns); let matrix = pcx.matrix.specialize_constructor(pcx, &ctor, &ctor_wild_subpatterns);